← Back to team overview

gtg team mailing list archive

[Merge] lp:~nimit-svnit/gtg/bug-1067738 into lp:gtg

 

Nimit Shah has proposed merging lp:~nimit-svnit/gtg/bug-1067738 into lp:gtg.

Requested reviews:
  Gtg developers (gtg)

For more details, see:
https://code.launchpad.net/~nimit-svnit/gtg/bug-1067738/+merge/130662

Emptied the text on quick-add bar when a user clicked on tagtree item or task tree item
-- 
https://code.launchpad.net/~nimit-svnit/gtg/bug-1067738/+merge/130662
Your team Gtg developers is requested to review the proposed merge of lp:~nimit-svnit/gtg/bug-1067738 into lp:gtg.
=== modified file 'CHANGELOG'
--- CHANGELOG	2012-09-08 08:10:51 +0000
+++ CHANGELOG	2012-10-20 05:46:21 +0000
@@ -53,6 +53,7 @@
     * Fix for bug-1037051 (Due date is not set for a new subtask), by Nimit Shah
     * Fix for bug #1036955: Due date is not preselected when start date is filled, by Steve Scheel
     * Fix for bug #1045036: Slovak Translation Updated by Slavko
+    * Fix for bug #1067738: Quick-add bar search query not cleared, by Nimit Shah
 
 2012-02-13 Getting Things GNOME! 0.2.9
     * Big refractorization of code, now using liblarch

=== modified file 'GTG/gtk/browser/browser.py'
--- GTG/gtk/browser/browser.py	2012-08-12 23:01:10 +0000
+++ GTG/gtk/browser/browser.py	2012-10-20 05:46:21 +0000
@@ -5,6 +5,13 @@
 # Copyright (c) 2008-2009 - Lionel Dricot & Bertrand Rousseau
 #
 # This program is free software: you can redistribute it and/or modify it under
+# the terms of the GNU General Public License as published by th# -*- coding: utf-8 -*-
+# pylint: disable-msg=W0201
+# -----------------------------------------------------------------------------
+# Getting Things Gnome! - a personal organizer for the GNOME desktop
+# Copyright (c) 2008-2009 - Lionel Dricot & Bertrand Rousseau
+#
+# This program is free software: you can redistribute it and/or modify it under
 # the terms of the GNU General Public License as published by the Free Software
 # Foundation, either version 3 of the License, or (at your option) any later
 # version.
@@ -825,6 +832,1641 @@
         """
         deals with mouse click event on the tag tree
         """
