Exemplo n.º 1
0
 def test_tag_task(self):
     """Sets the tags for a task."""
     store = TodoStore(self.db)
     task = store.new_task()
     tag = "you're it"
     store.tag_task(task, [tag])
     self.assertEqual([tag], task.tags)
Exemplo n.º 2
0
 def test_get_all_tags_duplicates(self):
     store = TodoStore(self.db)
     store.initialize_db()
     tags = ['foo', 'bar', 'bam']
     store.new_task(tags=tags)
     self.assertEqual(sorted(tags), sorted(store.get_all_tags()))
     tags2 = ['foo', 'sball']
     store.new_task(tags=tags2)
     self.assertEqual(set(tags + tags2), set(store.get_all_tags()))
Exemplo n.º 3
0
 def test_get_all_tags(self):
     store = TodoStore(self.db)
     store.initialize_db()
     tags = ['foo', 'bar', 'bam']
     task = store.new_task(tags=tags)
     self.assertEqual(sorted(tags), sorted(store.get_all_tags()))
     tags = ['foo', 'sball']
     task.tags = tags
     store.save_task(task)
     self.assertEqual(sorted(tags), sorted(store.get_all_tags()))
Exemplo n.º 4
0
Arquivo: ui.py Projeto: Kazade/Tasks
 def __init__(self, in_memory=False):
     super(Main, self).__init__()
     # Dynamically load the ui file generated by QtDesigner.
     uifile = os.path.join(
         os.path.abspath(os.path.dirname(__file__)), 'u1todo.ui')
     uic.loadUi(uifile, self)
     # hook up the signals to the signal handlers.
     self.connect_events()
     # Load the u1todo database.
     db = get_database()
     # And wrap it in a TodoStore object.
     self.store = TodoStore(db)
     # create or update the indexes if they are not up-to-date
     self.store.initialize_db()
     # Initially the delete button is disabled, because there are no tasks
     # to delete.
     self.delete_button.setEnabled(False)
     # Initialize some variables we will use to keep track of the tags.
     self._tag_docs = defaultdict(list)
     self._tag_buttons = {}
     self._tag_filter = []
     # Get all the tasks in the database, and add them to the UI.
     for task in self.store.get_all_tasks():
         self.add_task(task)
     self.task_edit.clear()
     # Give the edit field focus.
     self.task_edit.setFocus()
     # Initialize the variable that points to the currently selected list
     # item.
     self.item = None
Exemplo n.º 5
0
 def test_indexes_are_added(self):
     """New indexes are added when a new store is created."""
     store = TodoStore(self.db)
     store.initialize_db()
     INDEXES['foo'] = 'bar'
     self.assertNotIn('foo', dict(self.db.list_indexes()))
     store = TodoStore(self.db)
     store.initialize_db()
     self.assertIn('foo', dict(self.db.list_indexes()))
Exemplo n.º 6
0
 def test_indexes_are_updated(self):
     """Indexes are updated when a new store is created."""
     store = TodoStore(self.db)
     store.initialize_db()
     new_expression = 'newtags'
     INDEXES[TAGS_INDEX] = new_expression
     self.assertNotEqual(
         new_expression, dict(self.db.list_indexes())['tags'])
     store = TodoStore(self.db)
     store.initialize_db()
     self.assertEqual(
         [new_expression], dict(self.db.list_indexes())['tags'])
Exemplo n.º 7
0
 def test_get_tasks_by_tags(self):
     store = TodoStore(self.db)
     store.initialize_db()
     tags = ['foo', 'bar', 'bam']
     task1 = store.new_task(tags=tags)
     tags2 = ['foo', 'sball']
     task2 = store.new_task(tags=tags2)
     self.assertEqual(
         sorted([task1.task_id, task2.task_id]),
         sorted([t.task_id for t in store.get_tasks_by_tags(['foo'])]))
     self.assertEqual(
         [task1.task_id],
         [t.task_id for t in store.get_tasks_by_tags(['foo', 'bar'])])
     self.assertEqual(
         [task2.task_id],
         [t.task_id for t in store.get_tasks_by_tags(['foo', 'sball'])])
Exemplo n.º 8
0
 def test_get_all_tasks(self):
     store = TodoStore(self.db)
     store.initialize_db()
     task1 = store.new_task()
     task2 = store.new_task()
     task3 = store.new_task()
     task_ids = [task.task_id for task in store.get_all_tasks()]
     self.assertEqual(
         sorted([task1.task_id, task2.task_id, task3.task_id]),
         sorted(task_ids))
Exemplo n.º 9
0
 def test_reinitialize_db(self):
     """Creates indexes."""
     store = TodoStore(self.db)
     store.new_task()
     store.initialize_db()
     for key, value in self.db.list_indexes():
         self.assertEqual(INDEXES[key], value[0])
Exemplo n.º 10
0
 def test_save_task_get_task(self):
     """Saves a modified task and retrieves it from the db."""
     store = TodoStore(self.db)
     task = store.new_task()
     task.title = "This is the title."
     store.save_task(task)
     task_copy = store.get_task(task.task_id)
     self.assertEqual(task.title, task_copy.title)
Exemplo n.º 11
0
 def test_delete_task(self):
     """Deletes a task by id."""
     store = TodoStore(self.db)
     task = store.new_task()
     store.delete_task(task)
     self.assertRaises(KeyError, store.get_task, task.task_id)
Exemplo n.º 12
0
 def test_get_non_existant_task(self):
     """Saves a modified task and retrieves it from the db."""
     store = TodoStore(self.db)
     self.assertRaises(KeyError, store.get_task, "nonexistant")
Exemplo n.º 13
0
 def test_new_task_with_tags(self):
     """Creates a new task."""
     store = TodoStore(self.db)
     tags = ['foo', 'bar', 'bam']
     task = store.new_task(tags=tags)
     self.assertEqual(tags, task.tags)
Exemplo n.º 14
0
 def test_new_task_with_title(self):
     """Creates a new task."""
     store = TodoStore(self.db)
     title = "Un task muy importante"
     task = store.new_task(title=title)
     self.assertEqual(title, task.title)
Exemplo n.º 15
0
 def test_new_task(self):
     """Creates a new task."""
     store = TodoStore(self.db)
     task = store.new_task()
     self.assertTrue(isinstance(task, Task))
     self.assertIsNotNone(task.task_id)
Exemplo n.º 16
0
Arquivo: ui.py Projeto: Kazade/Tasks
class Main(QtGui.QMainWindow):
    """Main window of our application."""

    def __init__(self, in_memory=False):
        super(Main, self).__init__()
        # Dynamically load the ui file generated by QtDesigner.
        uifile = os.path.join(
            os.path.abspath(os.path.dirname(__file__)), 'u1todo.ui')
        uic.loadUi(uifile, self)
        # hook up the signals to the signal handlers.
        self.connect_events()
        # Load the u1todo database.
        db = get_database()
        # And wrap it in a TodoStore object.
        self.store = TodoStore(db)
        # create or update the indexes if they are not up-to-date
        self.store.initialize_db()
        # Initially the delete button is disabled, because there are no tasks
        # to delete.
        self.delete_button.setEnabled(False)
        # Initialize some variables we will use to keep track of the tags.
        self._tag_docs = defaultdict(list)
        self._tag_buttons = {}
        self._tag_filter = []
        # Get all the tasks in the database, and add them to the UI.
        for task in self.store.get_all_tasks():
            self.add_task(task)
        self.task_edit.clear()
        # Give the edit field focus.
        self.task_edit.setFocus()
        # Initialize the variable that points to the currently selected list
        # item.
        self.item = None

    def connect_events(self):
        """Hook up all the signal handlers."""
        # On enter, save the task that was being edited.
        self.task_edit.returnPressed.connect(self.update)
        # When the Edit/Add button is clicked, save the task that was being
        # edited.
        self.edit_button.clicked.connect(self.update)
        # When the Delete button is clicked, delete the currently selected task
        # (if any.)
        self.delete_button.clicked.connect(self.delete)
        # If a new row in the list is selected, change the currently selected
        # task, and put its contents in the edit field.
        self.todo_list.currentRowChanged.connect(self.row_changed)
        # If the checked status of an item in the list changes, change the done
        # status of the task.
        self.todo_list.itemChanged.connect(self.item_changed)
        self.sync_button.clicked.connect(self.synchronize)

    def refresh_filter(self):
        """Remove all tasks, and show only those that satisfy the new filter.

        """
        # Remove everything from the list.
        while len(self.todo_list):
            self.todo_list.takeItem(0)
        # Get the filtered tasks from the database.
        for task in self.store.get_tasks_by_tags(self._tag_filter):
            # Add them to the UI.
            self.add_task(task)
        # Clear the current selection.
        self.todo_list.setCurrentRow(-1)
        self.task_edit.clear()
        self.item = None

    def item_changed(self, item):
        """Mark a task as done or not done."""
        if item.checkState() == QtCore.Qt.Checked:
            item.task.done = True
        else:
            item.task.done = False
        # Save the task to the database.
        item.update_strikethrough()
        item.setText(item.task.title)
        self.store.save_task(item.task)
        # Clear the current selection.
        self.todo_list.setCurrentRow(-1)
        self.task_edit.clear()
        self.item = None

    def update(self):
        """Either add a new task or update an existing one."""
        text = unicode(self.task_edit.text(), 'utf-8')
        if not text:
            # There was no text in the edit field so do nothing.
            return
        if self.item is None:
            # No task was selected, so add a new one.
            task = self.store.new_task(text, tags=extract_tags(text))
            self.add_task(task)
        else:
            # A task was selected, so update it.
            self.update_task_text(text)
        # Clear the current selection.
        self.todo_list.setCurrentRow(-1)
        self.task_edit.clear()
        self.item = None

    def get_ubuntuone_credentials(self):
        cmt = CredentialsManagementTool()
        return cmt.find_credentials()

    def synchronize(self):
        self.sync_button.setEnabled(False)
        if self.u1_radio.isChecked():
            d = self.get_ubuntuone_credentials()
            d.addCallback(self._synchronize)
        else:
            # TODO: add ui for entering creds for non u1 servers.
            self._synchronize()

    def _synchronize(self, creds=None):
        if self.u1_radio.isChecked():
            # TODO: not hardcode
            target = 'https://u1db.one.ubuntu.com/~/u1todo'
        else:
            target = self.url_edit.text()
        if target.startswith('http://') or target.startswith('https://'):
            st = HTTPSyncTarget.connect(target)
            oauth_creds = {
                'token_key': creds['token'],
                'token_secret': creds['token_secret'],
                'consumer_key': creds['consumer_key'],
                'consumer_secret': creds['consumer_secret']}
            if creds:
                st.set_oauth_credentials(**oauth_creds)
        else:
            db = u1db.open(target, create=True)
            st = db.get_sync_target()
        syncer = Synchronizer(self.store.db, st)
        try:
            syncer.sync()
        except DatabaseDoesNotExist:
            # The server does not yet have the database, so create it.
            if target.startswith('http://') or target.startswith('https://'):
                db = HTTPDatabase(target)
                db.set_oauth_credentials(**oauth_creds)
                db.open(create=True)
            syncer.sync()
        self.refresh_filter()
        self.last_synced.setText(
            '<span style="color:green">%s</span>' % (datetime.now()))
        self.sync_button.setEnabled(True)

    def delete(self):
        """Delete a todo item."""
        # Delete the item from the database.
        row = self.todo_list.currentRow()
        item = self.todo_list.takeItem(row)
        if item is None:
            return
        self.store.delete_task(item.task)
        # Clear the current selection.
        self.todo_list.setCurrentRow(-1)
        self.task_edit.clear()
        self.item = None
        if self.todo_list.count() == 0:
            # If there are no tasks left, disable the delete button.
            self.delete_button.setEnabled(False)

    def add_task(self, task):
        """Add a new todo item."""
        # Wrap the task in a UITask object.
        item = UITask(task)
        self.todo_list.addItem(item)
        # We know there is at least one item now so we enable the delete
        # button.
        self.delete_button.setEnabled(True)
        if not task.tags:
            return
        # If the task has tags, we add them as filter buttons to the UI, if
        # they are new.
        for tag in task.tags:
            self.add_tag(task.task_id, tag)

    def add_tag(self, task_id, tag):
        """Create a link between the task with id task_id and the tag, and
        add a new button for tag if it was not already there.

        """
        # Add the task id to the list of document ids associated with this tag.
        self._tag_docs[tag].append(task_id)
        # If the list has more than one element the tag button was already
        # present.
        if len(self._tag_docs[tag]) > 1:
            return
        # Add a tag filter button for this tag to the UI.
        button = QtGui.QPushButton(tag)
        button._u1todo_tag = tag
        # Make the button an on/off button.
        button.setCheckable(True)
        # Store a reference to the button in a dictionary so we can find it
        # back more easily if we need to delete it.
        self._tag_buttons[tag] = button

        # We define a function to handle the clicked signal of the button,
        # since each button will need its own handler.
        def filter_toggle(checked):
            """Toggle the filter for the tag associated with this button."""
            if checked:
                # Add the tag to the current filter.
                self._tag_filter.append(button._u1todo_tag)
            else:
                # Remove the tag from the current filter.
                self._tag_filter.remove(button._u1todo_tag)
            # Apply the new filter.
            self.refresh_filter()

        # Attach the handler to the button's clicked signal.
        button.clicked.connect(filter_toggle)
        # Get the position where the button needs to be inserted. (We keep them
        # sorted alphabetically by the text of the tag.
        index = sorted(self._tag_buttons.keys()).index(tag)
        # And add the button to the UI.
        self.tag_buttons.insertWidget(index, button)

    def remove_tag(self, task_id, tag):
        """Remove the link between the task with id task_id and the tag, and
        remove the button for tag if it no longer has any tasks associated with
        it.

        """
        # Remove the task id from the list of document ids associated with this
        # tag.
        self._tag_docs[tag].remove(task_id)
        # If the list is not empty, we do not remove the button, because there
        # are still tasks that have this tag.
        if self._tag_docs[tag]:
            return
        # Look up the button.
        button = self._tag_buttons[tag]
        # Remove it from the ui.
        self.tag_buttons.removeWidget(button)
        # And remove the reference.
        del self._tag_buttons[tag]

    def update_tags(self, task_id, old_tags, new_tags):
        """Process any changed tags for this task_id."""
        # Process all removed tags.
        for tag in old_tags - new_tags:
            self.remove_tag(task_id, tag)
        # Process all tags newly added.
        for tag in new_tags - old_tags:
            self.add_tag(task_id, tag)

    def update_task_text(self, text):
        """Edit an existing todo item."""
        item = self.item
        task = item.task
        # Change the task's title to the text in the edit field.
        task.title = text
        # Record the current tags.
        old_tags = set(task.tags) if task.tags else set([])
        # Extract the new tags from the new text.
        new_tags = set(extract_tags(text))
        # Check if the tag filter buttons need updating.
        self.update_tags(item.task.task_id, old_tags, new_tags)
        # Set the tags on the task.
        task.tags = list(new_tags)
        # disconnect the signal temporarily while we change the title
        self.todo_list.itemChanged.disconnect(self.item_changed)
        # Change the text in the UI.
        item.setText(text)
        # reconnect the signal after we changed the title
        self.todo_list.itemChanged.connect(self.item_changed)
        # Save the changed task to the database.
        self.store.save_task(task)

    def row_changed(self, index):
        """Edit item when row changes."""
        if index == -1:
            self.task_edit.clear()
            return
        # If a row is selected, show the selected task's title in the edit
        # field.
        self.item = self.todo_list.item(index)
        self.task_edit.setText(self.item.task.title)