+        self.quickadd_entry.set_text('')
+        Log.debug("Received button event #%d at %d, %d" % (
+            event.button, event.x, event.y))
+        if event.button == 3:
+            x = int(event.x)
+            y = int(event.y)
+            time = event.time
+            pthinfo = treeview.get_path_at_pos(x, y)
+            if pthinfo is not None:
+                path, col, cellx, celly = pthinfo #pylint: disable-msg=W0612
+                treeview.grab_focus()
+                # The location we want the cursor to return to
+                # after we're done.
+                self.previous_cursor = treeview.get_cursor()
+                # For use in is_task_visible
+                self.previous_tag = self.get_selected_tags()
+                # Let's us know that we're working on a tag.
+                self.tag_active = True
+
+                # This location is stored in case we need to work with it
+                # later on.
+                self.target_cursor = path, col
+                treeview.set_cursor(path, col, 0)
+                #the nospecial=True disable right clicking for special tags
+                selected_tags = self.get_selected_tags(nospecial=True)
+                selected_search = self.get_selected_search()
+                #popup menu for searches
+                if selected_search is not None:
+                    my_tag = self.req.get_tag(selected_search)
+                    self.tagpopup.set_tag(my_tag)
+                    self.tagpopup.popup(None, None, None, event.button, time)
+                elif len(selected_tags) > 0:
+                    # Then we are looking at single, normal tag rather than
+                    # the special 'All tags' or 'Tasks without tags'. We only
+                    # want to popup the menu for normal tags.
+                    my_tag = self.req.get_tag(selected_tags[0])
+                    self.tagpopup.set_tag(my_tag)
+                    self.tagpopup.popup(None, None, None, event.button, time)
+                else:
+                    self.reset_cursor()
+            return True
+
+    def on_tag_treeview_key_press_event(self, treeview, event):
+        keyname = gtk.gdk.keyval_name(event.keyval)
+        is_shift_f10 = (keyname == "F10" and
+            event.get_state() & gtk.gdk.SHIFT_MASK)
+        if is_shift_f10 or keyname == "Menu":
+            selected_tags = self.get_selected_tags(nospecial=True)
+            selected_search = self.get_selected_search()
+            #popup menu for searches
+            if selected_search is not None:
+                self.searchpopup.popup(None, None, None, 0, event.time)
+            elif len(selected_tags) > 0:
+                # Then we are looking at single, normal tag rather than
+                # the special 'All tags' or 'Tasks without tags'. We only
+                # want to popup the menu for normal tags.
+                selected_tag = self.req.get_tag(selected_tags[0])
+                self.tagpopup.set_tag(selected_tag)
+                self.tagpopup.popup(None, None, None, 0, event.time)
+            else:
+                self.reset_cursor()
+            return True
+
+    def on_task_treeview_button_press_event(self, treeview, event):
+        """ Pop up context menu on right mouse click in the main
+        task tree view """
+        self.quickadd_entry.set_text('')
+        Log.debug("Received button event #%d at %d,%d" % (
+            event.button, event.x, event.y))
+        if event.button == 3:
+            x = int(event.x)
+            y = int(event.y)
+            time = event.time
+            pthinfo = treeview.get_path_at_pos(x, y)
+            if pthinfo is not None:
+                path, col, cellx, celly = pthinfo
+                selection = treeview.get_selection()
+                if selection.count_selected_rows() > 0:
+                    if not selection.path_is_selected(path):
+                        treeview.set_cursor(path, col, 0)
+                else:
+                    treeview.set_cursor(path, col, 0)
+                treeview.grab_focus()
+                self.taskpopup.popup(None, None, None, event.button, time)
+            return True
+
+    def on_task_treeview_key_press_event(self, treeview, event):
+        keyname = gtk.gdk.keyval_name(event.keyval)
+        is_shift_f10 = (keyname == "F10" and
+            event.get_state() & gtk.gdk.SHIFT_MASK)
+
+        if keyname == "Delete":
+            self.on_delete_tasks()
+            return True
+        elif is_shift_f10 or keyname == "Menu":
+            self.taskpopup.popup(None, None, None, 0, event.time)
+            return True
+
+    def on_closed_task_treeview_button_press_event(self, treeview, event):
+        if event.button == 3:
+            x = int(event.x)
+            y = int(event.y)
+            time = event.time
+            pthinfo = treeview.get_path_at_pos(x, y)
+            if pthinfo is not None:
+                path, col, cellx, celly = pthinfo
+                treeview.grab_focus()
+                treeview.set_cursor(path, col, 0)
+                self.ctaskpopup.popup(None, None, None, event.button, time)
+            return True
+
+    def on_closed_task_treeview_key_press_event(self, treeview, event):
+        keyname = gtk.gdk.keyval_name(event.keyval)
+        is_shift_f10 = (keyname == "F10" and
+            event.get_state() & gtk.gdk.SHIFT_MASK)
+
+        if keyname == "Delete":
+            self.on_delete_tasks()
+            return True
+        elif is_shift_f10 or keyname == "Menu":
+            self.ctaskpopup.popup(None, None, None, 0, event.time)
+            return True
+
+    def on_add_task(self, widget, status=None):
+        tags = [tag for tag in self.get_selected_tags() if tag.startswith('@')]
+        task = self.req.new_task(tags=tags, newtask=True)
+        uid = task.get_id()
+        if status:
+            task.set_status(status)
+        self.vmanager.open_task(uid, thisisnew=True)
+
+    def on_add_subtask(self, widget):
+        uid = self.get_selected_task()
+        if uid:
+            zetask = self.req.get_task(uid)
+            tags = [t.get_name() for t in zetask.get_tags()]
+            task = self.req.new_task(tags=tags, newtask=True)
+            #task.add_parent(uid)
+            zetask.add_child(task.get_id())
+            self.vmanager.open_task(task.get_id(), thisisnew=True)
+
+    def on_edit_active_task(self, widget, row=None, col=None):
+        tid = self.get_selected_task()
+        if tid:
+            self.vmanager.open_task(tid)
+
+    def on_edit_done_task(self, widget, row=None, col=None):
+        tid = self.get_selected_task('closed')
+        if tid:
+            self.vmanager.open_task(tid)
+
+    def on_delete_tasks(self, widget=None, tid=None):
+        #If we don't have a parameter, then take the selection in the treeview
+        if not tid:
+            #tid_to_delete is a [project,task] tuple
+            tids_todelete = self.get_selected_tasks()
+            if not tids_todelete:
+                return
+        else:
+            tids_todelete = [tid]
+        Log.debug("going to delete %s" % tids_todelete)
+        self.vmanager.ask_delete_tasks(tids_todelete)
+
+    def update_start_date(self, widget, new_start_date):
+        tasks = [self.req.get_task(uid)
+            for uid in self.get_selected_tasks()
+            if uid is not None]
+
+        start_date = Date.parse(new_start_date)
+
+        #FIXME: If the task dialog is displayed, refresh its start_date widget
+        for task in tasks:
+            task.set_start_date(start_date)
+
+    def on_mark_as_started(self, widget):
+        self.update_start_date(widget, "today")
+
+    def on_start_for_tomorrow(self, widget):
+        self.update_start_date(widget, "tomorrow")
+
+    def on_start_for_next_week(self, widget):
+        self.update_start_date(widget, "next week")
+
+    def on_start_for_next_month(self, widget):
+        self.update_start_date(widget, "next month")
+
+    def on_start_for_next_year(self, widget):
+        self.update_start_date(widget, "next year")
+
+    def on_start_clear(self, widget):
+        self.update_start_date(widget, None)
+
+    def update_due_date(self, widget, new_due_date):
+        tasks = [self.req.get_task(uid)
+            for uid in self.get_selected_tasks()
+            if uid is not None]
+
+        due_date = Date.parse(new_due_date)
+
+        #FIXME: If the task dialog is displayed, refresh its due_date widget
+        for task in tasks:
+            task.set_due_date(due_date)
+
+    def on_set_due_today(self, widget):
+        self.update_due_date(widget, "today")
+
+    def on_set_due_tomorrow(self, widget):
+        self.update_due_date(widget, "tomorrow")
+
+    def on_set_due_next_week(self, widget):
+        self.update_due_date(widget, "next week")
+
+    def on_set_due_next_month(self, widget):
+        self.update_due_date(widget, "next month")
+
+    def on_set_due_next_year(self, widget):
+        self.update_due_date(widget, "next year")
+
+    def on_set_due_now(self, widget):
+        self.update_due_date(widget, "now")
+
+    def on_set_due_soon(self, widget):
+        self.update_due_date(widget, "soon")
+
+    def on_set_due_someday(self, widget):
+        self.update_due_date(widget, "someday")
+
+    def on_set_due_clear(self, widget):
+        self.update_due_date(widget, None)
+
+    def on_modify_tags(self, widget):
+        """ Run Modify Tags dialog on selected tasks """
+        tasks = self.get_selected_tasks()
+        self.modifytags_dialog.modify_tags(tasks)
+
+    def close_all_task_editors(self, task_id):
+        """ Including editors of subtasks """
+        all_subtasks = []
+
+        def trace_subtasks(root):
+            all_subtasks.append(root)
+            for i in root.get_subtasks():
+                if i not in all_subtasks:
+                    trace_subtasks(i)
+
+        trace_subtasks(self.req.get_task(task_id))
+
+        for task in all_subtasks:
+            self.vmanager.close_task(task.get_id())
+
+    def on_mark_as_done(self, widget):
+        tasks_uid = [uid for uid in self.get_selected_tasks()
+                        if uid is not None]
+        if len(tasks_uid) == 0:
+            return
+        tasks = [self.req.get_task(uid) for uid in tasks_uid]
+        tasks_status = [task.get_status() for task in tasks]
+        for uid, task, status in zip(tasks_uid, tasks, tasks_status):
+            if status == Task.STA_DONE:
+                # Marking as undone
+                task.set_status(Task.STA_ACTIVE)
+                # Parents of that task must be updated - not to be shown
+                # in workview, update children count, etc.
+                for parent_id in task.get_parents():
+                    parent = self.req.get_task(parent_id)
+                    parent.modified()
+            else:
+                task.set_status(Task.STA_DONE)
+                self.close_all_task_editors(uid)
+
+    def on_dismiss_task(self, widget):
+        tasks_uid = [uid for uid in self.get_selected_tasks()
+                        if uid is not None]
+        if len(tasks_uid) == 0:
+            return
+        tasks = [self.req.get_task(uid) for uid in tasks_uid]
+        tasks_status = [task.get_status() for task in tasks]
+        for uid, task, status in zip(tasks_uid, tasks, tasks_status):
+            if status == Task.STA_DISMISSED:
+                task.set_status(Task.STA_ACTIVE)
+            else:
+                task.set_status(Task.STA_DISMISSED)
+                self.close_all_task_editors(uid)
+
+    def apply_filter_on_panes(self, filter_name):
+        """ Apply filters for every pane: active tasks, closed tasks """
+        for pane in self.vtree_panes:
+            vtree = self.req.get_tasks_tree(name=pane, refresh=False)
+            vtree.reset_filters(refresh=False, transparent_only=True)
+            vtree.apply_filter(filter_name, refresh=True)
+
+    def on_select_tag(self, widget=None, row=None, col=None):
+        """
+        callback for when selecting an element of the tagtree (left sidebar)
+        """
+        # FIXME add support for multiple selection of tags in future
+
+        # When enable_update_tags we should update all tags to match
+        # the current state. However, applying tag filter does not influence
+        # other tags, because of transparent filter. Therefore there is no
+        # self.tagree.refresh_all() => a significant optimization!
+        # See do_toggle_workview()
+        self.tv_factory.disable_update_tags()
+
+        #When you click on a tag, you want to unselect the tasks
+        taglist = self.get_selected_tags()
+        if len(taglist) > 0:
+            tagname = taglist[0]
+            self.apply_filter_on_panes(tagname)
+
+            # In case of search tag, set query in quickadd for
+            # refining search query
+            tag = self.req.get_tag(tagname)
+            if tag.is_search_tag():
+                self.quickadd_entry.set_text(tag.get_attribute("query"))
+
+        self.tv_factory.enable_update_tags()
+
+    def on_taskdone_cursor_changed(self, selection=None):
+        """Called when selection changes in closed task view.
+
+        Changes the way the selected task is displayed.
+        """
+        settings_done = {"label": GnomeConfig.MARK_DONE,
+                         "tooltip": GnomeConfig.MARK_DONE_TOOLTIP,
+                         "icon-name": "gtg-task-done"}
+        settings_undone = {"label": GnomeConfig.MARK_UNDONE,
+                           "tooltip": GnomeConfig.MARK_UNDONE_TOOLTIP,
+                           "icon-name": "gtg-task-undone"}
+        settings_dismiss = {"label": GnomeConfig.MARK_DISMISS,
+                           "tooltip": GnomeConfig.MARK_DISMISS_TOOLTIP,
+                           "icon-name": "gtg-task-dismiss"}
+        settings_undismiss = {"label": GnomeConfig.MARK_UNDISMISS,
+                              "tooltip": GnomeConfig.MARK_UNDISMISS_TOOLTIP,
+                              "icon-name": "gtg-task-undismiss"}
+
+        def update_button(button, settings):
+            button.set_icon_name(settings["icon-name"])
+            button.set_label(settings["label"])
+
+        def update_menu_item(menu_item, settings):
+            image = gtk.image_new_from_icon_name(settings["icon-name"], 16)
+            image.set_pixel_size(16)
+            image.show()
+            menu_item.set_image(image)
+            menu_item.set_label(settings["label"])
+
+        #We unselect all in the active task view
+        #Only if something is selected in the closed task list
+        #And we change the status of the Done/dismiss button
+        update_button(self.donebutton, settings_done)
+        update_menu_item(self.done_mi, settings_done)
+        update_button(self.dismissbutton, settings_dismiss)
+        update_menu_item(self.dismiss_mi, settings_dismiss)
+        if selection.count_selected_rows() > 0:
+            tid = self.get_selected_task('closed')
+            task = self.req.get_task(tid)
+            self.vtree_panes['active'].get_selection().unselect_all()
+            if task.get_status() == "Dismiss":
+                self.builder.get_object(
+                    "ctcm_mark_as_not_done").set_sensitive(False)
+                self.builder.get_object("ctcm_undismiss").set_sensitive(True)
+                update_button(self.dismissbutton, settings_undismiss)
+                update_menu_item(self.dismiss_mi, settings_undismiss)
+            else:
+                self.builder.get_object(
+                    "ctcm_mark_as_not_done").set_sensitive(True)
+                self.builder.get_object(
+                    "ctcm_undismiss").set_sensitive(False)
+                update_button(self.donebutton, settings_undone)
+                update_menu_item(self.done_mi, settings_undone)
+        self.update_buttons_sensitivity()
+
+    def on_task_cursor_changed(self, selection=None):
+        """Called when selection changes in the active task view.
+
+        Changes the way the selected task is displayed.
+        """
+        #We unselect all in the closed task view
+        #Only if something is selected in the active task list
+        self.donebutton.set_icon_name("gtg-task-done")
+        self.dismissbutton.set_icon_name("gtg-task-dismiss")
+        if selection.count_selected_rows() > 0:
+            if 'closed' in self.vtree_panes:
+                self.vtree_panes['closed'].get_selection().unselect_all()
+            self.donebutton.set_label(GnomeConfig.MARK_DONE)
+            self.donebutton.set_tooltip_text(GnomeConfig.MARK_DONE_TOOLTIP)
+            self.dismissbutton.set_label(GnomeConfig.MARK_DISMISS)
+        self.update_buttons_sensitivity()
+
+    def on_close(self, widget=None):
+        """Closing the window."""
+        #Saving is now done in main.py
+        self.quit()
+
+    #using dummy parameters that are given by the signal
+    def update_buttons_sensitivity(self, a=None, b=None, c=None):
+        enable = self.selection.count_selected_rows()
+        if 'closed' in self.vtree_panes:
+            enable += self.closed_selection.count_selected_rows() > 0
+        self.edit_mi.set_sensitive(enable)
+        self.new_subtask_mi.set_sensitive(enable)
+        self.done_mi.set_sensitive(enable)
+        self.dismiss_mi.set_sensitive(enable)
+        self.delete_mi.set_sensitive(enable)
+        self.donebutton.set_sensitive(enable)
+        self.dismissbutton.set_sensitive(enable)
+        self.deletebutton.set_sensitive(enable)
+
+### PUBLIC METHODS #########################################################
+    def get_selected_task(self, tv=None):
+        """
+        Returns the'uid' of the selected task, if any.
+        If multiple tasks are selected, returns only the first and
+        takes care of selecting only that (unselecting the others)
+
+        @param tv: The tree view to find the selected task in. Defaults to
+            the task_tview.
+        """
+        ids = self.get_selected_tasks(tv)
+        if len(ids) > 0:
+            #FIXME: we should also unselect all the others
+            return ids[0]
+        else:
+            return None
+
+    def get_selected_tasks(self, tv=None):
+        """
+        Returns a list of 'uids' of the selected tasks, and the corresponding
+        iters
+
+        @param tv: The tree view to find the selected task in. Defaults to
+            the task_tview.
+        """
+        #FIXME Why we have active as back case? is that so? Study this code
+        selected = []
+        if tv:
+            selected = self.vtree_panes[tv].get_selected_nodes()
+        else:
+            if 'active' in self.vtree_panes:
+                selected = self.vtree_panes['active'].get_selected_nodes()
+            for i in self.vtree_panes:
+                if len(selected) == 0:
+                    selected = self.vtree_panes[i].get_selected_nodes()
+        return selected
+
+    #If nospecial=True, only normal @tag are considered
+    def get_selected_tags(self, nospecial=False):
+        """
+        Returns the selected nodes from the tagtree
+
+        @param nospecial: doesn't return tags that do not stat with
+        """
+        taglist = []
+        if self.tagtreeview:
+            taglist = self.tagtreeview.get_selected_nodes()
+        #If no selection, we display all
+        if not nospecial and (not taglist or len(taglist) < 0):
+            taglist = ['gtg-tags-all']
+        if nospecial:
+            for t in list(taglist):
+                if not t.startswith('@'):
+                    taglist.remove(t)
+        return taglist
+
+    def reset_cursor(self):
+        """ Returns the cursor to the tag that was selected prior
+            to any right click action. Should be used whenever we're done
+            working with any tag through a right click menu action.
+            """
+        if self.tag_active:
+            self.tag_active = False
+            path, col = self.previous_cursor
+            if self.tagtreeview:
+                self.tagtreeview.set_cursor(path, col, 0)
+
+    def set_target_cursor(self):
+        """ Selects the last tag to be right clicked.
+
+            We need this because the context menu will deactivate
+            (and in turn, call reset_cursor()) before, for example, the color
+            picker dialog begins. Should be used at the beginning of any tag
+            editing function to remind the user which tag they're working with.
+            """
+        if not self.tag_active:
+            self.tag_active = True
+            path, col = self.target_cursor
+            if self.tagtreeview:
+                self.tagtreeview.set_cursor(path, col, 0)
+
+    def add_page_to_sidebar_notebook(self, icon, page):
+        """Adds a new page tab to the left panel.  The tab will
+        be added as the last tab.  Also causes the tabs to be
+        shown if they're not.
+        @param icon: a gtk.Image picture to display on the tab
+        @param page: gtk.Frame-based panel to be added
+        """
+        return self._add_page(self.sidebar_notebook, icon, page)
+
+    def add_page_to_main_notebook(self, title, page):
+        """Adds a new page tab to the top right main panel.  The tab
+        will be added as the last tab.  Also causes the tabs to be
+        shown.
+        @param title: Short text to use for the tab label
+        @param page: gtk.Frame-based panel to be added
+        """
+        return self._add_page(self.main_notebook, gtk.Label(title), page)
+
+    def add_page_to_accessory_notebook(self, title, page):
+        """Adds a new page tab to the lower right accessory panel.  The
+        tab will be added as the last tab.  Also causes the tabs to be
+        shown.
+        @param title: Short text to use for the tab label
+        @param page: gtk.Frame-based panel to be added
+        """
+        return self._add_page(self.accessory_notebook, gtk.Label(title), page)
+
+    def remove_page_from_sidebar_notebook(self, page):
+        """Removes a new page tab from the left panel.  If this leaves
+        only one tab in the notebook, the tab selector will be hidden.
+        @param page: gtk.Frame-based panel to be removed
+        """
+        return self._remove_page(self.sidebar_notebook, page)
+
+    def remove_page_from_main_notebook(self, page):
+        """Removes a new page tab from the top right main panel.  If
+        this leaves only one tab in the notebook, the tab selector will
+        be hidden.
+        @param page: gtk.Frame-based panel to be removed
+        """
+        return self._remove_page(self.main_notebook, page)
+
+    def remove_page_from_accessory_notebook(self, page):
+        """Removes a new page tab from the lower right accessory panel.
+        If this leaves only one tab in the notebook, the tab selector
+        will be hidden.
+        @param page: gtk.Frame-based panel to be removed
+        """
+        return self._remove_page(self.accessory_notebook, page)
+
+    def hide(self):
+        """ Hides the task browser """
+        self.browser_shown = False
+        self.window.hide()
+        gobject.idle_add(self.emit, "visibility-toggled")
+
+    def show(self):
+        """ Unhides the TaskBrowser """
+        self.browser_shown = True
+        #redraws the GDK window, bringing it to front
+        self.window.show()
+        self.window.present()
+        self.window.grab_focus()
+        self.quickadd_entry.grab_focus()
+        gobject.idle_add(self.emit, "visibility-toggled")
+
+    def iconify(self):
+        """ Minimizes the TaskBrowser """
+        self.window.iconify()
+
+    def is_visible(self):
+        """ Returns true if window is shown or false if hidden. """
+        return self.window.get_property("visible")
+
+    def is_active(self):
+        """ Returns true if window is the currently active window """
+        return self.window.get_property("is-active")
+
+    def get_builder(self):
+        return self.builder
+
+    def get_window(self):
+        return self.window
+
+    def get_active_tree(self):
+        '''
+        Returns the browser tree with all the filters applied. The tasks in
+        the tree are the same as the ones shown in the browser current view
+        '''
+        return self.activetree
+
+    def get_closed_tree(self):
+        '''
+        Returns the browser tree with all the filters applied. The tasks in
+        the tree are the same as the ones shown in the browser current closed
+        view.
+        '''
+        return self.__create_closed_tree()
+
+    def is_shown(self):
+        return self.browser_shown
+
+## BACKENDS RELATED METHODS ##################################################
+    def on_backend_failed(self, sender, backend_id, error_code):
+        """
+        Signal callback.
+        When a backend fails to work, loads a gtk.Infobar to alert the user
+
+        @param sender: not used, only here for signal compatibility
+        @param backend_id: the id of the failing backend
+        @param error_code: a backend error code, as specified
+            in BackendsSignals
+        """
+        infobar = self._new_infobar(backend_id)
+        infobar.set_error_code(error_code)
+
+    def on_backend_needing_interaction(self, sender, backend_id, description, \
+                                       interaction_type, callback):
+        '''
+        Signal callback.
+        When a backend needs some kind of feedback from the user,
+        loads a gtk.Infobar to alert the user.
+        This is used, for example, to request confirmation after authenticating
+        via OAuth.
+
+        @param sender: not used, only here for signal compatibility
+        @param backend_id: the id of the failing backend
+        @param description: a string describing the interaction needed
+        @param interaction_type: a string describing the type of interaction
+                                 (yes/no, only confirm, ok/cancel...)
+        @param callback: the function to call when the user provides the
+                         feedback
+        '''
+        infobar = self._new_infobar(backend_id)
+        infobar.set_interaction_request(description, interaction_type,
+            callback)
+
+    def __remove_backend_infobar(self, child, backend_id):
+        '''
+        Helper function to remove an gtk.Infobar related to a backend
+
+        @param child: a gtk.Infobar
+        @param backend_id: the id of the backend which gtk.Infobar should be
+                            removed.
+        '''
+        if isinstance(child, CustomInfoBar) and\
+            child.get_backend_id() == backend_id:
+            if self.vbox_toolbars:
+                self.vbox_toolbars.remove(child)
+
+    def remove_backend_infobar(self, sender, backend_id):
+        '''
+        Signal callback.
+        Deletes the gtk.Infobars related to a backend
+
+        @param sender: not used, only here for signal compatibility
+        @param backend_id: the id of the backend which gtk.Infobar should be
+                            removed.
+        '''
+        backend = self.req.get_backend(backend_id)
+        if not backend or (backend and backend.is_enabled()):
+            #remove old infobar related to backend_id, if any
+            if self.vbox_toolbars:
+                self.vbox_toolbars.foreach(self.__remove_backend_infobar, \
+                                       backend_id)
+
+    def _new_infobar(self, backend_id):
+        '''
+        Helper function to create a new infobar for a backend
+
+        @param backend_id: the backend for which we're creating the infobar
+        @returns gtk.Infobar: the created infobar
+        '''
+        #remove old infobar related to backend_id, if any
+        if not self.vbox_toolbars:
+            return
+        self.vbox_toolbars.foreach(self.__remove_backend_infobar, backend_id)
+        #add a new one
+        infobar = CustomInfoBar(self.req, self, self.vmanager, backend_id)
+        self.vbox_toolbars.pack_start(infobar, True)
+        return infobar
+
+#### SEARCH RELATED STUFF #####################################################
+    def get_selected_search(self):
+        """ return just one selected view """
+        if self.tagtreeview:
+            tags = self.tagtreeview.get_selected_nodes()
+            if len(tags)>0:
+                tag = self.tagtree.get_node(tags[0])
+                if tag.is_search_tag():
+                    return tags[0]
+        return None
+
+    def _init_search_completion(self):
+        """ Initialize search completion """
+        self.search_completion = self.builder.get_object(
+            "quickadd_entrycompletion")
+        self.quickadd_entry.set_completion(self.search_completion)
+
+        self.search_possible_actions = {
+            'add': _("Add Task"),
+            'open': _("Open Task"),
+            'search': _("Search"),
+        }
+
+        self.search_actions = []
+
+        self.search_complete_store = gtk.ListStore(str)
+        for tagname in self.req.get_all_tags():
+            # only for regular tags
+            if tagname.startswith("@"):
+                self.search_complete_store.append([tagname])
+
+        for command in SEARCH_COMMANDS:
+            self.search_complete_store.append([command])
+
+        self.search_completion.set_model(self.search_complete_store)
+        self.search_completion.set_text_column(0)
+
+    def on_quickadd_changed(self, editable):
+        """ Decide which actions are allowed with the current query """
+        # delete old actions
+        for i in range(len(self.search_actions)):
+            self.search_completion.delete_action(0)
+
+        self.search_actions = []
+        new_actions = []
+        query = self.quickadd_entry.get_text()
+        query = query.strip()
+
+        # If the tag pane is hidden, reset search filter when query is empty
+        if query == '' and not self.config.get("tag_pane"):
+            tree = self.req.get_tasks_tree(refresh=False)
+            filters = tree.list_applied_filters()
+            for tag_id in self.req.get_all_tags():
+                tag = self.req.get_tag(tag_id)
+                if tag.is_search_tag() and tag_id in filters:
+                    self.req.remove_tag(tag_id)
+                    self.apply_filter_on_panes(CoreConfig.ALLTASKS_TAG)
+                    return
+
+        if query:
+            if self.req.get_task_id(query) is not None:
+                new_actions.append('open')
+            else:
+                new_actions.append('add')
+
+            # Is query parsable?
+            try:
+                parse_search_query(query)
+                new_actions.append('search')
+            except InvalidQuery:
+                pass
+
+            # Add new order of actions
+            for aid, name in enumerate(new_actions):
+                action = self.search_possible_actions[name]
+                self.search_completion.insert_action_markup(aid, action)
+                self.search_actions.append(name)
+
+    def expand_search_tag(self):
+        """ For some unknown reason, search tag is not expanded correctly and
+        it must be done manually """
+        if self.tagtreeview is not None:
+            model = self.tagtreeview.get_model()
+            search_iter = model.my_get_iter((CoreConfig.SEARCH_TAG, ))
+            search_path = model.get_path(search_iter)
+            self.tagtreeview.expand_row(search_path, False)
+
+    def on_entrycompletion_action_activated(self, completion, index):
+        """ Executes action from completition of quickadd toolbar """
+        action = self.search_actions[index]
+        if action == 'add':
+            self.on_quickadd_activate(None)
+        elif action == 'open':
+            task_title = self.quickadd_entry.get_text()
+            task_id = self.req.get_task_id(task_title)
+            self.vmanager.open_task(task_id)
+            self.quickadd_entry.set_text('')
+        elif action == 'search':
+            query = self.quickadd_entry.get_text()
+            # ! at the beginning is reserved keyword for liblarch
+            if query.startswith('!'):
+                label = '_' + query
+            else:
+                label = query
+
+            # find possible name collisions
+            name, number = label, 1
+            already_search = False
+            while True:
+                tag = self.req.get_tag(name)
+                if tag is None:
+                    break
+
+                if tag.is_search_tag() and tag.get_attribute("query") == query:
+                    already_search = True
+                    break
+
+                # this name is used, adding number
+                number += 1
+                name = label + ' ' + str(number)
+
+            if not already_search:
+                tag = self.req.new_search_tag(name, query)
+
+            # Apply new search right now
+            if self.tagtreeview is not None:
+                # Select new search in tagsidebar and apply it
+
+                # Make sure search tag parent is expanded
+                # (otherwise selection does not work)
+                self.expand_search_tag()
+
+                # Get iterator for new search tag
+                model = self.tagtreeview.get_model()
+                path = self.tagtree.get_paths_for_node(tag.get_id())[0]
+                tag_iter = model.my_get_iter(path)
+
+                # Select only it and apply filters on top of that
+                selection = self.tagtreeview.get_selection()
+                selection.unselect_all()
+                selection.select_iter(tag_iter)
+                self.on_select_tag()
+            else:
+                self.apply_filter_on_panes(name)e Free Software
+# Foundation, either version 3 of the License, or (at your option) any later
+# version.
+#
+# This program is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+# details.
+#
+# You should have received a copy of the GNU General Public License along with
+# this program.  If not, see <http://www.gnu.org/licenses/>.
+# -----------------------------------------------------------------------------
+
+""" The main window for GTG, listing tags, and open and closed tasks """
+
+#=== IMPORT ===================================================================
+#system imports
+import time
+import threading
+from webbrowser import open as openurl
+
+import pygtk
+pygtk.require('2.0')
+import gobject
+import gtk
+
+#our own imports
+from GTG import _, info, ngettext
+from GTG.backends.backendsignals import BackendSignals
+from GTG.core import CoreConfig
+from GTG.core.search import parse_search_query, SEARCH_COMMANDS, InvalidQuery
+from GTG.core.task import Task
+from GTG.gtk.tag_completion import TagCompletion
+from GTG.gtk.browser import GnomeConfig
+from GTG.gtk.browser.custominfobar import CustomInfoBar
+from GTG.gtk.browser.modifytags_dialog import ModifyTagsDialog
+from GTG.gtk.browser.tag_context_menu import TagContextMenu
+from GTG.gtk.browser.treeview_factory import TreeviewFactory
+from GTG.tools.dates import Date
+from GTG.tools.logger import Log
+
+#=== MAIN CLASS ===============================================================
+
+
+
+class Timer:
+
+    def __init__(self, name):
+        self.name = name
+
+    def __enter__(self):
+        self.start = time.time()
+
+    def __exit__(self, *args):
+        print "%s : %s" % (self.name, time.time() - self.start)
+
+
+class TaskBrowser(gobject.GObject):
+    """ The UI for browsing open and closed tasks,
+    and listing tags in a tree """
+
+    __string_signal__ = (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE, (str, ))
+    __none_signal__ = (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE, tuple())
+    __gsignals__ = {'task-added-via-quick-add': __string_signal__,
+                    'visibility-toggled': __none_signal__,
+   }
+
+    def __init__(self, requester, vmanager):
+        gobject.GObject.__init__(self)
+        # Object prime variables
+        self.req = requester
+        self.vmanager = vmanager
+        self.config = self.req.get_config('browser')
+        self.tag_active = False
+
+        #treeviews handlers
+        self.vtree_panes = {}
+        self.tv_factory = TreeviewFactory(self.req, self.config)
+        self.activetree = self.req.get_tasks_tree(name='active', refresh=False)
+        self.vtree_panes['active'] = \
+                self.tv_factory.active_tasks_treeview(self.activetree)
+
+        ### YOU CAN DEFINE YOUR INTERNAL MECHANICS VARIABLES BELOW
+        self.in_toggle_workview = False
+
+        # Setup GTG icon theme
+        self._init_icon_theme()
+
+        # Set up models
+        # Active Tasks
+        self.activetree.apply_filter('active')
+        # Tags
+        self.tagtree = None
+        self.tagtreeview = None
+
+        # Load window tree
+        self.builder = gtk.Builder()
+        self.builder.add_from_file(GnomeConfig.GLADE_FILE)
+
+        # Define aliases for specific widgets
+        self._init_widget_aliases()
+
+        # Init non-glade widgets
+        self._init_ui_widget()
+
+        #Set the tooltip for the toolbar buttons
+        self._init_toolbar_tooltips()
+
+        # Initialize "About" dialog
+        self._init_about_dialog()
+
+        #Create our dictionary and connect it
+        self._init_signal_connections()
+
+        # Define accelerator keys
+        self._init_accelerators()
+
+        # Initialize search completion
+        self._init_search_completion()
+
+        self.restore_state_from_conf()
+
+        self.on_select_tag()
+        self.browser_shown = False
+
+        #Update the title when a task change
+        self.activetree.register_cllbck('node-added-inview',
+            self._update_window_title)
+        self.activetree.register_cllbck('node-deleted-inview',
+            self._update_window_title)
+        self._update_window_title()
+
+### INIT HELPER FUNCTIONS #####################################################
+#
+    def _init_icon_theme(self):
+        """
+        sets the deafault theme for icon and its directory
+        """
+        icon_dirs = CoreConfig().get_icons_directories()
+        for i in icon_dirs:
+            gtk.icon_theme_get_default().prepend_search_path(i)
+            gtk.window_set_default_icon_name("gtg")
+
+    def _init_widget_aliases(self):
+        """
+        defines aliases for UI elements found in the glide file
+        """
+        self.window = self.builder.get_object("MainWindow")
+        self.taskpopup = self.builder.get_object("task_context_menu")
+        self.defertopopup = self.builder.get_object("defer_to_context_menu")
+        self.ctaskpopup = self.builder.get_object("closed_task_context_menu")
+        self.editbutton = self.builder.get_object("edit_b")
+        self.edit_mi = self.builder.get_object("edit_mi")
+        self.donebutton = self.builder.get_object("done_b")
+        self.done_mi = self.builder.get_object("done_mi")
+        self.deletebutton = self.builder.get_object("delete_b")
+        self.delete_mi = self.builder.get_object("delete_mi")
+        self.newtask = self.builder.get_object("new_task_b")
+        self.newsubtask = self.builder.get_object("new_subtask_b")
+        self.new_subtask_mi = self.builder.get_object("new_subtask_mi")
+        self.dismissbutton = self.builder.get_object("dismiss_b")
+        self.dismiss_mi = self.builder.get_object("dismiss_mi")
+        self.about = self.builder.get_object("about_dialog")
+        self.main_pane = self.builder.get_object("main_pane")
+        self.menu_view_workview = self.builder.get_object("view_workview")
+        self.toggle_workview = self.builder.get_object("workview_toggle")
+        self.quickadd_entry = self.builder.get_object("quickadd_field")
+        self.toolbar = self.builder.get_object("task_toolbar")
+        self.quickadd_pane = self.builder.get_object("quickadd_pane")
+        self.sidebar = self.builder.get_object("sidebar_vbox")
+        self.sidebar_container = self.builder.get_object("sidebar-scroll")
+        self.sidebar_notebook = self.builder.get_object("sidebar_notebook")
+        self.main_notebook = self.builder.get_object("main_notebook")
+        self.accessory_notebook = self.builder.get_object("accessory_notebook")
+        self.vbox_toolbars = self.builder.get_object("vbox_toolbars")
+
+        self.closed_pane = None
+        self.tagpopup = TagContextMenu(self.req, self.vmanager)
+
+    def _init_ui_widget(self):
+        """ Sets the main pane with the tree with active tasks and
+        create ModifyTagsDialog """
+        # The Active tasks treeview
+        self.main_pane.add(self.vtree_panes['active'])
+
+        tag_completion = TagCompletion(self.req.get_tag_tree())
+        self.modifytags_dialog = ModifyTagsDialog(tag_completion, self.req)
+
+    def init_tags_sidebar(self):
+        """
+        initializes the tagtree (left area with tags and searches)
+        """
+        # The tags treeview
+        self.tagtree = self.req.get_tag_tree()
+        self.tagtreeview = self.tv_factory.tags_treeview(self.tagtree)
+        #Tags treeview
+        self.tagtreeview.connect('cursor-changed', \
+            self.on_select_tag)
+        self.tagtreeview.connect('row-activated', \
+            self.on_select_tag)
+        self.tagtreeview.connect('button-press-event', \
+            self.on_tag_treeview_button_press_event)
+        self.tagtreeview.connect('key-press-event', \
+            self.on_tag_treeview_key_press_event)
+        self.sidebar_container.add(self.tagtreeview)
+
+        # Refresh tree
+        self.tagtree.reset_filters(transparent_only=True)
+
+        # expanding search tag does not work automatically, request it
+        self.expand_search_tag()
+
+    def _init_toolbar_tooltips(self):
+        """
+        sets tooltips for widgets on toolbars
+        """
+        self.donebutton.set_tooltip_text(GnomeConfig.MARK_DONE_TOOLTIP)
+        self.editbutton.set_tooltip_text(GnomeConfig.EDIT_TOOLTIP)
+        self.dismissbutton.set_tooltip_text(GnomeConfig.MARK_DISMISS_TOOLTIP)
+        self.newtask.set_tooltip_text(GnomeConfig.NEW_TASK_TOOLTIP)
+        self.newsubtask.set_tooltip_text(GnomeConfig.NEW_SUBTASK_TOOLTIP)
+        self.toggle_workview.set_tooltip_text(
+            GnomeConfig.WORKVIEW_TOGGLE_TOOLTIP)
+        self.quickadd_entry.set_tooltip_text(
+            GnomeConfig.QUICKADD_ENTRY_TOOLTIP)
+        self.quickadd_entry.set_icon_tooltip_text(1,
+            GnomeConfig.QUICKADD_ICON_TOOLTIP)
+
+    def _init_about_dialog(self):
+        """
+        Show the about dialog
+        """
+        gtk.about_dialog_set_url_hook(lambda dialog, url: openurl(url))
+        self.about.set_website(info.URL)
+        self.about.set_website_label(info.URL)
+        self.about.set_version(info.VERSION)
+        self.about.set_authors(info.AUTHORS)
+        self.about.set_artists(info.ARTISTS)
+        self.about.set_documenters(info.DOCUMENTERS)
+        self.about.set_translator_credits(info.TRANSLATORS)
+
+    def _init_signal_connections(self):
+        """
+        connects signals on UI elements
+        """
+        SIGNAL_CONNECTIONS_DIC = {
+            "on_add_task":
+                self.on_add_task,
+            "on_edit_active_task":
+                self.on_edit_active_task,
+            "on_edit_done_task":
+                self.on_edit_done_task,
+            "on_delete_task":
+                self.on_delete_tasks,
+            "on_modify_tags":
+                self.on_modify_tags,
+            "on_mark_as_done":
+                self.on_mark_as_done,
+            "on_mark_as_started":
+                self.on_mark_as_started,
+            "on_start_for_tomorrow":
+                self.on_start_for_tomorrow,
+            "on_start_for_next_week":
+                self.on_start_for_next_week,
+            "on_start_for_next_month":
+                self.on_start_for_next_month,
+            "on_start_for_next_year":
+                self.on_start_for_next_year,
+            "on_start_clear":
+                self.on_start_clear,
+            "on_set_due_today":
+                self.on_set_due_today,
+            "on_set_due_tomorrow":
+                self.on_set_due_tomorrow,
+            "on_set_due_next_week":
+                self.on_set_due_next_week,
+            "on_set_due_next_month":
+                self.on_set_due_next_month,
+            "on_set_due_next_year":
+                self.on_set_due_next_year,
+            "on_set_due_now":
+                self.on_set_due_now,
+            "on_set_due_soon":
+                self.on_set_due_soon,
+            "on_set_due_someday":
+                self.on_set_due_someday,
+            "on_set_due_clear":
+                self.on_set_due_clear,
+            "on_dismiss_task":
+                self.on_dismiss_task,
+            "on_move":
+                self.on_move,
+            "on_size_allocate":
+                self.on_size_allocate,
+            "gtk_main_quit":
+                self.on_close,
+            "on_add_subtask":
+                self.on_add_subtask,
+            "on_tagcontext_deactivate":
+                self.on_tagcontext_deactivate,
+            "on_workview_toggled":
+                self.on_workview_toggled,
+            "on_view_workview_toggled":
+                self.on_workview_toggled,
+            "on_view_closed_toggled":
+                self.on_closed_toggled,
+            "on_view_sidebar_toggled":
+                self.on_sidebar_toggled,
+            "on_quickadd_field_activate":
+                self.on_quickadd_activate,
+            "on_quickadd_field_icon_press":
+                self.on_quickadd_iconpress,
+            "on_quickadd_field_changed":
+                self.on_quickadd_changed,
+            "on_quickadd_entrycompletion_action_activated":
+                self.on_entrycompletion_action_activated,
+            "on_view_quickadd_toggled":
+                self.on_toggle_quickadd,
+            "on_view_toolbar_toggled":
+                self.on_toolbar_toggled,
+            "on_about_clicked":
+                self.on_about_clicked,
+            "on_about_delete":
+                self.on_about_close,
+            "on_about_close":
+                self.on_about_close,
+            "on_documentation_clicked":
+                lambda w: openurl(info.HELP_URI),
+            "on_translate_clicked":
+                lambda w: openurl(info.TRANSLATE_URL),
+            "on_report_bug_clicked":
+                lambda w: openurl(info.REPORT_BUG_URL),
+            "on_preferences_activate":
+                self.open_preferences,
+            "on_edit_plugins_activate":
+                self.open_plugins,
+            "on_edit_backends_activate":
+                self.open_edit_backends,
+        }
+        self.builder.connect_signals(SIGNAL_CONNECTIONS_DIC)
+
+        # When destroying this window, quit GTG
+        self.window.connect("destroy", self.quit)
+
+        # Active tasks TreeView
+        self.vtree_panes['active'].connect('row-activated', \
+            self.on_edit_active_task)
+        self.vtree_panes['active'].connect('button-press-event', \
+            self.on_task_treeview_button_press_event)
+        self.vtree_panes['active'].connect('key-press-event', \
+            self.on_task_treeview_key_press_event)
+        self.vtree_panes['active'].connect('node-expanded', \
+            self.on_task_expanded)
+        self.vtree_panes['active'].connect('node-collapsed', \
+            self.on_task_collapsed)
+
+        b_signals = BackendSignals()
+        b_signals.connect(b_signals.BACKEND_FAILED, self.on_backend_failed)
+        b_signals.connect(b_signals.BACKEND_STATE_TOGGLED, \
+                          self.remove_backend_infobar)
+        b_signals.connect(b_signals.INTERACTION_REQUESTED, \
+                          self.on_backend_needing_interaction)
+        # Selection changes
+        self.selection = self.vtree_panes['active'].get_selection()
+        self.selection.connect("changed", self.on_task_cursor_changed)
+
+    def _add_accelerator_for_widget(self, agr, name, accel):
+        widget = self.builder.get_object(name)
+        key, mod = gtk.accelerator_parse(accel)
+        widget.add_accelerator("activate", agr, key, mod, gtk.ACCEL_VISIBLE)
+
+    def _init_accelerators(self):
+        """
+        initialize gtk accelerators for different interface elements
+        """
+        agr = gtk.AccelGroup()
+        self.builder.get_object("MainWindow").add_accel_group(agr)
+
+        self._add_accelerator_for_widget(agr, "view_sidebar", "F9")
+        self._add_accelerator_for_widget(agr, "file_quit", "<Control>q")
+        self._add_accelerator_for_widget(agr, "edit_undo", "<Control>z")
+        self._add_accelerator_for_widget(agr, "edit_redo", "<Control>y")
+        self._add_accelerator_for_widget(agr, "new_task_mi", "<Control>n")
+        self._add_accelerator_for_widget(agr, "new_subtask_mi",
+            "<Control><Shift>n")
+        self._add_accelerator_for_widget(agr, "edit_mi", "Return")
+        self._add_accelerator_for_widget(agr, "done_mi", "<Control>d")
+        self._add_accelerator_for_widget(agr, "dismiss_mi", "<Control>i")
+        self._add_accelerator_for_widget(agr, "tcm_modifytags", "<Control>t")
+        self._add_accelerator_for_widget(agr, "view_closed", "<Control>F9")
+        self._add_accelerator_for_widget(agr, "help_contents", "F1")
+
+        quickadd_field = self.builder.get_object("quickadd_field")
+        key, mod = gtk.accelerator_parse("<Control>l")
+        quickadd_field.add_accelerator("grab-focus", agr, key, mod,
+            gtk.ACCEL_VISIBLE)
+
+### HELPER FUNCTIONS ########################################################
+    def open_preferences(self, widget):
+        self.vmanager.open_preferences(self.config)
+        
+    def open_plugins(self, widget):
+        self.vmanager.configure_plugins()
+
+    def open_edit_backends(self, widget):
+        self.vmanager.open_edit_backends()
+
+    def quit(self, widget=None):
+        self.vmanager.close_browser()
+
+    def on_window_state_event(self, widget, event, data=None):
+        """ This event checks for the window state: maximized?
+        and stores the state in self.config.max
+        This is used to check the window state afterwards
+        and maximize it if needed """
+        mask = gtk.gdk.WINDOW_STATE_MAXIMIZED
+        if widget.get_window().get_state() & mask == mask:
+            self.config.set("max", True)
+        else:
+            self.config.set("max", False)
+
+    def restore_state_from_conf(self):
+
+#        # Extract state from configuration dictionary
+#        if not "browser" in self.config:
+#            #necessary to have the minimum width of the tag pane
+#            # inferior to the "first run" width
+#            self.builder.get_object("hpaned1").set_position(250)
+#            return
+
+        width = self.config.get('width')
+        height = self.config.get('height')
+        if width and height:
+            self.window.resize(width, height)
+
+        # checks for maximum size of window
+        self.window.connect('window-state-event', self.on_window_state_event)
+        if self.config.get("max"):
+            self.window.maximize()
+
+        xpos = self.config.get("x_pos")
+        ypos = self.config.get("y_pos")
+        if ypos and xpos:
+            self.window.move(xpos, ypos)
+
+        tag_pane = self.config.get("tag_pane")
+        if not tag_pane:
+            self.builder.get_object("view_sidebar").set_active(False)
+            self.sidebar.hide()
+        else:
+            self.builder.get_object("view_sidebar").set_active(True)
+            if not self.tagtreeview:
+                self.init_tags_sidebar()
+            self.sidebar.show()
+
+        sidebar_width = self.config.get("sidebar_width")
+        self.builder.get_object("hpaned1").set_position(sidebar_width)
+        self.builder.get_object("hpaned1").connect('notify::position',
+            self.on_sidebar_width)
+
+        closed_task_pane = self.config.get("closed_task_pane")
+        if not closed_task_pane:
+            self.hide_closed_pane()
+        else:
+            self.show_closed_pane()
+
+        botpos = self.config.get("bottom_pane_position")
+        self.builder.get_object("vpaned1").set_position(botpos)
+        self.builder.get_object("vpaned1").connect('notify::position',
+            self.on_bottom_pane_position)
+
+        toolbar = self.config.get("toolbar")
+        if toolbar:
+            self.builder.get_object("view_toolbar").set_active(1)
+        else:
+            self.toolbar.hide()
+            self.builder.get_object("view_toolbar").set_active(False)
+
+        quickadd_pane = self.config.get("quick_add")
+        if quickadd_pane:
+            self.builder.get_object("view_quickadd").set_active(True)
+        else:
+            self.quickadd_pane.hide()
+            self.builder.get_object("view_quickadd").set_active(False)
+
+        # Callbacks for sorting and restoring previous state
+        model = self.vtree_panes['active'].get_model()
+        model.connect('sort-column-changed', self.on_sort_column_changed)
+        sort_column = self.config.get('tasklist_sort_column')
+        sort_order = self.config.get('tasklist_sort_order')
+
+        if sort_column and sort_order:
+            sort_column, sort_order = int(sort_column), int(sort_order)
+            model.set_sort_column_id(sort_column, sort_order)
+
+        for path_s in self.config.get("collapsed_tasks"):
+            #the tuple was stored as a string. we have to reconstruct it
+            path = ()
+            for p in path_s[1:-1].split(","):
+                p = p.strip(" '")
+                path += (p, )
+            if path[-1] == '':
+                path = path[:-1]
+            self.vtree_panes['active'].collapse_node(path)
+
+        for t in self.config.get("collapsed_tags"):
+            #FIXME
+            print "Collapsing tag %s not implememted in browser.py" %t
+#            self.tagtreeview.set_collapsed_tags(toset)
+
+        self.set_view(self.config.get("view"))
+
+        def open_task(req, t):
+            """ Open the task if loaded. Otherwise ask for next iteration """
+            if req.has_task(t):
+                self.vmanager.open_task(t)
+                return False
+            else:
+                return True
+
+        for t in self.config.get("opened_tasks"):
+            gobject.idle_add(open_task, self.req, t)
+
+    def do_toggle_workview(self):
+        """ Switch between default and work view
+
+        Updating tags is disabled while changing view. It consumes
+        a lot of CPU cycles and the user does not see it. Afterwards,
+        updating of tags is re-enabled and all tags are refreshed.
+
+        Because workview can be switched from more than one button
+        (currently toggle button and check menu item), we need to change
+        status of others also. It invokes again this method =>
+        a loop of signals.
+
+        It is more flexible to have a dedicated variable
+        (self.in_toggle_workview) which prevents that recursion. The other way
+        how to solve this is to checking state of those two buttons and check
+        if they are not the same. Adding another way may complicate things...
+        """
+
+        if self.in_toggle_workview:
+            return
+
+        self.in_toggle_workview = True
+        self.tv_factory.disable_update_tags()
+
+        if self.config.get('view') == 'workview':
+            self.set_view('default')
+        else:
+            self.set_view('workview')
+
+        if self.tagtree is not None:
+            self.tv_factory.enable_update_tags()
+            self.tagtree.refresh_all()
+
+        self.in_toggle_workview = False
+
+    def set_view(self, viewname):
+        if viewname == 'default':
+            self.activetree.unapply_filter('workview')
+            workview = False
+        elif viewname == 'workview':
+            self.activetree.apply_filter('workview')
+            workview = True
+        else:
+            raise Exception('Cannot set the view %s' %viewname)
+        self.menu_view_workview.set_active(workview)
+        self.toggle_workview.set_active(workview)
+        #The config_set has to be after the toggle, else you will have a loop
+        self.config.set('view', viewname)
+        self.vtree_panes['active'].set_col_visible('startdate', not workview)
+
+    def _update_window_title(self, nid=None, path=None, state_id=None):
+        count = self.activetree.get_n_nodes()
+        #Set the title of the window:
+        parenthesis = ""
+        if count == 0:
+            parenthesis = _("no active tasks")
+        else:
+            parenthesis = ngettext("%(tasks)d active task", \
+                                   "%(tasks)d active tasks", \
+                                   count) % {'tasks': count}
+        self.window.set_title("%s - "%parenthesis + info.NAME)
+
+    def _add_page(self, notebook, label, page):
+        notebook.append_page(page, label)
+        if notebook.get_n_pages() > 1:
+            notebook.set_show_tabs(True)
+        page_num = notebook.page_num(page)
+        notebook.set_tab_detachable(page, True)
+        notebook.set_tab_reorderable(page, True)
+        notebook.set_current_page(page_num)
+        notebook.show_all()
+        return page_num
+
+    def _remove_page(self, notebook, page):
+        if page:
+            page.hide()
+            notebook.remove(page)
+        if notebook.get_n_pages() == 1:
+            notebook.set_show_tabs(False)
+        elif notebook.get_n_pages() == 0:
+            notebook.hide()
+
+### SIGNAL CALLBACKS ##########################################################
+# Typically, reaction to user input & interactions with the GUI
+#
+    def register_filter_callback(self, cb):
+        print "DEPRECATED function register_filter_callback."
+        print "It is only dummy funnction now, ready for removing"
+
+    def unregister_filter_callback(self, cb):
+        print "DEPRECATED function unregister_filter_callback."
+        print "It is only dummy funnction now, ready for removing"
+
+    def on_sort_column_changed(self, model):
+        sort_column, sort_order = model.get_sort_column_id()
+
+        if sort_order == gtk.SORT_ASCENDING:
+            sort_order = 0
+        else:
+            sort_order = 1
+
+        self.config.set('tasklist_sort_column', sort_column)
+        self.config.set('tasklist_sort_order', sort_order)
+
+    def on_move(self, widget = None, data = None):
+        xpos, ypos = self.window.get_position()
+        self.config.set('x_pos', xpos)
+        self.config.set('y_pos', ypos)
+
+    def on_size_allocate(self, widget = None, data = None):
+        width, height = self.window.get_size()
+        self.config.set('width', width)
+        self.config.set('height', height)
+
+    def on_bottom_pane_position(self, widget, data = None):
+        self.config.set('bottom_pane_position', widget.get_position())
+
+    def on_sidebar_width(self, widget, data = None):
+        self.config.set('sidebar_width', widget.get_position())
+
+    def on_about_clicked(self, widget):
+        """
+        show the about dialog
+        """
+        self.about.show()
+
+    def on_about_close(self, widget, response):
+        """
+        close the about dialog
+        """
+        self.about.hide()
+        return True
+
+    def on_tagcontext_deactivate(self, menushell):
+        self.reset_cursor()
+
+    def on_workview_toggled(self, widget):
+        self.do_toggle_workview()
+
+    def on_sidebar_toggled(self, widget):
+        view_sidebar = self.builder.get_object("view_sidebar")
+        if self.sidebar.get_property("visible"):
+            view_sidebar.set_active(False)
+            self.config.set("tag_pane", False)
+            self.sidebar.hide()
+        else:
+            view_sidebar.set_active(True)
+            if not self.tagtreeview:
+                self.init_tags_sidebar()
+            self.sidebar.show()
+            self.config.set("tag_pane", True)
+
+    def on_closed_toggled(self, widget):
+        if widget.get_active():
+            self.show_closed_pane()
+        else:
+            self.hide_closed_pane()
+
+    def __create_closed_tree(self):
+        closedtree = self.req.get_tasks_tree(name='closed', refresh=False)
+        closedtree.apply_filter('closed', refresh=False)
+        return closedtree
+
+    def show_closed_pane(self):
+        # The done/dismissed tasks treeview
+        if not 'closed' in self.vtree_panes:
+            ctree = self.__create_closed_tree()
+            self.vtree_panes['closed'] = \
+                         self.tv_factory.closed_tasks_treeview(ctree)
+                    # Closed tasks TreeView
+            self.vtree_panes['closed'].connect('row-activated', \
+                self.on_edit_done_task)
+            self.vtree_panes['closed'].connect('button-press-event', \
+                self.on_closed_task_treeview_button_press_event)
+            self.vtree_panes['closed'].connect('key-press-event', \
+                self.on_closed_task_treeview_key_press_event)
+
+            self.closed_selection = self.vtree_panes['closed'].get_selection()
+            self.closed_selection.connect("changed",
+                self.on_taskdone_cursor_changed)
+            ctree.apply_filter(self.get_selected_tags()[0], refresh=True)
+        if not self.closed_pane:
+            self.closed_pane = gtk.ScrolledWindow()
+            self.closed_pane.set_size_request(-1, 100)
+            self.closed_pane.set_policy(gtk.POLICY_AUTOMATIC,
+                gtk.POLICY_AUTOMATIC)
+            self.closed_pane.add(self.vtree_panes['closed'])
+
+        elif self.accessory_notebook.page_num(self.closed_pane) != -1:
+            # Already contains the closed pane
+            return
+
+        self.add_page_to_accessory_notebook("Closed", self.closed_pane)
+        self.builder.get_object("view_closed").set_active(True)
+        self.config.set('closed_task_pane', True)
+
+    def hide_closed_pane(self):
+        #If we destroy completely the vtree, we cannot display it anymore
+        #Check is to hide/show the closed task pane multiple times.
+        #I let this code commented for now because it might be useful
+        #for performance reason, to really destroy the view when we don't
+        #display it. (Lionel, 17092010)
+#        if self.vtree_panes.has_key('closed'):
+#            self.vtree_panes['closed'].set_model(None)
+#            del self.vtree_panes['closed']
+        self.remove_page_from_accessory_notebook(self.closed_pane)
+        self.builder.get_object("view_closed").set_active(False)
+        self.config.set('closed_task_pane', False)
+
+    def on_toolbar_toggled(self, widget):
+        if widget.get_active():
+            self.toolbar.show()
+            self.config.set('toolbar', True)
+        else:
+            self.toolbar.hide()
+            self.config.set('toolbar', False)
+
+    def on_toggle_quickadd(self, widget):
+        if widget.get_active():
+            self.quickadd_pane.show()
+            self.config.set('quick_add', True)
+        else:
+            self.quickadd_pane.hide()
+            self.config.set('quick_add', False)
+
+    def on_task_expanded(self, sender, tid):
+        colt = self.config.get("collapsed_tasks")
+        if tid in colt:
+            colt.remove(tid)
+
+    def on_task_collapsed(self, sender, tid):
+        colt = self.config.get("collapsed_tasks")
+        if tid not in colt:
+            colt.append(str(tid))
+
+    def on_quickadd_activate(self, widget):
+        """ Add a new task from quickadd toolbar """
+        text = unicode(self.quickadd_entry.get_text())
+        text = text.strip()
+        if text:
+            tags = self.get_selected_tags(nospecial=True)
+
+            # We will select quick-added task in browser.
+            # This has proven to be quite complex and deserves an explanation.
+            # We register a callback on the sorted treemodel that we're
+            # displaying, which is a TreeModelSort. When a row gets added,
+            # we're notified of it.
+            # We have to verify that that row belongs to the task we should
+            # select. So, we have to wait for the task to be created, and then
+            # wait for its tid to show up (invernizzi)
+            def select_next_added_task_in_browser(treemodelsort, path,
+                iter, self):
+
+                def selecter(treemodelsort, path, iter, self):
+                    self.__last_quick_added_tid_event.wait()
+                    treeview = self.vtree_panes['active']
+                    tid = self.activetree.get_node_for_path(path)
+                    if self.__last_quick_added_tid == tid:
+                        #this is the correct task
+                        treemodelsort.disconnect(
+                            self.__quick_add_select_handle)
+                        selection = treeview.get_selection()
+                        selection.unselect_all()
+                        selection.select_path(path)
+
+                #It cannot be another thread than the main gtk thread !
+                gobject.idle_add(selecter, treemodelsort, path, iter, self)
+            #event that is set when the new task is created
+            self.__last_quick_added_tid_event = threading.Event()
+            self.__quick_add_select_handle = \
+                    self.vtree_panes['active'].get_model().connect(
+                        "row-inserted", select_next_added_task_in_browser,
+                        self)
+            task = self.req.new_task(newtask=True)
+            self.__last_quick_added_tid = task.get_id()
+            self.__last_quick_added_tid_event.set()
+            task.set_complex_title(text, tags=tags)
+            self.quickadd_entry.set_text('')
+
+            #signal the event for the plugins to catch
+            gobject.idle_add(self.emit, "task-added-via-quick-add",
+                             task.get_id())
+        else:
+            #if no text is selected, we open the currently selected task
+            nids = self.vtree_panes['active'].get_selected_nodes()
+            for nid in nids:
+                self.vmanager.open_task(nid)
+
+    def on_quickadd_iconpress(self, widget, icon, event):
+        """ Clear the text in quickadd field by clicking on 'clear' icon """
+        if icon == gtk.ENTRY_ICON_SECONDARY:
+            self.quickadd_entry.set_text('')
+
+    def on_tag_treeview_button_press_event(self, treeview, event):
+        """
+        deals with mouse click event on the tag tree
+        """
         Log.debug("Received button event #%d at %d, %d" % (
             event.button, event.x, event.y))
         if event.button == 3: