← Back to team overview

gtg team mailing list archive

[Merge] lp:~gtg/gtg/liblarch_indpendant into lp:gtg

 

Lionel Dricot has proposed merging lp:~gtg/gtg/liblarch_indpendant into lp:gtg.

Requested reviews:
  Izidor Matušov (izidor)
Related bugs:
  Bug #827961 in Getting Things GNOME!: "put liblarch out of the repository"
  https://bugs.launchpad.net/gtg/+bug/827961

For more details, see:
https://code.launchpad.net/~gtg/gtg/liblarch_indpendant/+merge/92269

This put liblarch out of GTG source tree.

It goes like this:

1) GTG tries to import liblarch from the system.
2) if it fails, GTG tries to import liblarch from the parent folder.
3) if it fails, it tells you the git command to run to put liblarch in the parent folder

It also checks if the API version of liblarch is compatible.
-- 
https://code.launchpad.net/~gtg/gtg/liblarch_indpendant/+merge/92269
Your team Gtg developers is subscribed to branch lp:~gtg/gtg/liblarch_indpendant.
=== modified file 'GTG/core/tagstore.py'
--- GTG/core/tagstore.py	2012-02-01 05:27:07 +0000
+++ GTG/core/tagstore.py	2012-02-09 13:32:34 +0000
@@ -29,7 +29,7 @@
 
 from GTG              import _
 from GTG.core         import CoreConfig
-from GTG.tools.liblarch.tree    import TreeNode
+from liblarch         import TreeNode
 from GTG.tools        import cleanxml
 from GTG.tools.logger import Log
 

=== modified file 'GTG/core/task.py'
--- GTG/core/task.py	2012-02-08 18:03:44 +0000
+++ GTG/core/task.py	2012-02-09 13:32:34 +0000
@@ -32,7 +32,7 @@
 from GTG                     import _
 from GTG.tools.dates         import date_today, no_date, Date
 from datetime                import datetime
-from GTG.tools.liblarch.tree import TreeNode
+from liblarch                import TreeNode
 from GTG.tools.logger        import Log
 from GTG.tools.dates         import no_date, get_canonical_date
 

=== modified file 'GTG/core/treefactory.py'
--- GTG/core/treefactory.py	2012-02-05 19:25:30 +0000
+++ GTG/core/treefactory.py	2012-02-09 13:32:34 +0000
@@ -22,7 +22,7 @@
 from GTG.tools.dates  import date_today, no_date, Date
 
 from GTG                         import _
-from GTG.tools.liblarch          import Tree
+from liblarch                    import Tree
 from GTG.core.task               import Task
 from GTG.core.tagstore           import Tag
 from GTG.core         import CoreConfig

=== modified file 'GTG/gtk/browser/treeview_factory.py'
--- GTG/gtk/browser/treeview_factory.py	2012-02-05 18:23:28 +0000
+++ GTG/gtk/browser/treeview_factory.py	2012-02-09 13:32:34 +0000
@@ -26,7 +26,7 @@
 from GTG.core                         import CoreConfig
 from GTG.core.task                    import Task
 from GTG.gtk.browser.CellRendererTags import CellRendererTags
-from GTG.gtk.liblarch_gtk             import TreeView
+from liblarch_gtk                     import TreeView
 from GTG.gtk                          import colors
 from GTG.tools                        import dates
 

=== removed directory 'GTG/gtk/liblarch_gtk'
=== removed file 'GTG/gtk/liblarch_gtk/__init__.py'
--- GTG/gtk/liblarch_gtk/__init__.py	2012-02-06 18:17:12 +0000
+++ GTG/gtk/liblarch_gtk/__init__.py	1970-01-01 00:00:00 +0000
@@ -1,524 +0,0 @@
-# -*- coding: utf-8 -*-
-# -----------------------------------------------------------------------------
-# Gettings Things Gnome! - a personal organizer for the GNOME desktop
-# Copyright (c) 2008-2011 - 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.
-#
-# 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/>.
-# -----------------------------------------------------------------------------
-
-import gtk
-import gobject
-
-from GTG.gtk.liblarch_gtk.treemodel import TreeModel
-
-
-# Useful for debugging purpose.
-# Disabling that will disable the TreeModelSort on top of our TreeModel
-ENABLE_SORTING = True
-USE_TREEMODELFILTER = False
-
-class TreeView(gtk.TreeView):
-    """ Widget which display LibLarch FilteredTree.
-
-    This widget extends gtk.TreeView by several features:
-      * Drag'n'Drop support
-      * Sorting support
-      * separator rows
-      * background color of a row
-      * selection of multiple rows
-    """
-
-    __string_signal__ = (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE, (str, ))
-    __gsignals__ = {'node-expanded' : __string_signal__, \
-                    'node-collapsed': __string_signal__, \
-                    }
-
-    def __init__(self, tree, description):
-        """ Build the widget
-
-        @param  tree - LibLarch FilteredTree
-        @param  description - definition of columns.
-
-        Parameters of description dictionary for a column:
-          * value => (type of values, function for generating value from a node)
-          * renderer => (renderer_attribute, renderer object)
-
-          Optional:
-          * order => specify order of column otherwise use natural oreder
-          * expandable => is the column expandable?
-          * resizable => is the column resizable?
-          * visible => is the column visible?
-          * title => title of column
-          * new_colum => do not create a separate column, just continue with the previous one
-                (this can be used to create columns without borders)
-          * sorting => allow default sorting on this column
-          * sorting_func => use special function for sorting on this func
-
-        Example of columns descriptions:
-        description = { 'title': {
-                'value': [str, self.task_title_column],
-                'renderer': ['markup', gtk.CellRendererText()],
-                'order': 0
-            }}
-        """
-        gtk.TreeView.__init__(self)
-        self.columns = {}
-        self.bg_color_func = None
-        self.bg_color_column = None
-        self.separator_func = None
-
-        self.dnd_internal_target = ''
-        self.dnd_external_targets = {}
-        
-        # Sort columns
-        self.order_of_column = []
-        last = 9999
-        for col_name in description:
-            desc = description[col_name]
-            order = desc.get('order', last)
-            last += 1
-            self.order_of_column.append((order, col_name))
-
-        types = []
-        sorting_func = []
-        # Build the first coulumn if user starts with new_colum=False
-        col = gtk.TreeViewColumn()
-
-        # Build columns according to the order
-        for col_num, (order_num, col_name) in enumerate(sorted(self.order_of_column), 1):
-            desc = description[col_name]
-            types.append(desc['value'])
-
-            expand = desc.get('expandable', False)
-            resizable = desc.get('resizable', True)
-            visible = desc.get('visible', True)
-
-            if 'renderer' in desc:
-                rend_attribute, renderer = desc['renderer']
-            else:
-                rend_attribute = 'markup'
-                renderer = gtk.CellRendererText()
-
-            # If new_colum=False, do not create new column, use the previous one
-            # It will create columns without borders
-            if desc.get('new_column',True):
-                col = gtk.TreeViewColumn()
-                newcol = True
-            else:
-                newcol = False
-            col.set_visible(visible)
-
-            if 'title' in desc:
-                col.set_title(desc['title'])
-
-            col.pack_start(renderer, expand=expand)
-            col.add_attribute(renderer, rend_attribute, col_num)
-            col.set_resizable(resizable)
-            col.set_expand(expand)
-
-            # Allow to set background color
-            col.set_cell_data_func(renderer, self._celldatafunction)
-            
-            if newcol:
-                self.append_column(col)
-            self.columns[col_name] = (col_num, col)
-
-            if ENABLE_SORTING:
-                if 'sorting' in desc:
-                    # Just allow sorting and use default comparing
-                    sort_num, sort_col = self.columns[desc['sorting']]
-                    col.set_sort_column_id(sort_num)
-
-                if 'sorting_func' in desc:
-                    # Use special funcion for comparing, e.g. dates
-                    sorting_func.append((col_num, col, desc['sorting_func']))
-
-        self.basetree = tree
-        # Build the model around LibLarch tree
-        self.basetreemodel = TreeModel(tree, types)
-        #Applying an intermediate treemodelfilter, for debugging purpose
-        if USE_TREEMODELFILTER:
-            treemodelfilter = self.basetreemodel.filter_new()
-        else:
-            treemodelfilter = self.basetreemodel
-        # Apply TreeModelSort to be able to sort
-        if ENABLE_SORTING:
-#            self.treemodel = gtk.TreeModelSort(treemodelfilter)
-            self.treemodel = self.basetreemodel
-            for col_num, col, sort_func in sorting_func:
-                self.treemodel.set_sort_func(col_num,
-                    self._sort_func, sort_func)
-                col.set_sort_column_id(col_num)
-        else:
-            self.treemodel = treemodelfilter
-
-        self.set_model(self.treemodel)
-
-        self.expand_all()
-        self.show()
-        
-        
-        self.collapsed_paths = []
-        self.connect('row-expanded', self.__emit, 'expanded')
-        self.connect('row-collapsed', self.__emit, 'collapsed')
-        self.treemodel.connect('row-has-child-toggled', self.on_child_toggled)
-
-    def __emit(self, sender, iter, path, data):
-        """ Emitt expanded/collapsed signal """
-        node_id = self.treemodel.get_value(iter, 0)
-        #recreating the path of the collapsed node
-        ll_path = ()
-        i = 1
-        while i <= len(path):
-            temp_iter = self.treemodel.get_iter(path[:i])
-            ll_path += (self.treemodel.get_value(temp_iter,0),)
-            i+=1
-        if data == 'expanded':
-            self.emit('node-expanded', ll_path)
-        elif data == 'collapsed':
-            self.emit('node-collapsed', ll_path)
-
-    def on_child_toggled(self, treemodel, path, iter, param=None):
-        """ Expand row """
-        #is the toggled node in the collapsed paths?
-        collapsed = False
-        nid = treemodel.get_value(iter,0)
-        while iter and not collapsed:
-            for c in self.collapsed_paths:
-                if c[-1] == nid:
-                    collapsed = True
-            iter = treemodel.iter_parent(iter)
-        if not self.row_expanded(path) and not collapsed:
-            self.expand_row(path, True)
-            
-
-    def collapse_node(self, llpath):
-        """ Hide children of a node
-        
-        This method is needed for "rember collapsed nodes" feature of GTG.
-        Transform node_id into paths and those paths collapse. By default all
-        children are expanded (see self.expand_all())"""
-        node_id = llpath[-1].strip("'")
-        if not node_id:
-            raise Exception('pas de node_id pour %s' %str(llpath))
-        if not self.basetree.is_displayed(node_id):
-            self.basetree.queue_action(node_id,self.collapse_node,param=llpath)
-        else:
-            iter = self.basetreemodel.my_get_iter(llpath)
-            if iter:
-                target_path = self.basetreemodel.get_path(iter)
-                if self.basetreemodel.get_value(iter,0) == node_id:
-                    self.collapse_row(target_path)
-                    self.collapsed_paths.append(llpath)
-                    it = self.basetreemodel.get_iter(target_path)
-                    newid = self.basetreemodel.get_value(it,0)
-                else:
-                    self.basetree.queue_action(node_id,self.collapse_node,param=llpath)
-            else:
-                #if we don't have iter, it is probably because the TreeModel
-                #is not loaded yet. Let just wait one more time
-                self.basetree.queue_action(node_id,self.collapse_node,param=llpath)
-                        
-
-    def show(self):
-        """ Shows the TreeView and connect basetreemodel to LibLarch """
-        gtk.TreeView.show(self)
-        self.basetreemodel.connect_model()
-
-    def get_columns(self):
-        """ Return the list of columns name """
-        return self.columns.keys()
-
-    def set_main_search_column(self, col_name):
-        """ Set search column for GTK integrate search
-        This is just wrapper to use internal representation of columns"""
-        col_num, col = self.columns[col_name]
-        self.set_search_column(col_num)
-
-    def set_expander_column(self, col_name):
-        """ Set expander column (that which expands through free space)
-        This is just wrapper to use internal representation of columns"""
-        col_num, col = self.columns[col_name]
-        self.set_property("expander-column", col)
-
-    def set_sort_column(self, col_name):
-        """ Select column to sort by it by default """
-        if ENABLE_SORTING:
-            col_num, col = self.columns[col_name]
-            self.treemodel.set_sort_column_id(col_num, gtk.SORT_ASCENDING)
-
-    def set_col_visible(self, col_name,visible):
-        """ Set visiblity of column.
-        Allow to hide/show certain column """
-        col_num, col = self.columns[col_name]
-        col.set_visible(visible)
-
-    def set_col_resizable(self, col_name, resizable):
-        """ Allow/forbid column to be resizable """
-        col_num, col = self.columns[col_name]
-        col.set_resizable(resizable)
-
-    def set_bg_color(self, color_func, color_column):
-        """ Set which column and function for generating background color """
-        if self.columns.has_key(color_column):
-            self.bg_color_column = self.columns[color_column][0]
-            self.bg_color_func = color_func
-        else:
-            raise ValueError("There is no colum %s to use to set color" % color_column)
-
-    def _sort_func(self, model, iter1, iter2, func=None):
-        """ Sort two iterators by function which gets node objects.
-        This is a simple wrapper which prepares node objects and then
-        call comparing function. In other case return default value -1
-        """
-        node_id_a = model.get_value(iter1, 0)
-        node_id_b = model.get_value(iter2, 0)
-        if node_id_a and node_id_b and func:
-            id, order = self.treemodel.get_sort_column_id()
-            node_a = self.basetree.get_node(node_id_a)
-            node_b = self.basetree.get_node(node_id_b)
-            sort = func(node_a, node_b, order)
-        else:
-            sort = -1
-        return sort
-
-    def _celldatafunction(self, column, cell, model, iter):
-        """ Determine background color for cell
-        
-        Requirements: self.bg_color_func and self.bg_color_column must be set
-        (see self.set_bg_color())
-        
-        We need:
-            * the standard color for a cell (it depends on GTK theme).
-            * value of column which the background is generated from
-              (e.g. list of tags)
-
-        Then the function for calculating background color is called.
-        Result is set as background of cell.
-        """
-        color = None
-        if self.bg_color_func and self.bg_color_column:
-            bgcolor = column.get_tree_view().get_style().base[gtk.STATE_NORMAL]
-            if iter and model.iter_is_valid(iter):
-                value = model.get_value(iter, self.bg_color_column)
-                if value:
-                    color = self.bg_color_func(value, bgcolor)
-        cell.set_property("cell-background", color)
-
-    ######### DRAG-N-DROP functions #####################################
-
-    def set_dnd_name(self, dndname):
-        """ Sets Drag'n'Drop name and initialize Drag'n'Drop support
-        
-        If ENABLE_SORTING, drag_drop signal must be handled by this widget."""
-        self.dnd_internal_target = dndname
-        self.__init_dnd()
-        self.connect('drag_data_get', self.on_drag_data_get)
-        self.connect('drag_data_received', self.on_drag_data_received)
-            
-
-    def set_dnd_external(self, sourcename, func):
-        """ Add a new external target and initialize Drag'n'Drop support"""
-        i = 1
-        while self.dnd_external_targets.has_key(i):
-            i += 1
-        self.dnd_external_targets[i] = [sourcename, func]
-        self.__init_dnd()
-
-    def __init_dnd(self):
-        """ Initialize Drag'n'Drop support
-        
-        Firstly build list of DND targets:
-            * name
-            * scope - just the same widget / same application
-            * id
-
-        Enable DND by calling enable_model_drag_dest(), 
-        enable_model-drag_source()
-
-        It didnt use support from gtk.Widget(drag_source_set(),
-        drag_dest_set()). To know difference, look in PyGTK FAQ:
-        http://faq.pygtk.org/index.py?file=faq13.033.htp&req=show
-        """
-        self.defer_select = False
-        
-        if self.dnd_internal_target == '':
-            error = 'Cannot initialize DND without a valid name\n'
-            error += 'Use set_dnd_name() first'
-            raise Exception(error)
-            
-        dnd_targets = [(self.dnd_internal_target, gtk.TARGET_SAME_WIDGET, 0)]
-        for target in self.dnd_external_targets:
-            name = self.dnd_external_targets[target][0]
-            dnd_targets.append((name, gtk.TARGET_SAME_APP, target))
-    
-        self.enable_model_drag_source( gtk.gdk.BUTTON1_MASK,
-            dnd_targets, gtk.gdk.ACTION_DEFAULT | gtk.gdk.ACTION_MOVE)
-
-        self.enable_model_drag_dest(\
-            dnd_targets, gtk.gdk.ACTION_DEFAULT | gtk.gdk.ACTION_MOVE)
-    
-    def on_drag_data_get(self, treeview, context, selection, info, timestamp):
-        """ Extract data from the source of the DnD operation.
-        
-        Serialize iterators of selected tasks in format 
-        <iter>,<iter>,...,<iter> and set it as parameter of DND """
-
-        treeselection = treeview.get_selection()
-        model, paths = treeselection.get_selected_rows()
-        iters = [model.get_iter(path) for path in paths]
-        iter_str = ','.join([model.get_string_from_iter(iter) for iter in iters])
-        selection.set(self.dnd_internal_target, 0, iter_str)
-
-    def on_drag_data_received(self, treeview, context, x, y, selection, info,\
-                              timestamp):
-        """ Handle a drop situation.
-
-        First of all, we need to get id of node which should accept
-        all draged nodes as their new children. If there is no node,
-        drop to root node.
-
-        Deserialize iterators of dragged nodes (see self.on_drag_data_get())
-        Info parameter determines which target was used:
-            * info == 0 => internal DND within this TreeView
-            * info > 0 => external DND
-        
-        In case of internal DND we just use Tree.move_node().
-        In case of external DND we call function associated with that DND
-        set by self.set_dnd_external()
-        """
-        #TODO: it should be configurable for each TreeView if you want:
-        # 0 : no drag-n-drop at all
-        # 1 : drag-n-drop move the node
-        # 2 : drag-n-drop copy the node 
-
-        model = treeview.get_model()
-        drop_info = treeview.get_dest_row_at_pos(x, y)
-        if drop_info:
-            path, position = drop_info
-            iter = model.get_iter(path)
-            # Must add the task to the parent of the task situated
-            # before/after 
-            if position == gtk.TREE_VIEW_DROP_BEFORE or\
-               position == gtk.TREE_VIEW_DROP_AFTER:
-                # Get sibling parent
-                destination_iter = model.iter_parent(iter)
-            else:
-                # Must add task as a child of the dropped-on iter
-                # Get parent
-                destination_iter = iter
-
-            if destination_iter:
-                destination_tid = model.get_value(destination_iter, 0)
-            else:
-                #it means we have drag-n-dropped above the first task
-                # we should consider the destination as a root then.
-                destination_tid = None
-        else:
-            # Must add the task to the root
-            # Parent = root => iter=None
-            destination_tid = None
-
-        tree = self.basetree.get_basetree()
-
-        # Get dragged iter as a TaskTreeModel iter
-        # If there is no selected task (empty selection.data), 
-        # explictly skip handling it (set to empty list)
-        if selection.data == '':
-            iters = []
-        else:
-            iters = selection.data.split(',')
-
-        dragged_iters = []
-        for iter in iters:
-            if info == 0:
-                try:
-                    dragged_iters.append(model.get_iter_from_string(iter))
-                except ValueError:
-                    #I hate to silently fail but we have no choice.
-                    #It means that the iter is not good.
-                    #Thanks shitty gtk API for not allowing us to test the string
-                    dragged_iter = None
-
-            elif info in self.dnd_external_targets and destination_tid:
-                f = self.dnd_external_targets[info][1]
-
-                src_model = context.get_source_widget().get_model()
-                dragged_iters.append(src_model.get_iter_from_string(iter))
-                
-                
-        for dragged_iter in dragged_iters:
-            if info == 0:
-                if dragged_iter and model.iter_is_valid(dragged_iter):
-                    dragged_tid = model.get_value(dragged_iter, 0)
-                    try:
-                        tree.move_node(dragged_tid, new_parent_id=destination_tid)
-                    except Exception, e:
-                        print 'Problem with dragging: %s' % e
-            elif info in self.dnd_external_targets and destination_tid:    
-                source = src_model.get_value(dragged_iter,0)
-                # Handle external Drag'n'Drop
-                f(source, destination_tid)
-
-
-    ######### Separators support ##############################################
-    def _separator_func(self, model, itera, user_data=None):
-        """ Call user function to determine if this node is separator """
-        if itera and model.iter_is_valid(itera):
-            node_id = model.get_value(itera, 0)
-            node = self.basetree.get_node(node_id)
-            if self.separator_func:
-                return self.separator_func(node)
-            else:
-                return False
-        else:
-            return False
-
-    def set_row_separator_func(self, func):
-        """ Enable support for row separators.
-
-        @param func - function which determines if a node is separator,
-            None will disable support for row separators.
-        """
-        self.separator_func = func
-        gtk.TreeView.set_row_separator_func(self,self._separator_func)
-
-    ######### Multiple selection ####################################################
-    def get_selected_nodes(self):
-        """ Return list of node_id from liblarch for selected nodes """
-        # Get the selection in the gtk.TreeView
-        selection = self.get_selection()
-        # Get the selection iter
-        if selection.count_selected_rows() <= 0:
-            ids = []
-        else:
-            model, paths = selection.get_selected_rows()
-            iters = [model.get_iter(path) for path in paths]
-            ts  = self.get_model()
-            #0 is the column of the tid
-            ids = [ts.get_value(iter, 0) for iter in iters]
-
-        return ids
-
-    def set_multiple_selection(self, multiple_selection):
-        """ Allow/forbid multiple selection in TreeView """
-        # TODO support for dragging multiple rows at the same time
-        # See LP #817433
-
-        if multiple_selection:
-            selection_type = gtk.SELECTION_MULTIPLE
-        else:
-            selection_type = gtk.SELECTION_SINGLE
-
-        self.get_selection().set_mode(selection_type)

=== removed file 'GTG/gtk/liblarch_gtk/treemodel.py'
--- GTG/gtk/liblarch_gtk/treemodel.py	2012-02-07 12:33:46 +0000
+++ GTG/gtk/liblarch_gtk/treemodel.py	1970-01-01 00:00:00 +0000
@@ -1,193 +0,0 @@
-# -*- coding: utf-8 -*-
-# -----------------------------------------------------------------------------
-# Gettings Things Gnome! - a personal organizer for the GNOME desktop
-# Copyright (c) 2008-2011 - 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.
-#
-# 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/>.
-# -----------------------------------------------------------------------------
-
-import gtk
-
-class TreeModel(gtk.TreeStore):
-    """ Local copy of showed tree """
-
-    def __init__(self, tree, types):
-        """ Initializes parent and create list of columns. The first colum
-        is node_id of node """
-        
-        self.count = 0
-        self.count2 = 0
-
-        self.types = [[str, lambda node: node.get_id()]] + types
-        only_types = [python_type for python_type, access_method in self.types]
-
-        gtk.TreeStore.__init__(self, *only_types)
-        self.cache_paths = {}
-        self.cache_position = {}
-        self.tree = tree
-
-    def connect_model(self):
-        """ Register "signals", callbacks from liblarch.
-        
-        Also asks for the current status by providing add_task callback.
-        We are able to connect to liblarch tree on the fly. """
-
-        self.tree.register_cllbck('node-added-inview',self.add_task)
-        self.tree.register_cllbck('node-deleted-inview',self.remove_task)
-        self.tree.register_cllbck('node-modified-inview',self.update_task)
-        self.tree.register_cllbck('node-children-reordered',self.reorder_nodes)
-
-        # Request the current state
-        self.tree.get_current_state()
-
-    def my_get_iter(self, path):
-        """ Because we sort the TreeStore, paths in the treestore are
-        not the same as paths in the FilteredTree. We do the  conversion here.
-        We receive a Liblarch path as argument and return a gtk.TreeIter"""
-        #The function is recursive. We take iter for path (A,B,C) in cache.
-        #If there is not, we take iter for path (A,B) and try to find C.
-        if path == ():
-            return None
-        nid = str(path[-1])
-        self.count += 1
-        #We try to use the cache
-        iter = self.cache_paths.get(path,None)
-        toreturn = None
-        if iter and self.iter_is_valid(iter) and nid == self.get_value(iter,0):
-            self.count2 += 1
-            toreturn = iter
-        else:
-            root = self.my_get_iter(path[:-1])
-            #This is a small ad-hoc optimisation.
-            #Instead of going through all the children nodes
-            #We go directly at the last known position.
-            pos = self.cache_position.get(path,None)
-            if pos:
-                iter = self.iter_nth_child(root,pos)
-                if iter and self.get_value(iter,0) == nid:
-                    toreturn = iter
-            if not toreturn:
-                if root:
-                    iter = self.iter_children(root)
-                else:
-                    iter = self.get_iter_first()
-                while iter and self.get_value(iter,0) != nid:
-                    iter = self.iter_next(iter)
-            self.cache_paths[path] = iter
-            toreturn = iter
-#        print "%s / %s" %(self.count2,self.count)
-#        print "my_get_iter %s : %s" %(nid,self.get_string_from_iter(toreturn))
-        return toreturn
-
-    def print_tree(self):
-        """ Print TreeStore as Tree into console """
-
-        def push_to_stack(stack, level, iterator):
-            """ Macro which adds a new element into stack if it is possible """
-            if iterator is not None:
-                stack.append((level, iterator))
-
-        stack = []
-        push_to_stack(stack, 0, self.get_iter_first())
-
-        print "+"*50
-        print "Treemodel print_tree: "
-        while stack != []:
-            level, iterator = stack.pop()
-
-            print "=>"*level, self.get_value(iterator, 0)
-
-            push_to_stack(stack, level, self.iter_next(iterator))
-            push_to_stack(stack, level+1, self.iter_children(iterator))
-        print "+"*50
-
-### INTERFACE TO LIBLARCH #####################################################
-
-    def add_task(self, node_id, path):
-        """ Add new instance of node_id to position described at path.
-
-        @param node_id: identification of task
-        @param path: identification of position
-        """
-        node = self.tree.get_node(node_id)
-
-        # Build a new row
-        row = []
-        for python_type, access_method in self.types:
-            value = access_method(node)
-            row.append(value)
-
-        # Find position to add task
-        iter_path = path[:-1]
-
-        iterator = self.my_get_iter(iter_path)
-        self.cache_position[path] = self.iter_n_children(iterator)
-        it = self.insert(iterator, -1, row)
-        
-        # Show the new task if possible
-#        self.row_has_child_toggled(self.get_path(it), it)
-
-    def remove_task(self, node_id, path):
-        """ Remove instance of node.
-
-        @param node_id: identification of task
-        @param path: identification of position
-        """
-        it = self.my_get_iter(path)
-        if not it:
-            raise Exception("Trying to remove node %s with no iterator"%node_id)
-        actual_node_id = self.get_value(it, 0)
-        assert actual_node_id == node_id
-        self.remove(it)
-        self.cache_position.pop(path)
-
-    def update_task(self, node_id, path):
-        """ Update instance of node by rebuilding the row.
-
-        @param node_id: identification of task
-        @param path: identification of position
-        """
-        #We cannot assume that the node is in the tree because
-        #update is asynchronus
-        #Also, we should consider that missing an update is not critical
-        #and ignoring the case where there is no iterator
-        if self.tree.is_displayed(node_id):
-            node = self.tree.get_node(node_id)
-            #That call to my_get_iter is really slow!
-            iterator = self.my_get_iter(path)
-        
-            if iterator:
-                for column_num, (python_type, access_method) in enumerate(self.types):
-                    value = access_method(node)
-                    self.set_value(iterator, column_num, value)
-
-    def reorder_nodes(self, node_id, path, neworder):
-        """ Reorder nodes.
-        
-        This is deprecated signal. In the past it was useful for reordering
-        showed nodes of tree. It was possible to delete just the last
-        element and therefore every element must be moved to the last position
-        and then deleted.
-
-        @param node_id: identification of root node
-        @param path: identification of poistion of root node
-        @param neworder: new order of children of root node
-        """
-
-        if path is not None:
-            it = self.my_get_iter(path)
-        else:
-            it = None
-        self.reorder(it, neworder)
-        self.print_tree()

=== removed file 'GTG/tests/test_liblarch.py'
--- GTG/tests/test_liblarch.py	2012-02-06 18:17:12 +0000
+++ GTG/tests/test_liblarch.py	1970-01-01 00:00:00 +0000
@@ -1,1765 +0,0 @@
-# -*- coding: utf-8 -*-
-# -----------------------------------------------------------------------------
-# Gettings Things Gnome! - a personal organizer for the GNOME desktop
-# Copyright (c) 2008-2010- 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.
-#
-# 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/>.
-# -----------------------------------------------------------------------------
-
-"""Tests for the tagstore."""
-
-import unittest
-import gtk
-import gobject
-import functools
-import inspect
-import time
-import random
-
-from GTG.tools.liblarch import Tree
-from GTG.tools.liblarch.tree import TreeNode
-from GTG.gtk.liblarch_gtk import TreeView
-from GTG.tests.signals_testing import SignalCatcher, CallbackCatcher, GobjectSignalsManager
-from GTG.tests.tree_testing import TreeTester
-
-# Prefer callbacks or signals?
-USE_CALLBACKS_INSTEAD_OF_SIGNALS=True
-
-#This is a dummy treenode that only have one properties: a color
-class DummyNode(TreeNode):
-    def __init__(self,tid):
-        TreeNode.__init__(self, tid)
-        self.colors = []
-
-    def add_color(self,color):
-        if color not in self.colors:
-            self.colors.append(color)
-        self.modified()
-
-    def has_color(self,color):
-        return color in self.colors
-
-    def remove_color(self,color):
-        if color in self.colors:
-            self.colors.remove(color)
-        self.modified()
-
-
-
-class TestLibLarch(unittest.TestCase):
-    """Tests for `Tree`."""
-
-
-    def caller_name(self):
-        '''
-        Returns the filename and the line of the calling function.
-        Precisely, it returns the calling calling function (because
-        you're calling this one).
-        '''
-        frame=inspect.currentframe()
-        frame=frame.f_back.f_back
-        code=frame.f_code
-        return code.co_filename, code.co_firstlineno    
-
-    def _assertSignal(self, generator, signal_name, function, \
-                     how_many_signals = 1):
-        def new(how_many_signals, error_code, *args, **kws):
-            with SignalCatcher(self, generator, signal_name,\
-                               how_many_signals = how_many_signals,
-                               error_code = error_code)\
-                    as [signal_catched_event, signal_arguments]:
-                function(*args, **kws)
-                signal_catched_event.wait()
-                self.recorded_signals[signal_name] += signal_arguments
-            return None
-
-        # Functools.partial create something like a closure. It provides
-        # several arguments by default, but additional arguments are
-        # still possible
-        return functools.partial(new, how_many_signals, self.caller_name())
-
-    def _assertCallback(self, generator, signal_name, function, \
-                     how_many_signals = 1):
-        def new(how_many_signals, error_code, *args, **kws):
-            with CallbackCatcher(self, generator, signal_name,\
-                               how_many_signals = how_many_signals,
-                               error_code = error_code)\
-                    as [signal_catched_event, signal_arguments]:
-                function(*args, **kws)
-                #Ensuring there's no async signal left
-                generator.flush()
-                signal_catched_event.wait()
-                self.recorded_signals[signal_name] += signal_arguments
-            return None
-
-        return functools.partial(new, how_many_signals, self.caller_name())
-
-    if USE_CALLBACKS_INSTEAD_OF_SIGNALS:
-        assertSignal = _assertCallback
-    else:
-        assertSignal = _assertSignal
-
-    def test_assertSignal(self):
-        """ Creates a fake GObject which emits N signals and test whether
-        they are emitted.
-
-        The last parameter of assertSignal(...)(33) is parameter for
-        FakeGobject.emit_n_signals.
-        """
-
-        class FakeGobject(gobject.GObject):
-            __gsignals__ = {'node-added-inview': (gobject.SIGNAL_RUN_FIRST,
-                                    gobject.TYPE_NONE, [])}
-            def emit_n_signals(self, n):
-                while n:
-                    n -= 1
-                    gobject.idle_add(self.emit, 'node-added-inview')
-        fake_gobject = FakeGobject() 
-        self._assertSignal(fake_gobject, \
-                          'node-added-inview', \
-                          fake_gobject.emit_n_signals, 33)(33)
-
-    def setUp(self):
-        """Set up a dummy tree with filters and nodes.
-
-        Construct a Tree for testing, with some filters for testing, including
-        filters with parameters 'flat' and 'transparent'.  Create a collection of
-        nodes with some of the properties these filters filter on.
-        """
-        i = 0
-        #node numbers, used to check
-        self.red_nodes = 0
-        self.blue_nodes = 0
-        self.green_nodes = 0
-        #Larch, is the tree. Learn to recognize it.
-        self.tree = Tree()
-        self.view = self.tree.get_viewtree()
-        self.tester = TreeTester(self.view)
-        self.mainview = self.tree.get_main_view()
-        self.tree.add_filter('blue',self.is_blue)
-        self.tree.add_filter('green',self.is_green)
-        self.tree.add_filter('red',self.is_red)
-        self.tree.add_filter('leaf',self.is_leaf)
-        param = {}
-        param['flat'] = True
-        self.tree.add_filter('flatgreen',self.is_green,parameters=param)
-        self.tree.add_filter('flatleaves',self.is_leaf,parameters=param)
-        param = {}
-        param['transparent'] = True
-        self.tree.add_filter('transblue',self.is_blue,parameters=param)
-        self.tree.add_filter('transgreen',self.is_green,parameters=param)
-        #first, we add some red nodes at the root
-        while i < 5:
-            node = DummyNode(str(i))
-            node.add_color('red')
-            self.tree.add_node(node)
-            i += 1
-            self.red_nodes += 1
-        #then, we add some blue nodes also at the root
-        while i < 10:
-            node = DummyNode(str(i))
-            node.add_color('blue')
-            self.tree.add_node(node)
-            i+=1
-            self.blue_nodes += 1
-        #finally, we add some green nodes as children of the last nodes
-        # (stairs-like configuration)
-        while i < 15:
-            node = DummyNode(str(i))
-            node.add_color('green')
-            self.tree.add_node(node,parent_id=str(i-1))
-            i+=1
-            self.green_nodes += 1
-        self.total = self.red_nodes + self.blue_nodes + self.green_nodes
-        ################now testing the GTK treeview ##################
-        #The columns description:
-        desc = {}
-        col = {}
-        col['title'] = "Node name"
-        render_text = gtk.CellRendererText()
-        col['renderer'] = ['markup',render_text]
-        def get_node_name(node):
-            return node.get_id()
-        col['value'] = [str,get_node_name]
-        desc['titles'] = col
-        treeview = TreeView(self.view,desc)
-        #initalize gobject signaling system
-        self.gobject_signal_manager = GobjectSignalsManager()
-        self.gobject_signal_manager.init_signals()
-        self.recorded_signals = {'node-added-inview': [],
-                                 'node-modified-inview': [],
-                                 'node-deleted-inview': []}
-        self.assertNodeAddedInview = functools.partial ( \
-            self.assertSignal, self.view, 'node-added-inview')
-        self.assertNodeModifiedInview = functools.partial ( \
-            self.assertSignal, self.view, 'node-modified-inview')
-        self.assertNodeDeletedInview = functools.partial ( \
-            self.assertSignal, self.view, 'node-deleted-inview')
-
-    def tearDown(self):
-        try:
-            self.tester.test_validity()
-        finally:
-            #stopping gobject main loop
-            self.gobject_signal_manager.terminate_signals()
-        
-    ####Filters
-    def is_blue(self,node,parameters=None):
-        return node.has_color('blue')
-    def is_green(self,node,parameters=None):
-        return node.has_color('green')
-    def is_red(self,node,parameters=None):
-        return node.has_color('red')
-    def is_leaf(self,node,parameters=None):
-        return not node.has_child()
-        
-    #### Testing nodes movements in the tree
-    #### We test by counting nodes that meet some criterias
-    
-    def test_get_node(self):
-        """Test that one node can be retrieved from the tree
-        """
-
-        view = self.tree.get_viewtree()
-        self.assertEqual(view.get_node_for_path(()), None)
-        #we test that get node works for the last node
-        node = self.tree.get_node(str(self.total-1))
-        self.assertTrue(node != None)
-        self.assertEqual(str(self.total-1),node.get_id())
-        #and not for an non-existing node
-        self.assertRaises(ValueError,self.tree.get_node,str(self.total))
-
-    def test_add_remove_node(self):
-        """ Test the adding and removal of nodes """
-        view = self.tree.get_viewtree(refresh=True)
-        node = DummyNode('temp')
-        node.add_color('blue')
-
-        # run "self.tree.add_node(node, parent_id = '0')" and check that 
-        # it generates a 'node-added-view' AND a 'node-modified-inview'
-        self.assertSignal(self.view, \
-                            'node-modified-inview', \
-                            self.assertSignal(self.view, \
-                                              'node-added-inview', \
-                                          self.tree.add_node))(node, parent_id = '0')
-        self.assertTrue(('temp',('0', 'temp')) in self.recorded_signals['node-added-inview'])
-        self.assertTrue(('0',('0', )) in \
-                     self.recorded_signals['node-modified-inview'])
-        shouldbe = self.blue_nodes + 1
-        total = self.red_nodes + self.blue_nodes + self.green_nodes
-        #Testing that the blue node count has increased
-        self.assertEqual(total+1,view.get_n_nodes())
-        self.assertEqual(shouldbe,view.get_n_nodes(withfilters=['blue']))
-        #also comparing with another view
-        self.assertEqual(total+1,self.view.get_n_nodes())
-        self.assertEqual(shouldbe,self.view.get_n_nodes(withfilters=['blue']))
-        self.tree.del_node('temp')
-        #Testing that it goes back to normal
-        self.assertEqual(total,view.get_n_nodes())
-        self.assertEqual(self.blue_nodes,view.get_n_nodes(withfilters=['blue']))
-        #also comparing with another view
-        self.assertEqual(total,self.view.get_n_nodes())
-        self.assertEqual(self.blue_nodes,self.view.get_n_nodes(withfilters=['blue']))
-        self.tester.test_validity()
-        
-    def test_modifying_node(self):
-        """ Modifying a node and see if the change is reflected in filters """
-        viewblue = self.tree.get_viewtree(refresh=False)
-        testblue = TreeTester(viewblue)
-        viewblue.apply_filter('blue')
-        viewred = self.tree.get_viewtree(refresh=False)
-        testred = TreeTester(viewred)
-        viewred.apply_filter('red')
-        node = DummyNode('temp')
-        node.add_color('blue')
-        #Do you see : we are modifying a child
-        self.assertSignal(self.view, \
-                          'node-modified-inview', \
-                          self.tree.add_node, 1)(node,parent_id='0')
-        self.assertTrue(('0',('0', )) in self.recorded_signals['node-modified-inview'])
-        #Node is blue
-        self.assertTrue(viewblue.is_displayed('temp'))
-        self.assertFalse(viewred.is_displayed('temp'))
-        #node is blue and red
-        node.add_color('red')
-        self.assertTrue(viewblue.is_displayed('temp'))
-        self.assertTrue(viewred.is_displayed('temp'))
-        #node is red only
-        node.remove_color('blue')
-        self.assertFalse(viewblue.is_displayed('temp'))
-        self.assertTrue(viewred.is_displayed('temp'))
-        testred.test_validity()
-        testblue.test_validity()
-
-    def test_removing_parent(self):
-        """Test behavior of node when its parent goes away.
-
-        When you remove a parent, the child nodes should be added to
-        the root if they don't have any other parents.
-        """
-        view = self.tree.get_viewtree(refresh=True)
-        node = DummyNode('temp')
-        node.add_color('blue')
-        self.tree.add_node(node,parent_id='0')
-        all_nodes = self.view.get_all_nodes()
-        self.assertTrue('0' in all_nodes)
-        self.assertTrue('temp' in all_nodes)
-        self.assertSignal(self.view, \
-                          'node-deleted-inview', \
-                          self.tree.del_node, 1)('0')
-#        self.assertTrue(('0',(0, )) in self.recorded_signals['node-deleted-inview'])
-        all_nodes = self.view.get_all_nodes()
-        self.assertFalse('0' in all_nodes)
-        self.assertTrue('temp' in all_nodes)
-        
-    def test_adding_to_late_parent(self):
-        '''Add a node to a parent not yet in the tree
-        then add the parent later'''
-        view = self.tree.get_viewtree(refresh=True)
-        node = DummyNode('child')
-        self.tree.add_node(node,parent_id='futur')
-        all_nodes = view.get_all_nodes()
-        self.assertTrue('child' in all_nodes)
-        self.assertFalse('futur' in all_nodes)
-        self.assertEqual(len(view.node_parents('child')),0)
-        #now inserting the parent
-        node2 = DummyNode('futur')
-        self.tree.add_node(node2)
-        all_nodes = view.get_all_nodes()
-        self.assertTrue('child' in all_nodes)
-        self.assertTrue('futur' in all_nodes)
-        self.assertTrue('futur' in view.node_parents('child'))
-        #TODO the same test but with filters
-        
-    def test_adding_to_late_parent2(self):
-        '''Another tricky case with late parent. This was
-        a very rare but existing crash'''
-        view = self.tree.get_viewtree(refresh=True)
-        node = DummyNode('child')
-        self.tree.add_node(node)
-        self.assertEqual(len(view.node_parents('child')),0)
-        node2 = DummyNode('futur')
-        node.add_parent('futur')
-        node.modified()
-        self.assertEqual(len(view.node_parents('child')),0)
-        self.assertNotEqual(view.get_paths_for_node('child'),[(0,0)])
-        self.tree.add_node(node2)
-        self.assertTrue('futur' in view.node_parents('child'))
-        
-    def test_adding_to_late_parent3(self):
-        '''Another tricky case with late parent. This was
-        a very rare but existing crash'''
-        view = self.tree.get_viewtree(refresh=True)
-        view.apply_filter('red')
-        node = DummyNode('child')
-        node.add_color('red')
-        self.tree.add_node(node)
-        node2 = view.get_node('0')
-        node2.remove_color('red')
-        node.add_parent('0')
-        node.modified()
-        self.assertEqual(len(view.node_parents('child')),0)
-        self.assertNotEqual(view.get_paths_for_node('child'),[('0','child')])
-        node2.add_color('red')
-        self.assertTrue('0' in view.node_parents('child'))
-        
-    def test_adding_self_parent(self):
-        '''A node cannot be its own parent'''
-        view = self.tree.get_viewtree(refresh=True)
-        node = view.get_node('0')
-        node.add_parent('0')
-        self.assertEqual(len(node.get_parents()),0)
-        self.assertEqual(len(node.get_children()),0)
-        node.set_parent('0')
-        self.assertEqual(len(node.get_parents()),0)
-        self.assertEqual(len(node.get_children()),0)
-        node.add_child('0')
-        self.assertEqual(len(node.get_parents()),0)
-        self.assertEqual(len(node.get_children()),0)
-        
-        
-    def test_multiple_children(self):
-        '''We test a node with two children.'''
-        view = self.tree.get_viewtree(refresh=True)
-        node = DummyNode('child')
-        node2 = DummyNode('child2')
-        self.tree.add_node(node,parent_id='0')
-        self.tree.add_node(node2,parent_id='0')
-        #We first test that the childrens are both there.
-        self.assertEqual(view.node_n_children('0'),2)
-        self.assertEqual(view.next_node('child'),'child2')
-        #We build a list of children paths
-        paths = []
-        paths += view.get_paths_for_node('child')
-        paths += view.get_paths_for_node('child2')
-        #take the paths of the parent - let's call it (X,) "
-        roots = view.get_paths_for_node('0')
-        #Then, (X,0) and (X,1) should be both in paths of children
-        for r in roots:
-            p = r + ('child',)
-            self.assertTrue(p in paths)
-            p = r + ('child2',)
-            self.assertTrue(p in paths)
-            
-    def test_counting_children(self):
-        '''We test the number of children, recursively or not'''
-        view = self.tree.get_viewtree(refresh=True)
-        zero = self.tree.get_node('0')
-        zero.add_color('blue')
-        node = DummyNode('child')
-        node.add_color('blue')
-        node2 = DummyNode('child2')
-        self.assertEqual(view.node_n_children('0'),0)
-        self.tree.add_node(node,parent_id='0')
-        self.assertEqual(view.node_n_children('0'),1)
-        self.tree.add_node(node2,parent_id='0')
-        self.assertEqual(view.node_n_children('0'),2)
-        self.assertEqual(view.node_n_children('0',recursive=True),2)
-        node3 = DummyNode('child3')
-        node3.add_color('blue')
-        self.tree.add_node(node3,parent_id='child')
-        self.assertEqual(view.node_n_children('0'),2)
-        self.assertEqual(view.node_n_children('0',recursive=True),3)
-        node4 = DummyNode('child4')
-        self.tree.add_node(node4,parent_id='child3')
-        self.assertEqual(view.node_n_children('0'),2)
-        self.assertEqual(view.node_n_children('0',recursive=True),4)
-        self.assertEqual(view.node_n_children('child'),1)
-        self.assertEqual(view.node_n_children('child',recursive=True),2)
-        view.apply_filter('blue')
-        self.assertEqual(view.node_n_children('0'),1)
-        self.assertEqual(view.node_n_children('0',recursive=True),2)
-        self.assertEqual(view.node_n_children('child'),1)
-        self.assertEqual(view.node_n_children('child',recursive=True),1)
-        node5 = DummyNode('child5')
-        self.tree.add_node(node5,parent_id='child2')
-        self.tree.del_node('child4')
-        self.assertEqual(view.node_n_children('0'),1)
-        node2.add_color('blue')
-        self.assertEqual(view.node_n_children('0',recursive=True),3)
-        view.unapply_filter('blue')
-        self.assertEqual(view.node_n_children('0'),2)
-        self.assertEqual(view.node_n_children('0',recursive=True),4)
-        self.tree.del_node('child3')
-        self.assertEqual(view.node_n_children('0'),2)
-        self.assertEqual(view.node_n_children('0',recursive=True),3)
-        
-            
-    def test_clean_multiple_parents(self):
-        view = self.tree.get_viewtree(refresh=True)
-        node = DummyNode('child')
-        node2 = DummyNode('child2')
-        self.tree.add_node(node,parent_id='0')
-        self.tree.add_node(node2,parent_id='child')
-        node.add_parent('1')
-        node2.add_parent('1')
-        self.assertEqual(len(view.node_parents('child')),2)
-        view.apply_filter('blue')
-
-    def test_adding_to_late_parent_with_leaf_filter(self):
-        '''Add a node to a parent not yet in the tree
-        then add the parent later'''
-        view = self.tree.get_viewtree(refresh=True)
-        node = DummyNode('child')
-        self.tree.add_node(node,parent_id='futur')
-        all_nodes = view.get_all_nodes()
-        self.assertTrue('child' in all_nodes)
-        self.assertFalse('futur' in all_nodes)
-        self.assertEqual(len(view.node_parents('child')),0)
-        #now inserting the parent
-        view.apply_filter('leaf')
-        node2 = DummyNode('futur')
-        self.tree.add_node(node2)
-        all_nodes = view.get_all_nodes()
-        self.assertTrue('child' in all_nodes)
-        self.assertFalse('futur' in all_nodes)
-        self.assertFalse('futur' in view.node_parents('child'))
-        view.reset_filters()
-        self.assertTrue(view.is_displayed('futur'))
-        self.assertTrue('futur' in view.node_parents('child'))
-
-    def test_updating_parent(self):
-        node = DummyNode('child')
-        node.add_color('red')
-        self.tree.add_node(node,parent_id='0')
-        view = self.tree.get_viewtree(refresh=False)
-        view.apply_filter('red')
-        self.assertEqual(view.node_parents('child'),['0'])
-        path0 = view.get_paths_for_node('0')[0]
-        pathchild = path0 + ('child',)
-        self.assertEqual(view.get_paths_for_node('child'),[pathchild])
-        node0 = view.get_node('0')
-        node0.add_color('blue')
-        self.assertEqual(view.node_parents('child'),['0'])
-        self.assertEqual(view.get_paths_for_node('child'),[pathchild])
-        node0.remove_color('red')
-        self.assertEqual(view.node_parents('child'),[])
-        self.assertEqual(view.get_paths_for_node('child'),[('child',)])
-        node0.add_color('red')
-        path0 = view.get_paths_for_node('0')[0]
-        pathchild = path0 + ('child',)
-        self.assertEqual(view.node_parents('child'),['0'])
-        self.assertEqual(view.get_paths_for_node('child'),[pathchild])
-        
-    def test_addchild_with_late_parent(self):
-        '''Add a child to a node which is not yet in the tree. 
-        We also check with a callback that the path sent is well
-        corresponding to the nid received.
-        '''
-        def check_path(nid,path):
-            realnode = view.get_node_for_path(path)
-#            self.assertEqual(nid,realnode)
-        def printtree(tid,paths=None):
-            treestr = ' '
-            #The printtree method returns an error when the printed tree
-            #is not logical. Thus, by connecting a print tree to signals,
-            #the test will fail if there's any inconsistencies.
-            view.print_tree(string=True)
-        view = self.tree.get_viewtree(refresh=True)
-        view.register_cllbck('node-modified-inview',check_path)
-        view.register_cllbck('node-deleted-inview',printtree)
-        node = DummyNode('child')
-        node2 = DummyNode('futur')
-        node3 = DummyNode('child2')
-        node2.add_child('child')
-        node2.add_child('child2')
-        self.tree.add_node(node)
-        self.tree.add_node(node3)
-        all_nodes = view.get_all_nodes()
-        self.assertTrue('child' in all_nodes)
-        self.assertTrue('child2' in all_nodes)
-        self.assertFalse('futur' in all_nodes)
-        self.assertEqual(len(view.node_parents('child')),0)
-        self.assertEqual(len(view.node_parents('child2')),0)
-        #now inserting the parent
-        view.apply_filter('leaf')
-        self.tree.add_node(node2)
-        all_nodes = view.get_all_nodes()
-        self.assertTrue('child' in all_nodes)
-        self.assertTrue('child2' in all_nodes)
-        self.assertFalse('futur' in all_nodes)
-        self.assertFalse('futur' in view.node_parents('child'))
-        self.assertFalse('futur' in view.node_parents('child2'))
-        view.reset_filters()
-        self.assertTrue(view.is_displayed('futur'))
-        self.assertTrue('futur' in view.node_parents('child'))
-        self.assertTrue('futur' in view.node_parents('child2'))
-        
-    def test_addparent_with_late_child(self):
-        '''Add a child not yet in the tree to a node'''
-        view = self.tree.get_viewtree(refresh=True)
-        node = DummyNode('parent')
-        node2 = DummyNode('futur')
-        node.add_child('futur')
-        self.tree.add_node(node)
-        all_nodes = view.get_all_nodes()
-        self.assertTrue('parent' in all_nodes)
-        self.assertFalse('futur' in all_nodes)
-        self.assertEqual(view.node_n_children('parent'),0)
-        #now inserting the parent
-        view.apply_filter('leaf')
-        self.tree.add_node(node2)
-        all_nodes = view.get_all_nodes()
-        self.assertTrue('futur' in all_nodes)
-        self.assertFalse('parent' in all_nodes)
-        self.assertFalse('parent' in view.node_parents('futur'))
-        view.reset_filters()
-        self.assertTrue(view.is_displayed('parent'))
-        self.assertTrue('futur' in view.node_all_children('parent'))
-        
-    def test_more_late_child(self):
-        '''This one is trickier. We add a node with some children.
-        Then, we add later a new child between the existing children.
-        '''
-        view = self.tree.get_viewtree(refresh=True)
-        node = DummyNode('parent')
-        node1 = DummyNode('futur1')
-        node2 = DummyNode('futur2')
-        node3 = DummyNode('futur3')
-        node4 = DummyNode('futur4')
-        node.add_child('futur1')
-        node.add_child('futur2')
-        node.add_child('futur3')
-        node.add_child('futur4')
-        self.tree.add_node(node)
-        self.tree.add_node(node1)
-        #look, we miss the node 2 !
-        self.tree.add_node(node3)
-        self.tree.add_node(node4)
-        self.assertEqual(view.node_n_children('parent'),3)
-        self.tree.add_node(node2)
-        self.assertEqual(view.node_n_children('parent'),4)
-        
-    def test_late_first_child(self):
-        '''Futur2 is the child of parent
-           Futur1 is both the child of parent and futur2
-           Futur1 will be added later, forcing a reorganization.
-        '''
-        view = self.tree.get_viewtree(refresh=True)
-        node = DummyNode('parent')
-        node1 = DummyNode('futur1')
-        node2 = DummyNode('futur2')
-        node.add_child('futur1')
-        node.add_child('futur2')
-        node2.add_child('futur1')
-        self.tree.add_node(node)
-        self.tree.add_node(node2)
-        #Look, we didn't add futur1
-        self.assertEqual(view.node_n_children('parent'),1)
-        self.assertEqual(view.node_n_children('futur2'),0)
-        self.assertFalse(view.is_displayed('futur1'))
-        #Now we add it !
-        self.tree.add_node(node1)
-        self.assertEqual(view.node_n_children('parent'),2)
-        self.assertEqual(view.node_n_children('futur2'),1)
-        self.assertTrue(view.is_displayed('futur1'))
-        
-    def test_move_node_to_a_multiple_parent(self):
-        view = self.tree.get_viewtree(refresh=True)
-        node = self.tree.get_node('13')
-        node3 = self.tree.get_node('3')
-        node.add_parent('9')
-        node.add_parent('10')
-        self.tree.del_node('3')
-        self.assertFalse(self.tree.has_node('3'))
-        self.tree.add_node(node3,parent_id='13')
-        self.assertEqual(len(view.get_paths_for_node('3')),3)
-        self.tree.del_node('3')
-        self.tree.move_node('4','13')
-        self.assertEqual(len(view.get_paths_for_node('4')),3)
-        
-    def test_recursive_removing_parent(self):
-        """Test behavior of node when its parent goes away.
-
-        When you remove a parent recursively, all the children
-        are also removed !
-        """
-        view = self.tree.get_viewtree(refresh=True)
-        node = DummyNode('temp')
-        node.add_color('blue')
-        self.tree.add_node(node,parent_id='0')
-        all_nodes = self.view.get_all_nodes()
-        self.assertTrue('0' in all_nodes)
-        self.assertTrue('temp' in all_nodes)
-        self.assertSignal(self.view, \
-                          'node-deleted-inview', \
-                          self.tree.del_node, 1)('0', recursive = True)
-        self.assertTrue(('temp',('0', 'temp')) in\
-                                 self.recorded_signals['node-deleted-inview'])
-        all_nodes = self.view.get_all_nodes()
-        self.assertFalse('0' in all_nodes)
-        self.assertFalse('temp' in all_nodes)
-
-    def test_move_node(self):
-        """Test node movement from parents.
-
-        Check that node can be moved from one node to another,
-        and to root.  When moved to root, verify it has no parents.
-        """
-        view = self.tree.get_viewtree(refresh=True)
-        node = DummyNode('temp')
-        node.add_color('blue')
-        self.tree.add_node(node,parent_id='0')
-        #Testing initial situation
-        self.assertTrue(view.node_has_child('0'))
-        self.assertTrue('temp' in view.node_all_children('0'))
-        self.assertTrue('temp' not in view.node_all_children('1'))
-
-        #Moving node
-        self.assertSignal(self.view, \
-                          'node-modified-inview', \
-                          self.tree.move_node, 2)('temp','1')
-#        self.assertTrue(('0',(0,)) in self.recorded_signals['node-modified-inview'])
-        self.assertTrue(('1',('1',)) in self.recorded_signals['node-modified-inview'])
-        self.assertTrue(view.node_has_child('1'))
-        self.assertTrue('temp' in view.node_all_children('1'))
-        self.assertTrue('temp' not in view.node_all_children('0'))
-        #Now moving to root
-        self.tree.move_node('temp')
-        self.assertTrue('temp' not in view.node_all_children('1'))
-        self.assertTrue('temp' not in view.node_all_children('0'))
-        #temp still exist and doesn't have any parents
-        all_nodes = self.mainview.get_all_nodes()
-        self.assertTrue('temp' in all_nodes)
-        self.assertEqual(0,len(self.mainview.node_parents('temp')))
-
-    def test_add_parent(self):
-        """Test that a node can have two parents.
-
-        Verify that when a node with a parent gets a second parent, 
-        the node can be found in both parent nodes.
-        """
-        view = self.tree.get_viewtree(refresh = True)
-        node = DummyNode('temp')
-        node.add_color('blue')
-        self.assertSignal(self.view, \
-                          'node-modified-inview', \
-                          self.tree.add_node, 1)(node, parent_id = '0')
-        #Not checking temp. Indeed, it has been added, so there should not 
-        #be any modified signal
-        self.assertTrue(('0',('0',)) in self.recorded_signals['node-modified-inview'])
-        #Testing initial situation
-        self.assertTrue(view.node_has_child('0'))
-        self.assertTrue('temp' in view.node_all_children('0'))
-        self.assertTrue('temp' not in view.node_all_children('1'))
-        #Adding another parent
-        self.assertSignal(self.view, \
-                          'node-modified-inview', \
-                          self.tree.add_parent, 1)('temp','1')
-        self.assertTrue(('1',('1',)) in self.recorded_signals['node-modified-inview'])
-        self.assertTrue(view.node_has_child('1'))
-        self.assertTrue('temp' in view.node_all_children('1'))
-        self.assertTrue('temp' in view.node_all_children('0'))
-    
-    #we try to add a task as a child of one of its grand-children.
-    #Nothing should happen
-
-    def test_cyclic_paradox(self):
-        """Try to add a node as a child of one of its grand-children."""
-        view = self.tree.get_main_view()
-        node = DummyNode('temp')
-        node.add_color('blue')
-        self.tree.add_node(node,parent_id='0')
-        self.tree.add_parent('0','1')
-        self.assertTrue('1' in self.mainview.node_parents('0'))
-        self.assertTrue('0' in self.mainview.node_parents('temp'))
-        #direct circular relationship
-        self.assertRaises(Exception,self.tree.add_parent,'0','temp')
-        #More complex circular relationship
-        self.assertRaises(Exception,self.tree.add_parent,'1','temp')
-        # And then printing => if it stops, nothing ciruclar stays there
-        view.print_tree(True)
-        
-    def test_mainview(self):
-        """Verify mainview behavior
-
-        Test that mainview is always up-to-date and raise exception when
-        trying to add filters on it
-        """
-        self.assertRaises(Exception,self.mainview.apply_filter,'blue')
-        
-    #### Testing each method of the ViewTree
-    
-    ### Testing each method of the TreeView
-    def test_viewtree_get_n_nodes(self):
-        """ Test get_n_nodes() method of TreeView
-
-        Check that retrieving counts of nodes with various filters returns
-        the expected collections.
-        """
-        total = self.red_nodes + self.blue_nodes + self.green_nodes
-        self.assertEqual(total,self.view.get_n_nodes())
-        self.assertEqual(self.green_nodes,self.view.get_n_nodes(withfilters=['green']))
-        self.assertEqual(total,self.mainview.get_n_nodes())
-        
-    def test_viewtree_get_n_nodes_with_cache(self):
-        '''Testing the cache of the get_n_nodes'''
-        nbr = self.green_nodes
-        self.assertEqual(nbr,self.mainview.get_n_nodes(\
-                            withfilters=['green'],include_transparent=False))
-        node = self.tree.get_node('0')
-        node.add_color('green')
-        
-        self.assertEqual(nbr+1,self.mainview.get_n_nodes(\
-                            withfilters=['green'],include_transparent=False))
-        node.remove_color('green')
-        self.assertEqual(nbr,self.mainview.get_n_nodes(\
-                            withfilters=['green'],include_transparent=False))
-    
-    def test_viewtree_get_all_nodes(self):
-        all_nodes = self.view.get_all_nodes()
-        all_nodes2 = self.mainview.get_all_nodes()
-        self.assertEqual(True,'0' in all_nodes)
-        self.assertEqual(False,'tmp' in all_nodes)
-        self.assertEqual(self.total,len(all_nodes))
-        #Mainview
-        self.assertEqual(True,'0' in all_nodes2)
-        self.assertEqual(False,'tmp' in all_nodes2)
-        self.assertEqual(self.total,len(all_nodes2))
-        #adding a node
-        node = DummyNode('temp')
-        node.add_color('blue')
-        self.tree.add_node(node,parent_id=str(0))
-        all_nodes = self.view.get_all_nodes()
-        all_nodes2 = self.mainview.get_all_nodes()
-        self.assertTrue('0' in all_nodes)
-        self.assertTrue('temp' in all_nodes)
-        self.assertEqual(self.total+1,len(all_nodes))
-        #Mainview
-        self.assertTrue('0' in all_nodes2)
-        self.assertTrue('temp' in all_nodes2)
-        self.assertEqual(self.total+1,len(all_nodes2))
-        #Removing the node
-        self.tree.del_node('1')
-        all_nodes = self.view.get_all_nodes()
-        all_nodes2 = self.mainview.get_all_nodes()
-        self.assertFalse('1' in all_nodes)
-        self.assertTrue('temp' in all_nodes)
-        self.assertEqual(self.total,len(all_nodes))
-        #mainview
-        self.assertFalse('1' in all_nodes2)
-        self.assertTrue('temp' in all_nodes2)
-        self.assertEqual(self.total,len(all_nodes2))
-        
-        
-    def test_viewtree_get_node_for_path(self):
-        view = self.tree.get_viewtree(refresh=True)
-        #nid1 and nid2 are not always the same
-        nid1 = view.get_node_for_path(('0',))
-        nid2 = self.mainview.get_node_for_path(('0',))
-        self.assertTrue(nid1 != None)
-        self.assertTrue(nid2 != None)
-        #Thus we do a mix of test.
-        nid1b = view.next_node(nid1)
-        path1b = view.get_paths_for_node(nid1b)
-        self.assertEqual([(nid1b,)],path1b)
-        #same for mainview
-        nid2b = self.mainview.next_node(nid2)
-        path2b = self.mainview.get_paths_for_node(nid2b)
-        self.assertEqual([(nid2b,)],path2b)
-        #with children
-        node = DummyNode('temp')
-        node.add_color('blue')
-        self.tree.add_node(node,parent_id=nid1)
-        self.tree.add_parent('temp',nid2)
-        self.assertEqual('temp',self.mainview.get_node_for_path((nid1,'temp')))
-        self.assertEqual('temp',view.get_node_for_path((nid2,'temp')))
-        #Adding a child to the child
-        node2 = DummyNode('temp2')
-        node2.add_color('blue')
-        self.tree.add_node(node2,parent_id=nid1)
-        node = DummyNode('temp_child')
-        node.add_color('blue')
-        self.tree.add_node(node,parent_id='temp2')
-        self.assertEqual('temp_child',view.get_node_for_path((nid1,'temp2','temp_child')))
-        self.tree.add_parent('temp2',nid2)
-        self.assertEqual('temp_child',self.mainview.get_node_for_path((nid2,'temp2','temp_child')))
-        #with filters
-        view.apply_filter('blue')
-        pl = view.get_paths_for_node('temp2')
-        for p in pl:
-            pp = p + ('temp_child',)
-            self.assertEqual('temp_child',view.get_node_for_path(pp))
-        
-    def test_viewtree_get_paths_for_node(self):
-        view = self.tree.get_viewtree(refresh=True)
-        #testing the root path
-        self.assertEqual([()],view.get_paths_for_node())
-        self.assertEqual([()],self.mainview.get_paths_for_node())
-        #with children
-        #the first blue node is:
-        firstgreen = self.red_nodes + self.blue_nodes - 1
-        pp = view.get_paths_for_node(str(firstgreen))[0]
-        i = 0
-        #Testing all the green nodes (that are in stairs)
-        while i < self.green_nodes:
-            returned = view.get_paths_for_node(str(firstgreen+i))[0]
-            self.assertEqual(pp,returned)
-            i+=1
-            pp += (str(firstgreen+i),)
-        #with filters
-        view.apply_filter('green')
-        pp = view.get_paths_for_node(str(firstgreen+1))[0]
-        i = 1
-        #Testing all the green nodes (that are in stairs)
-        while i < self.green_nodes:
-            returned = view.get_paths_for_node(str(firstgreen+i))[0]
-            self.assertEqual(pp,returned)
-            i+=1
-            pp += (str(firstgreen+i),)
-        
-    def test_viewtree_next_node(self):
-        view = self.tree.get_viewtree(refresh=True)
-        """Test next_node() for TreeView.
-
-        Add two nodes to a parent, then verify various ways of looking
-        at the next node in the parent's list.
-        """
-        node = DummyNode('temp')
-        node.add_color('blue')
-        node.add_color('green')
-        self.tree.add_node(node,parent_id='0')
-        view = self.tree.get_viewtree(refresh=True)
-        node = DummyNode('temp2')
-        node.add_color('red')
-        self.tree.add_node(node,parent_id='0')
-        #we give the pid
-        self.assertEqual('temp2',view.next_node('temp',pid='0'))
-        self.assertEqual('temp2',self.mainview.next_node('temp',pid='0'))
-        #or we give not (should be the same here because only one parent)
-        self.assertEqual('temp2',view.next_node('temp'))
-        self.assertEqual('temp2',self.mainview.next_node('temp'))
-        #next node for last node.
-        self.assertEqual(None,view.next_node('temp2'))
-        self.assertEqual(None,self.mainview.next_node('temp2'))
-        #with filters, temp should not have any next node
-        view.apply_filter('blue',refresh=False)
-        view.apply_filter('green')
-        self.assertEqual(None,view.next_node('temp'))
-
-    def test_viewtree_node_has_child(self):
-        view = self.tree.get_viewtree(refresh=True)
-        """Test node_has_child() for TreeView
-
-        Verify that TreeView's node_n_children()'s return changes after
-        a node is added to an empty TreeView instance.
-        """
-        node = DummyNode('temp')
-        node.add_color('blue')
-        self.assertFalse(view.node_has_child('0'))
-        self.assertFalse(self.mainview.node_has_child('0'))
-        #Adding the node to the tree
-        self.tree.add_node(node,parent_id='0')
-        self.assertTrue(view.node_has_child('0'))
-        self.assertTrue(self.mainview.node_has_child('0'))
-        
-    def test_moving_to_future_parent(self):
-        view = self.tree.get_viewtree(refresh=True)
-        node = DummyNode('future_par')
-        node2 = DummyNode('child')
-        self.tree.add_node(node2,parent_id='0')
-        self.assertTrue('child' in view.node_all_children('0'))
-        node2.set_parent('future_par')
-        self.assertFalse('child' in view.node_all_children('0'))
-        self.assertFalse(node2.has_parent())
-        self.tree.add_node(node)
-        self.assertTrue('child' in view.node_all_children('future_par'))
-        self.assertTrue(node2.has_parent())
-    
-    def test_viewtree_node_all_children(self):
-        view = self.tree.get_viewtree(refresh=True)
-        self.assertEqual(0,len(view.node_all_children('0')))
-        """Test node_all_children() for TreeView.
-
-        We also test node_n_children here. Nearly the same method.
-        """
-        #checking that 0 and 1 are in root
-        self.assertTrue('0' in view.node_all_children())
-        self.assertTrue('1' in view.node_all_children())
-        self.assertTrue('0' in self.mainview.node_all_children())
-        self.assertTrue('1' in self.mainview.node_all_children())
-        node = DummyNode('temp')
-        node.add_color('blue')
-        #adding a new children
-        self.tree.add_node(node,parent_id='0')
-        self.assertEqual(1,view.node_n_children('0'))
-        self.assertTrue('temp' in view.node_all_children('0'))
-        self.assertEqual(1,self.mainview.node_n_children('0'))
-        self.assertTrue('temp' in self.mainview.node_all_children('0'))
-        #Testing with a filter
-        view.apply_filter('red')
-        self.assertFalse('temp' in view.node_all_children('0'))
-        view.unapply_filter('red')
-        #moving an existing children
-        self.tree.move_node('1','0')
-        self.assertEqual(2,view.node_n_children('0'))
-        self.assertTrue('1' in view.node_all_children('0'))
-        self.assertFalse('1' in view.node_all_children())
-        self.assertEqual(2,self.mainview.node_n_children('0'))
-        self.assertTrue('1' in self.mainview.node_all_children('0'))
-        self.assertFalse('1' in self.mainview.node_all_children())
-        #removing a node
-        self.tree.del_node('temp')
-        self.assertEqual(1,view.node_n_children('0'))
-        self.assertFalse('temp' in view.node_all_children('0'))
-        self.assertEqual(1,self.mainview.node_n_children('0'))
-        self.assertFalse('temp' in self.mainview.node_all_children('0'))
-        #moving a node elsewhere
-        self.tree.move_node('1')
-        self.assertEqual(0,view.node_n_children('0'))
-        self.assertFalse('1' in view.node_all_children('0'))
-        self.assertEqual(0,self.mainview.node_n_children('0'))
-        self.assertFalse('1' in self.mainview.node_all_children('0'))
-        #checking that '1' is back in root
-        self.assertTrue('1' in view.node_all_children())
-        self.assertTrue('1' in self.mainview.node_all_children())
-        
-    def test_viewtree_node_nth_child(self):
-        """Test node_nth_child() for TreeView.
-
-        Verify that when retrieving a given child node, that it is
-        returned, except when requesting a node not in the tree or that
-        is not present due being filtered out.
-        """
-        view = self.tree.get_viewtree(refresh=True)
-        node = DummyNode('temp')
-        node.add_color('blue')
-        #Asking for a child that doesn't exist should raise an exception
-        self.assertRaises(ValueError,view.node_nth_child,'0',0)
-        self.assertRaises(ValueError,self.mainview.node_nth_child,'0',0)
-        #Adding the node to the tree
-        self.tree.add_node(node,parent_id='0')
-        self.assertEqual('temp',view.node_nth_child('0',0))
-        self.assertEqual('temp',self.mainview.node_nth_child('0',0))
-        #Now with a filter
-        view.apply_filter('red')
-        self.assertRaises(ValueError,view.node_nth_child,'0',0)
-        
-        
-    def test_viewtree_node_parents(self):
-        view = self.tree.get_viewtree(refresh=True)
-        """Test node_parents() for TreeView.
-
-        Verify that a node's parents can be retrieved, if it has any.
-        Check that if a node has multiple parents, that both parents are
-        returned.
-        """
-        #Checking that a node at the root has no parents
-        self.assertEqual([],view.node_parents('0'))
-        self.assertEqual([],self.mainview.node_parents('0'))
-        #Adding a child
-        node = DummyNode('temp')
-        node.add_color('blue')
-        self.tree.add_node(node,parent_id='0')
-        self.assertEqual(['0'],view.node_parents('temp'))
-        self.assertEqual(['0'],self.mainview.node_parents('temp'))
-        #adding a second node.add_child('0')parent
-        self.tree.add_parent('temp','1')
-        self.assertEqual(['0','1'],view.node_parents('temp'))
-        self.assertEqual(['0','1'],self.mainview.node_parents('temp'))
-        #now with a filter
-        view.apply_filter('blue')
-        self.assertEqual([],view.node_parents('temp'))
-        #if the node is not displayed, asking for parents will raise an error
-        view.unapply_filter('blue')
-        view.apply_filter('red')
-        self.assertRaises(IndexError,view.node_parents,'temp')
-        
-
-    def test_viewtree_is_displayed(self):
-        view = self.tree.get_viewtree(refresh=True)
-        """Test is_displayed() for TreeView.
-
-        Verify that a node is shown as displayed once it's been added
-        to the tree, but not if an active filter should be hiding it.
-        """
-        node = DummyNode('temp')
-        node.add_color('blue')
-        self.assertFalse(view.is_displayed('temp'))
-        self.assertFalse(self.mainview.is_displayed('temp'))
-        #Adding the node to the tree
-        self.tree.add_node(node,parent_id='0')
-        self.assertTrue(view.is_displayed('temp'))
-        self.assertTrue(self.mainview.is_displayed('temp'))
-        view.apply_filter('blue')
-        self.assertTrue(view.is_displayed('temp'))
-        view.apply_filter('red')
-        self.assertFalse(view.is_displayed('temp'))
-
-
-
-
-
-############ Filters
-
-    def test_simple_filter(self):
-        view = self.tree.get_viewtree(refresh=False)
-        test = TreeTester(view)
-        """Test use of filters to restrict nodes shown.
-
-        When the 'red' filter is applied, only nodes with the 'red' color
-        should be returned.  Applying the 'blue' filter on top of that should
-        result in no nodes, since there are no nodes with both 'red' and 'blue'.
-
-        When two filters are applied, and the second one is removed, the
-        result should be the same as if only the first one had been applied.
-
-        When a node gains a color, check that it is filtered appropriately.
-
-        When a displayed node is added to a non-displayed parent, it
-        should still be displayed.
-        """
-        view.apply_filter('red')
-        test.test_validity()
-        self.assertEqual(self.red_nodes,view.get_n_nodes())
-        self.assertEqual(self.red_nodes,view.get_n_nodes(withfilters=['red']))
-        self.assertEqual(0,view.get_n_nodes(withfilters=['blue']))
-        #Red nodes are all at the root
-        self.assertEqual(self.red_nodes,view.node_n_children())
-        #applying another filter
-        view.apply_filter('green')
-        test.test_validity()
-        self.assertEqual(0,view.get_n_nodes())
-        #unapplying the first filter
-        view.unapply_filter('red')
-        test.test_validity()
-        self.assertEqual(self.green_nodes,view.get_n_nodes())
-        self.assertEqual(self.green_nodes,view.get_n_nodes(withfilters=['green']))
-        self.assertEqual(0,view.get_n_nodes(withfilters=['red']))
-        #There's only one green node at the root
-        self.assertEqual(1,view.node_n_children())
-        #Modifying a node to make it red and green
-        self.assertFalse(view.is_displayed('0'))
-        node = view.get_node('0')
-        node.add_color('green')
-        #It should now be in the view
-        self.assertTrue(view.is_displayed('0'))
-        self.assertEqual(1,view.get_n_nodes(withfilters=['red']))
-        self.assertEqual(2,view.node_n_children())
-        #Now, we add a new node
-        node = DummyNode('temp')
-        node.add_color('green')
-        self.tree.add_node(node)
-        test.test_validity()
-        #It should now be in the view
-        self.assertTrue(view.is_displayed('temp'))
-        self.assertEqual(3,view.node_n_children())
-        #We remove it
-        self.tree.del_node('temp')
-        test.test_validity()
-        self.assertFalse(view.is_displayed('temp'))
-        self.assertEqual(2,view.node_n_children())
-        #We add it again as a children of a non-displayed node
-        self.tree.add_node(node,parent_id='1')
-        test.test_validity()
-        self.assertTrue(view.is_displayed('temp'))
-        self.assertEqual(3,view.node_n_children())
-        #It should not have parent
-        self.assertEqual(0,len(view.node_parents('temp')))
-
-    def test_leaf_filter(self):
-        view = self.tree.get_viewtree(refresh=False)
-        test = TreeTester(view)
-        """Test filtering to show only the leaf nodes.
-
-        When the 'leaf' filter is applied and a child added to a node,
-        the parent node should not be present in the results.
-        """
-        view.apply_filter('leaf')
-        total = self.red_nodes + self.blue_nodes
-        self.assertEqual(total,view.get_n_nodes())
-        view.apply_filter('green')
-        self.assertEqual(1,view.get_n_nodes())
-        nid = view.get_node_for_path(('14',))
-        #Now, we add a new node
-        node = DummyNode('temp')
-        node.add_color('green')
-        self.tree.add_node(node,parent_id='14')
-        self.assertEqual(1,view.get_n_nodes())
-        nid = view.get_node_for_path(('temp',))
-        self.assertEqual('temp',nid)
-        test.test_validity()
-
-    #we copy/paste the test
-    def test_flatleaves_filters(self):
-        """We apply a leaves + flat filter and the result
-        should be the same as a simple leaf filter.
-        """
-        view = self.tree.get_viewtree(refresh=False)
-        test = TreeTester(view)
-        view.apply_filter('flatleaves')
-        total = self.red_nodes + self.blue_nodes
-        self.assertEqual(total,view.get_n_nodes())
-        view.apply_filter('green')
-        self.assertEqual(1,view.get_n_nodes())
-        nid = view.get_node_for_path(('14',))
-        #Now, we add a new node
-        node = DummyNode('temp')
-        node.add_color('green')
-        self.tree.add_node(node,parent_id=nid)
-        self.assertEqual(1,view.get_n_nodes())
-        nid = view.get_node_for_path(('temp',))
-        self.assertEqual('temp',nid)
-        test.test_validity()
-        
-    #green are stairs
-    #the flat filter should make them flat
-    def test_flat_filters(self):
-        """Test a flat filter.
-        
-        Green nodes are in "stairs" (each one being the child of another)
-        By applying a filter with the flat properties, we test that
-        all the nodes are now seen "flately".
-        """
-        view = self.tree.get_viewtree(refresh=False)
-        test = TreeTester(view)
-        view.apply_filter('flatgreen')
-        #all green nodes should be visibles
-        self.assertEqual(self.green_nodes,view.get_n_nodes())
-        i = 10
-        nodes = []
-        #we check that the paths are on the root
-        while i < self.green_nodes:
-            nid = view.get_node_for_path((str(i),))
-            view.print_tree()
-            nodes.append(nid)
-            self.assertFalse(nid == None)
-            #let see if a node has parent
-            self.assertFalse(view.node_has_parent(nid))
-            #and, of course, it cannot have children
-            self.assertFalse(view.node_has_child(nid))
-            i += 1
-        #we check that we have seen all the nodes
-        i = 10
-        while i <= self.green_nodes :
-            self.assertTrue(str(self.total-i) in nodes)
-            i += 1
-        test.test_validity()
-        
-    def test_transparent_filters(self):
-        view = self.tree.get_viewtree(refresh=False)
-        test = TreeTester(view)
-        """Test excluding transparent filters
-
-        Filters marked with the 'transparent' property should apply in get_n_nodes()
-        normally, but can be turned off via the include_transparent parameter.
-        """
-        view.apply_filter('transgreen')
-        self.assertEqual(self.green_nodes,view.get_n_nodes())
-        self.assertEqual(self.total,view.get_n_nodes(include_transparent=False))
-        #Now with filters in the counting
-        count1 = view.get_n_nodes(withfilters=['transblue'])
-        count2 = view.get_n_nodes(withfilters=['transblue'],\
-                                                    include_transparent=False)
-        self.assertEqual(0,count1)
-        self.assertEqual(self.blue_nodes,count2)
-        test.test_validity()
-
-    def test_view_signals(self):
-        view = self.tree.get_viewtree(refresh = True)
-        
-    def test_update_callback(self):
-        '''We test the update callbacks and we check that the path
-            received is well corresponding to the nid received'''
-        def check_path(nid,path):
-            self.assertEqual(view.get_node_for_path(path),nid)
-            self.assertTrue(path in view.get_paths_for_node(nid))
-        view = self.tree.get_viewtree(refresh=False)
-        test = TreeTester(view)
-        view.register_cllbck('node-modified-inview',check_path)
-        view.register_cllbck('node-added-inview',check_path)
-        view.apply_filter('leaf')
-        view.unapply_filter('leaf')
-        test.test_validity()
-        
-    def test_torture(self):
-        '''This is a torture test, where we will do whatever
-        we want in random order.
-        '''
-        view = self.tree.get_viewtree(refresh = False)
-        test = TreeTester(view)
-        view.reset_filters(refresh=True)
-        node = DummyNode('parent')
-        node.add_child('1')
-        node.add_child('3')
-        node.add_child('5')
-        node.add_child('7')
-        node.add_child('9')
-        node.add_child('11')
-        self.assertEqual(node.get_id(), "parent")
-        self.assertFalse(view.is_displayed('parent'))
-        self.tree.add_node(node)
-        test.test_validity()
-        self.assertEqual(view.node_n_children('parent'),6)
-        self.assertEqual(node.get_id(), "parent")
-        view.apply_filter('blue')
-        test.test_validity()
-        self.assertEqual(node.get_id(), "parent")
-        self.assertFalse(view.is_displayed('parent'))
-        node.add_color('blue')
-        test.test_validity()
-        self.assertTrue(view.is_displayed('parent'))
-        self.assertEqual(view.node_n_children('parent'),3)
-        
-    def test_copypasting_child(self):
-        view = self.tree.get_viewtree(refresh = False)
-        test = TreeTester(view)
-        view.apply_filter('green')
-        node = DummyNode('child')
-        node.add_color('green')
-        node1 = DummyNode('child2')
-        node1.add_color('green')
-        node2 = DummyNode('parent')
-        node2.add_color('green')
-        self.tree.add_node(node2)
-        self.tree.add_node(node,parent_id='10')
-        self.tree.add_node(node1,parent_id='10')
-        #We copy paste 'child' into 'parent'
-        node2.add_child('child')
-        test.test_validity()
-
-    def test_speed(self):
-        '''
-        Performance tests. Patches that reduce performance too much are not
-        acceptable
-        '''
-        self.tester.quit()
-        BIG_NUMBER = 1000
-        view = self.tree.get_viewtree(refresh = False)
-        nodes_id = []
-        start = time.time()
-        for index in xrange(BIG_NUMBER):
-            node = DummyNode("stress" + str(index))
-            nodes_id.append(node.get_id())
-            self.tree.add_node(node)
-        end = time.time()
-        print "\nADDING %d NODES: %f" % (BIG_NUMBER, end - start)
-
-        start = time.time()
-        for node_id in nodes_id:
-            self.tree.refresh_node(node_id)
-        end = time.time()
-        print "\nUPDATING %d NODES: %f" % (BIG_NUMBER, end - start)
-
-        start = time.time()
-        for node_id in nodes_id:
-            self.tree.del_node(node_id)
-        end = time.time()
-        print "\nDELETING %d NODES: %f" % (BIG_NUMBER, end - start)
-
-    def test_remove_grand_grand_parent(self):
-        """ Remove from tree a node which is parent of child 
-        which is also parent.
-
-        Using example tree from setUp()
-
-        root:
-             0
-             1
-             2
-             3
-             4
-             5
-             6
-             7
-             8
-             9 <- We want to remove this
-              10
-               11
-                12
-                 13
-                  14
-
-        The result should be
-        root:
-             1
-             2
-             3
-             4
-             5
-             6
-             7
-             8
-             10
-              11
-               12
-                13
-                 14
-        """
-
-        self.tree.del_node("9")
-
-        # Testing expected parents => (node, [parents])
-        relationships = [
-            (0,[]), (1,[]), (2,[]), (3,[]), (4,[]), (5,[]), (6,[]), (7,[]), (8,[]),
-            (10,[]), (11,[10]), (12,[11]), (13,[12]), (14,[13]),
-        ]
-
-        for node_id, parents in relationships:
-            # Convert IDs to strings
-            node_id = str(node_id)
-            parents = [str(parent) for parent in parents]
-
-            self.assertEqual(self.tree.get_node(node_id).get_parents(), parents)
-
-    def test_put_orphan_to_root(self):
-        """ Put orphan (a child of deleted parent) to root,
-        not to the parent of the parent
-
-        Using example tree from setUp()
-
-        root:
-             0
-             1
-             2
-             3
-             4
-             5
-             6
-             7
-             8
-             9
-              10
-               11
-                12
-                 13 <- we remove this
-                  14
-
-        The result should be
-        root:
-             0
-             1
-             2
-             3
-             4
-             5
-             6
-             7
-             8
-             10
-              11
-               12
-             14
-        """
-
-        self.tree.del_node("13")
-        orphan_node = self.tree.get_node("14")
-        self.assertEqual(orphan_node.get_parents(), [])
-
-    def test_delete_task_randomly(self):
-        """ Create a "big" number of tasks and delete them in "random" order.
-
-        Testability is done by having always the same seed for random number generator."""
-
-        # Fairly random number (Debian-like :-D)
-        SEED_NUMBER = 4
-        ADD_NODES_TO_TREE = 20
-        BASE_ID = 100
-
-        original_state = random.getstate()
-        random.seed(SEED_NUMBER)
-
-        view = self.tree.get_viewtree()
-        total_count = view.get_n_nodes()
-
-        parent_id = None
-        for i in range(ADD_NODES_TO_TREE):
-            node_id = str(BASE_ID + i)
-            node = TreeNode(node_id, parent_id)
-            self.tree.add_node(node)
-            parent_id = node_id
-
-        self.assertEqual(total_count + ADD_NODES_TO_TREE, view.get_n_nodes())
-
-        nodes = view.get_all_nodes()
-        random.shuffle(nodes)
-
-        for node_id in nodes:
-            self.tree.del_node(node_id)
-
-        random.setstate(original_state)
-
-    def test_add_existing_relationship(self):
-        """ Add the same relationship several times.
-
-        LibLarch should recognize that the relationship exists and do nothing. """
-
-        view = self.tree.get_viewtree()
-        count = view.get_n_nodes()
-
-        parent_id = "parent"
-        parent = DummyNode(parent_id)
-        parent.add_parent("12")
-        parent.add_parent("0")
-        self.tree.add_node(parent)
-        count += 1
-        self.assertEqual(count, view.get_n_nodes())
-
-        child_id = "child"
-        child = DummyNode(child_id)
-        self.tree.add_node(child)
-        count += 1
-
-        # A random number of iterations
-        for i in range(20):
-            child.add_parent(parent_id)
-
-            self.assertEqual(count, view.get_n_nodes())
-            self.assertEqual([parent_id], view.node_parents(child_id))
-            self.assertEqual([child_id], view.node_all_children(parent_id))
-            self.assertEqual(["0", "12"], sorted(view.node_parents(parent_id)))
-
-    def test_remove_parent_of_multiple_parent_task_child(self):
-        """ Remove one parent of multiple parent task child.
-
-        The child should stay where it is, not moved to root. """
-
-        view = self.tree.get_viewtree()
-
-        self.tree.add_node(DummyNode("t1"))
-        self.tree.add_node(DummyNode("t2"))
-
-        node = DummyNode("t3")
-        node.add_parent("t1")
-        self.tree.add_node(node)
-
-        node = DummyNode("t4")
-        node.add_parent("t3")
-        node.add_parent("t2")
-        self.tree.add_node(node)
-
-        node = DummyNode("t5")
-        node.add_parent("t4")
-        self.tree.add_node(node)
-
-        node = DummyNode("t6")
-        node.add_parent("t1")
-        self.tree.add_node(node)
-
-        self.assertEqual(["t3", "t6"], view.node_all_children("t1"))
-        self.assertEqual(["t4"], view.node_all_children("t2"))
-        self.assertEqual(["t3", "t2"], view.node_parents("t4"))
-        self.assertEqual(["t4"], view.node_parents("t5"))
-
-        self.tree.del_node("t3")
-
-        self.assertEqual(["t6"], view.node_all_children("t1"))
-        self.assertEqual(["t4"], view.node_all_children("t2"))
-        self.assertEqual(["t2"], view.node_parents("t4"))
-        self.assertEqual(["t4"], view.node_parents("t5"))
-
-    def test_remove_parent_of_multiple_children(self):
-        """ Remove parent of multiple immediate children.
-
-        This is very basic test but sometimes it fails. """
-        self.tree.add_node(DummyNode("A"))
-        self.tree.add_node(DummyNode("B"), parent_id="A")
-        self.tree.add_node(DummyNode("C"), parent_id="A")
-
-        self.tree.del_node("A")
-
-    def test_add_children_first(self):
-        """ Set children of a task first and only then add it tree.
-
-        This is the way the localfile backend works. """
-
-        CHILDREN_NUM = 6
-        children = ['%d@1' % i for i in range(1, CHILDREN_NUM+1)]
-        master_id = '0@1'
-
-        view = self.tree.get_main_view()
-        # We need to access root of the tree
-        tree_root = view.get_node('root')
-
-        # Clean tree first
-        for node_id in view.get_all_nodes():
-            self.tree.del_node(node_id)
-
-        self.assertEqual([], view.get_all_nodes())
-        self.assertEqual([], tree_root.get_children())
-
-        # Add master node with reference of children
-        master = DummyNode(master_id)
-        for child_id in children:
-            master.add_child(child_id)
-        self.tree.add_node(master)
-
-        # Now add children
-        for child_id in children:
-            self.tree.add_node(DummyNode(child_id))
-
-        # Check status
-        self.assertEqual([master_id] + children, sorted(view.get_all_nodes()))
-
-        # Master node
-        self.assertEqual([], view.node_parents(master_id))
-        self.assertEqual(children, view.node_all_children(master_id))
-
-        # Children
-        for node_id in children:
-            self.assertEqual([master_id], view.node_parents(node_id))
-            self.assertEqual([], view.node_all_children(node_id))
-
-        # Check root => there should be no nodes but master
-        self.assertEqual([master_id], tree_root.get_children())
-
-    def test_maintree_print_tree(self):
-        """ Test MainTree's print_tree() to string """
-        view = self.tree.get_main_view()
-        self.assertEqual(view.print_tree(True),
-"""root
- 0
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
-  10
-   11
-    12
-     13
-      14
-""")
-        self.tree.add_node(DummyNode('temp'), '0')
-        self.assertEqual(['temp'], view.node_all_children('0'))
-        self.assertEqual(view.print_tree(True),
-"""root
- 0
-  temp
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
-  10
-   11
-    12
-     13
-      14
-""")
-
-    def test_almost_circular_dependencies(self):
-        """ Have the nasty tree:
-        n1
-        -n2
-        -n3
-        --n2
-        """
-
-        a = DummyNode("a")
-        b = DummyNode("b")
-        c = DummyNode("c")
-
-        a.add_child("b")
-        a.add_child("c")
-        c.add_child("b")
-
-        self.tree.add_node(a)
-        self.tree.add_node(b)
-        self.tree.add_node(c)
-
-    def test_remove_tasks(self):
-        """ This test case is based on real code and a bug.
-        have node 'a' with children 'b', 'c' and then remove
-        'a' recursively. """
-        a = DummyNode("a")
-        b = DummyNode("b")
-        c = DummyNode("c")
-
-        a.add_child("b")
-        a.add_child("c")
-
-        self.tree.add_node(a)
-        self.tree.add_node(b)
-        self.tree.add_node(c)
-
-        for node_id in ['a', 'b', 'c']:
-            if self.tree.has_node(node_id):
-                self.tree.del_node(node_id, True)
-
-    def test_remove_recursively_clean(self):
-        """ Test that when we have task with many subtasks,
-        all will be removed and no will left in tree """
-        N = 50
-        prefix = "child_"
-
-        view = self.tree.get_main_view()
-
-        parent = DummyNode("parent")
-        self.tree.add_node(parent)
-        for i in range(N):
-            node_id = prefix + str(i)
-            self.tree.add_node(DummyNode(node_id))
-            parent.add_child(node_id)
-
-        self.tree.del_node("parent", True)
-
-        self.assertTrue("parent" not in view.get_all_nodes())
-        # No orphans are left
-        for node_id in view.get_all_nodes():
-            self.assertFalse(node_id.startswith(prefix))
-            
-    def test_queue_action_one_action(self):
-        self.testvalue = 0
-        def action(x):
-            self.testvalue += x
-        self.tree = Tree()
-        self.view = self.tree.get_viewtree()
-        self.tree.add_filter('blue',self.is_blue)
-        self.tree.add_filter('green',self.is_green)
-        self.view.apply_filter('green')
-        bl = DummyNode('bl')
-        bl.add_color('blue')
-        gr = DummyNode('gr')
-        gr.add_color('green')
-        self.view.queue_action('bl',action,1)
-        self.view.queue_action('gr',action,2)
-        self.assertEqual(self.testvalue,0)
-        self.tree.add_node(bl)
-        self.assertEqual(self.testvalue,0)
-        self.tree.add_node(gr)
-        self.assertEqual(self.testvalue,2)
-        
-    def test_queue_action_multiples_actions(self):
-        self.testvalue = 0
-        def action(x):
-            self.testvalue += x
-        self.tree = Tree()
-        self.view = self.tree.get_viewtree()
-        self.tree.add_filter('blue',self.is_blue)
-        self.tree.add_filter('green',self.is_green)
-        self.view.apply_filter('green')
-        bl = DummyNode('bl')
-        bl.add_color('blue')
-        gr = DummyNode('gr')
-        gr.add_color('green')
-        self.view.queue_action('bl',action,1)
-        self.view.queue_action('bl',action,3)
-        self.view.queue_action('gr',action,2)
-        self.assertEqual(self.testvalue,0)
-        self.tree.add_node(bl)
-        self.assertEqual(self.testvalue,0)
-        self.tree.add_node(gr)
-        self.assertEqual(self.testvalue,2)
-        self.view.unapply_filter('green')
-        #test value should be 2 + 1 + 3 = 6
-        self.assertEqual(self.testvalue,6)
-        
-        
-    def test_recursive_count(self):
-        self.value = 0
-        self.view = self.tree.get_viewtree()
-        def update(x,path):
-            if x == '0':
-                self.value = self.view.node_n_children(x,recursive=True)
-        self.view.register_cllbck('node-modified-inview',update)
-        a = DummyNode('a')
-        b = DummyNode('b')
-        c = DummyNode('c')
-        d = DummyNode('d')
-        d.add_color('blue')
-        zero = self.tree.get_node('0')
-        zero.add_color('blue')
-        self.view.flush()
-        self.assertEqual(self.value,0)
-        self.tree.add_node(a,'0')
-        self.view.flush()
-        self.assertEqual(self.value,1)
-        self.tree.add_node(b,'a')
-        self.view.flush()
-        self.assertEqual(self.value,2)
-        self.tree.add_node(c,'b')
-        self.view.flush()
-        self.assertEqual(self.value,3)
-        self.tree.add_node(d,'0')
-        self.view.flush()
-        self.assertEqual(self.value,4)
-        self.tree.del_node('b')
-        self.view.flush()
-        self.assertEqual(self.value,2)
-        self.view.apply_filter('blue')
-        self.view.flush()
-        self.assertEqual(self.value,1)     
-        
-
-def test_suite():
-    return unittest.TestLoader().loadTestsFromName(__name__)

=== removed directory 'GTG/tools/liblarch'
=== removed file 'GTG/tools/liblarch/__init__.py'
--- GTG/tools/liblarch/__init__.py	2012-02-06 18:17:12 +0000
+++ GTG/tools/liblarch/__init__.py	1970-01-01 00:00:00 +0000
@@ -1,397 +0,0 @@
-# -*- coding: utf-8 -*-
-# -----------------------------------------------------------------------------
-# Getting Things Gnome! - a personal organizer for the GNOME desktop
-# Copyright (c) 2008-2011- 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.
-#
-# 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/>.
-
-import functools
-
-from GTG.tools.liblarch.tree import MainTree
-from GTG.tools.liblarch.filteredtree import FilteredTree
-from GTG.tools.liblarch.filters_bank import FiltersBank
-
-class Tree:
-    """ A thin wrapper to MainTree that adds filtering capabilities.
-    It also provides a few methods to operate complex operation on the
-    MainTree (e.g, move_node) """ 
-
-    def __init__(self):
-        """ Creates MainTree which wraps and a main view without filters """
-        self.__tree = MainTree()
-        self.__fbank = FiltersBank(self.__tree)
-        self.views = {}
-        self.views['main'] = ViewTree(self, self.__tree, self.__fbank, static=True)
-
-##### HANDLE NODES ############################################################
-
-    def get_node(self, node_id):
-        """ Returns the object of node.
-        If the node does not exists, a ValueError is raised. """
-        return self.__tree.get_node(node_id)
-
-    def has_node(self, node_id):
-        """ Does the node exists in this tree? """
-        return self.__tree.has_node(node_id)
-
-    def add_node(self, node, parent_id=None, priority="low"):
-        """ Add a node to tree. If parent_id is set, put the node as a child of
-        this node, otherwise put it as a child of the root node."""
-        self.__tree.add_node(node, parent_id, priority)
-
-    def del_node(self, node_id, recursive=False):
-        """ Remove node from tree and return whether it was successful or not """
-        return self.__tree.remove_node(node_id, recursive)
-
-    def refresh_node(self, node_id, priority="low"):
-        """ Send a request for updating the node """
-        self.__tree.modify_node(node_id, priority)
-
-    def refresh_all(self):
-        """ Refresh all nodes """
-        self.__tree.refresh_all()
-
-    def move_node(self, node_id, new_parent_id=None):
-        """ Move the node to a new parent (dismissing all other parents)
-        use pid None to move it to the root """
-        if self.has_node(node_id):
-            node = self.get_node(node_id)
-            node.set_parent(new_parent_id)
-            toreturn = True
-        else:
-            toreturn = False
-
-        return toreturn
-
-
-    def add_parent(self, node_id, new_parent_id=None):
-        """ Add the node to a new parent. Return whether operation was
-        successful or not. If the node does not exists, return False """
-
-        if self.has_node(node_id):
-            node = self.get_node(node_id)
-            return node.add_parent(new_parent_id)
-        else:
-            return False
-
-##### VIEWS ###################################################################
-    def get_main_view(self):
-        """ Return the special view "main" which is without any filters on it."""
-        return self.views['main']
-
-    def get_viewtree(self, name=None, refresh=True):
-        """ Returns a viewtree by the name:
-          * a viewtree with that name exists => return it
-          * a viewtree with that name does not exist => create a new one and return it
-          * name is None => create an anonymous tree (do not remember it)
-
-        If refresh is False, the view is not initialized. This is useful as
-        an optimization if you plan to apply a filter.
-        """
-
-        if name is not None and self.views.has_key(name):
-            view_tree = self.views[name]
-        else:
-            view_tree = ViewTree(self,self.__tree,self.__fbank,refresh=refresh)
-            if name is not None:
-                self.views[name] = view_tree
-        return view_tree
-
-##### FILTERS ##################################################################
-    def list_filters(self):
-        """ Return a list of all available filters by name """
-        return self.__fbank.list_filters()
-
-    def add_filter(self, filter_name, filter_func, parameters=None):
-        """ Adds a filter to the filter bank.
-
-        @filter_name : name to give to the filter
-        @filter_func : the function that will filter the nodes
-        @parameters : some default parameters fot that filter
-        Return True if the filter was added
-        Return False if the filter_name was already in the bank
-        """
-        return self.__fbank.add_filter(filter_name, filter_func, parameters)
-
-    def remove_filter(self,filter_name):
-        """ Remove a filter from the bank. Only custom filters that were 
-        added here can be removed. Return False if the filter was not removed.
-        """
-        return self.__fbank.remove_filter(filter_name)
-
-# There should be two classes: for static and for dynamic mode
-# There are many conditions, and also we would prevent unallowed modes
-class ViewTree:
-    def __init__(self, maininterface, maintree, filters_bank,\
-                                             refresh = True, static = False):
-        """A ViewTree is the interface that should be used to display Tree(s).
-
-           In static mode, FilteredTree layer is not created. (There is no need)
-
-           We connect to MainTree or FilteredTree to get informed about changes.
-           If FilteredTree is used, it is connected to MainTree to handle changes
-           and then send id to ViewTree if it applies.
-
-           @param maintree: a Tree object, cointaining all the nodes
-           @param filters_bank: a FiltersBank object. Filters can be added
-                                dinamically to that.
-           @param refresh: if True, this ViewTree is automatically refreshed
-                           after applying a filter.
-           @param static: if True, this is the view of the complete maintree.
-                           Filters cannot be added to such a view.
-        """
-        self.maininterface = maininterface
-        self.__maintree = maintree
-        self.__cllbcks = {}
-        self.__fbank = filters_bank
-        self.static = static
-
-        if self.static:
-            self._tree = self.__maintree
-            self.__ft = None
-            self.__maintree.register_callback('node-added', \
-                        functools.partial(self.__emit, 'node-added'))
-            self.__maintree.register_callback('node-deleted', \
-                        functools.partial(self.__emit, 'node-deleted'))
-            self.__maintree.register_callback('node-modified', \
-                        functools.partial(self.__emit, 'node-modified'))
-        else:
-            self.__ft = FilteredTree(maintree, filters_bank, refresh = refresh)
-            self._tree = self.__ft
-            self.__ft.set_callback('added', \
-                        functools.partial(self.__emit, 'node-added-inview'))
-            self.__ft.set_callback('deleted', \
-                        functools.partial(self.__emit, 'node-deleted-inview'))
-            self.__ft.set_callback('modified', \
-                        functools.partial(self.__emit, 'node-modified-inview'))
-            self.__ft.set_callback('reordered', \
-                        functools.partial(self.__emit, 'node-children-reordered'))
-                        
-    def queue_action(self, node_id,func,param=None):
-        self.__ft.set_callback('runonce',func,node_id=node_id,param=param)
-        
-    #Ensure that there's no Async callbacks left. Should be only used for testing
-    def flush(self):
-        return self.__ft.flush()
-                        
-    def get_basetree(self):
-        """ Return Tree object """
-        return self.maininterface
-
-    def register_cllbck(self, event, func):
-        """ Store function and return unique key which can be used to
-        unregister the callback later """
-
-        if not self.__cllbcks.has_key(event):
-            self.__cllbcks[event] = {}
-
-        callbacks = self.__cllbcks[event]
-        key = 0
-        while callbacks.has_key(key):
-            key += 1
-
-        callbacks[key] = func
-        return key
-
-    def deregister_cllbck(self, event, key):
-        """ Remove the callback identifed by key (from register_cllbck) """
-        try:
-            del self.__cllbcks[event][key]
-        except KeyError:
-            pass
-        
-    def __emit(self, event, node_id, path=None, neworder=None):
-        """ Handle a new event from MainTree or FilteredTree
-        by passing it to other objects, e.g. TreeWidget """
-        callbacks = dict(self.__cllbcks.get(event, {}))
-#        print "ViewTree __emit for %s" %str(node_id)
-        for func in callbacks.itervalues():
-#            print "   -> func = %s - %s" %(func,str(path))
-            if neworder:
-                func(node_id, path, neworder)
-            else:
-                func(node_id,path)
-
-    def get_node(self, node_id):
-        """ Get a node from MainTree """
-        return self.__maintree.get_node(node_id)
-        
-    #FIXME Remove this method from public interface
-    def get_root(self):
-        return self.__maintree.get_root()
-
-    #FIXME Remove this method from public interface
-    def refresh_all(self):
-        self.__maintree.refresh_all()
-
-    def get_current_state(self):
-        """ Request current state to be send by signals/callbacks.
-
-        This allow LibLarch widget to connect on fly (e.g. after FilteredTree
-        is up and has some nodes). """
-
-        if self.static:
-            self.__maintree.refresh_all()
-        else:
-            self.__ft.get_current_state()
-
-    def print_tree(self, string=None):
-        """ Print the shown tree, i.e. MainTree or FilteredTree """
-        return self._tree.print_tree(string)
-
-    def get_all_nodes(self):
-        """ Return list of node_id of displayed nodes """
-        return self._tree.get_all_nodes()
-
-    def get_n_nodes(self, withfilters=[], include_transparent=True):
-        """ Returns quantity of displayed nodes in this tree
-
-        @withfilters => Additional filters are applied before counting,
-        i.e. the currently applied filters are also taken into account
-
-        @inclde_transparent => if it is False, filters which don't have
-        the transparent parameters are skipped, not takend into account
-        """
-
-        if not self.__ft:
-            self.__ft = FilteredTree(self.__maintree, self.__fbank, refresh = True)
-        return self.__ft.get_n_nodes(withfilters=withfilters,\
-                                    include_transparent=include_transparent)
-
-    def get_node_for_path(self, path):
-        """ Convert path to node_id.
-
-        I am not sure what this is for... """
-        return self._tree.get_node_for_path(path)
-
-    def get_paths_for_node(self, node_id=None):
-        """ If node_id is none, return root path
-
-        *Almost* reverse function to get_node_for_path
-        (1 node can have many paths, 1:M)
-        """
-        return self._tree.get_paths_for_node(node_id)
-
-    # FIXME change pid => parent_id
-    def next_node(self, node_id, pid=None):
-        """ Return the next node to node_id.
-
-        @parent_id => identify which instance of node_id to work.
-        If None, random instance is used """
-
-        return self._tree.next_node(node_id, pid)
-        
-    def node_has_child(self, node_id):
-        """ Has the node at least one child? """
-        if self.static:
-            return self.__maintree.get_node(node_id).has_child()
-        else:
-            return self.__ft.node_has_child(node_id)
-
-    def node_all_children(self, node_id=None):
-        """ Return children of a node """
-        if self.static:
-            if not node_id or self.__maintree.has_node(node_id):
-                return self.__maintree.get_node(node_id).get_children()
-            else:
-                return []
-        else:
-            return self._tree.node_all_children(node_id)
-
-    def node_n_children(self, node_id=None, recursive=False):
-        """ Return quantity of children of node_id.
-        If node_id is None, use the root node. 
-        Every instance of node has the same children"""
-        if not self.__ft:
-            self.__ft = FilteredTree(self.__maintree, self.__fbank, refresh = True)
-        return self.__ft.node_n_children(node_id,recursive)
-
-    def node_nth_child(self, node_id, n):
-        """ Return nth child of the node. """
-        if self.static:
-            if not node_id or node_id == 'root':
-                node = self.__maintree.get_root()
-            else:
-                node = self.__maintree.get_node(node_id)
-
-            if node and node.get_n_children() > n:
-                return node.get_nth_child(n)
-            else:
-                raise ValueError("node %s has less than %s nodes" %(node_id, n))
-        else:
-            realn = self.__ft.node_n_children(node_id)
-            if realn <= n:
-                raise ValueError("viewtree has %s nodes, no node %s" %(realn, n))
-            return self.__ft.node_nth_child(node_id, n)
-        
-    def node_has_parent(self, node_id):
-        """ Has node parents? Is it child of root? """
-        return len(self.node_parents(node_id)) > 0
-
-    def node_parents(self, node_id):
-        """ Returns displayed parents of the given node, or [] if there is no 
-        parent (such as if the node is a child of the virtual root),
-        or if the parent is not displayable.
-        Doesn't check wheter node node_id is displayed or not. (we only care about
-        parents)
-        """
-        if self.static:
-            return self.__maintree.get_node(node_id).get_parents()
-        else:
-            return self.__ft.node_parents(node_id)
-
-    def is_displayed(self, node_id):
-        """ Is the node displayed? """
-        if self.static:
-            return self.__maintree.has_node(node_id)
-        else:
-            return self.__ft.is_displayed(node_id)
-
-####### FILTERS ###############################################################
-    def list_applied_filters(self):
-        return self.__ft.list_applied_filters()
-        
-    def apply_filter(self, filter_name, parameters=None, \
-                     reset=False, refresh=True):
-        """ Applies a new filter to the tree.
-
-        @param filter_name: The name of an already registered filter to apply
-        @param parameters: Optional parameters to pass to the filter
-        @param reset : optional boolean. Should we remove other filters?
-        @param refresh : should we refresh after applying this filter ?
-        """
-        if self.static:
-            raise Exception("WARNING: filters cannot be applied" + \
-                            "to a static tree\n")
-
-        self.__ft.apply_filter(filter_name, parameters, reset, refresh)
-
-    def unapply_filter(self,filter_name,refresh=True):
-        """ Removes a filter from the tree.
-
-        @param filter_name: The name of filter to remove
-        """
-        if self.static:
-            raise Exception("WARNING: filters cannot be unapplied" +\
-                            "from a static tree\n")
-        
-        self.__ft.unapply_filter(filter_name, refresh)
-
-    def reset_filters(self, refresh=True, transparent_only=False):
-        """ Remove all filters currently set on the tree. """
-        if self.static:
-            raise Exception("WARNING: filters cannot be reset" +\
-                            "on a static tree\n")
-        else:
-             self.__ft.reset_filters(refresh, transparent_only)

=== removed file 'GTG/tools/liblarch/filteredtree.py'
--- GTG/tools/liblarch/filteredtree.py	2012-02-07 12:33:46 +0000
+++ GTG/tools/liblarch/filteredtree.py	1970-01-01 00:00:00 +0000
@@ -1,684 +0,0 @@
-from __future__ import with_statement
-# -*- coding: utf-8 -*-
-# -----------------------------------------------------------------------------
-# Gettings Things Gnome! - a personal organizer for the GNOME desktop
-# Copyright (c) 2008-2011 - 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.
-#
-# 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/>.
-# -----------------------------------------------------------------------------
-#
-import gobject
-import processqueue
-
-ASYNC_MODIFY = True
-
-class FilteredTree():
-    """ FilteredTree is the most important and also the most buggy part of
-    LibLarch.
-
-    FilteredTree transforms general changes in tree like creating/removing 
-    relationships between nodes and adding/updating/removing nodes into a serie
-    of simple steps which can be for instance by GTK Widget.
-
-    FilteredTree allows filtering - hiding certain nodes defined by a predicate.
-
-    The reason of most bugs is that FilteredTree is request to update a node.
-    FilteredTree must update its ancestors and also decestors. You cann't do that
-    by a simple recursion.
-    """
-
-    def __init__(self, tree, filtersbank, refresh=True):
-        """ Construct a layer where filters could by applied
-
-        @param tree: Original tree to filter.
-        @param filtersbank: Filter bank which stores filters
-        @param refresh: Requests all nodes in the beginning? Additional
-            filters can be added and refresh can be done later
-
-        _flat defines whether only nodes without children can be shown. For example WorkView filter.
-        """
-
-        self.cllbcks = {}
-        self.callcount = {'up':0,'down':0,'both':0}
-        self._queue = processqueue.SyncQueue()
-
-        # Cache
-        self.nodes = {}
-        self.root_id = None
-        self.nodes[self.root_id] = {'parents': [], 'children': []}
-        self.cache_paths = {}
-
-        # Connect to signals from MainTree
-        self.tree = tree
-        self.tree.register_callback("node-added", self.__external_modify)
-        self.tree.register_callback("node-modified", self.__external_modify)
-        self.tree.register_callback("node-deleted", self.__external_modify)
-
-        # Filters
-        self.__flat = False
-        self.applied_filters = []
-        self.fbank = filtersbank
-        
-        if refresh:
-            self.refilter()
-            
-
-    def set_callback(self, event, func,node_id=None, param=None):
-        """ Register a callback for an event.
-
-        It is possible to have just one callback for event.
-        @param event: one of added, modified, deleted, reordered
-        @param func: callback function
-        """
-        if event == 'runonce':
-            if not node_id:
-                raise Exception('runonce callback should come with a node_id')
-            if self.is_displayed(node_id):
-                #it is essential to idle_add to avoid hard recursion
-                gobject.idle_add(func,param)
-            else:
-                if not self.cllbcks.has_key(node_id):
-                    self.cllbcks[node_id] = []
-                self.cllbcks[node_id].append([func,node_id,param])
-        else:
-            self.cllbcks[event] = [func,node_id,param]
-        
-    def callback(self, event, node_id, path, neworder=None,async=False):
-        """ Run a callback.
-
-        To call callback, the object must be initialized and function exists.
-
-        @param event: one of added, modified, deleted, reordered, runonce
-        @param node_id: node_id parameter for callback function
-        @param path: path parameter for callback function
-        @param neworder: neworder parameter for reorder callback function
-        
-        The runonce event is actually only run once, when a given task appears.
-        """
-        
-        if event == 'added':
-            for func,nid,param in self.cllbcks.get(node_id,[]):
-                if nid and self.is_displayed(nid):
-                    func(param)
-                    if self.cllbcks.has_key(node_id):
-                        self.cllbcks.pop(node_id)
-                else:
-                    raise Exception('%s is not displayed but %s was added' %(nid,node_id))
-        func,nid,param = self.cllbcks.get(event, (None,None,None))
-        if func:
-            if neworder:
-                if async:
-                    self._queue.push(func, node_id, path, neworder)
-                else:
-                    func(node_id,path,neworder)
-            else:
-                if async:
-                    self._queue.push(func, node_id, path)
-                else:
-                    func(node_id,path)
-                    
-    def flush(self):
-        return self._queue.flush()
-            
-
-#### EXTERNAL MODIFICATION ####################################################
-    def __external_modify(self, node_id):
-        return self.__update_node(node_id,direction="both")
-        
-    def __update_node(self, node_id,direction):
-        '''update the node node_id and propagate the 
-        change in direction (up|down|both) '''
-#        print "update %s in %s" %(node_id,direction)
-        if node_id == self.root_id:
-            return None
-        
-        #Updating the node itself.
-        current_display = self.is_displayed(node_id)
-        new_display = self.__is_displayed(node_id)
-
-        completely_updated = True
-
-        if not current_display and not new_display:
-            # If a task is not displayed and should not be displayed, we
-            # should still check its parent because he might not be aware
-            # that he has a child
-            if self.tree.has_node(node_id):
-                node = self.tree.get_node(node_id)
-                for parent in node.get_parents():
-                    self.__update_node(parent,"up")
-            return completely_updated
-        elif not current_display and new_display:
-            action = 'added'
-        elif current_display and not new_display:
-            action = 'deleted'
-        else:
-            action = 'modified'
-            
-        # Create node info for new node
-        if action == 'added':
-            self.nodes[node_id] = {'parents':[], 'children':[]}
-
-        # Make sure parents are okay if we adding or updating
-        if action == 'added' or action == 'modified':
-            current_parents = self.nodes[node_id]['parents']
-            new_parents = self.__node_parents(node_id)
-            self.nodes[node_id]['parents'] = [parent_id for parent_id in new_parents 
-                if parent_id in self.nodes]
-
-            remove_from = list(set(current_parents) - set(new_parents))
-            add_to = list(set(new_parents) - set(current_parents))
-            stay = list(set(new_parents) - set(add_to))
-
-            #If we are updating a node at the root, we should take care
-            #of the root too
-            if direction == "down" and self.root_id in add_to:
-                direction = "both"
-
-            #We update the parents
-            if action == 'added':
-                #This check is for "phantom parents", for example
-                #If we have a flat or leave-only filter, we have to update the
-                #real parents!
-                node = self.tree.get_node(node_id)
-                for parent in node.get_parents():
-                    if parent not in new_parents and parent not in current_parents:
-                        self.__update_node(parent,direction="up")
-            for parent_id in remove_from:
-                self.send_remove_tree(node_id, parent_id)
-                self.nodes[parent_id]['children'].remove(node_id)
-                if direction == "both" or direction == "up":
-                    self.__update_node(parent_id,direction="up")
-            #there might be some optimization here
-            for parent_id in add_to:
-                if parent_id in self.nodes:
-                    self.nodes[parent_id]['children'].append(node_id)
-                    self.send_add_tree(node_id, parent_id)
-                    if direction == "both" or direction == "up":
-                        self.__update_node(parent_id,direction="up")
-                else:
-                    completely_updated = False
-            #We update all the other parents
-            if direction == "both" or direction == "up":
-                for parent_id in stay:
-                    self.__update_node(parent_id,direction="up")
-            #We update the node itself     
-            #Why should we call the callback only for modify?
-            if action == 'modified':
-                self.callcount[direction] += 1
-#                print self.callcount
-                for path in self.get_paths_for_node(node_id):
-                    self.callback(action, node_id, path,async=ASYNC_MODIFY) 
-            
-            #We update the children
-            current_children = self.nodes[node_id]['children']
-            new_children = self.__node_children(node_id)
-            if direction == "both" or direction == "down":
-                for cid in new_children:
-                    if cid not in current_children:
-                        self.__update_node(cid,direction="down")
-
-        elif action == 'deleted':
-            paths = self.get_paths_for_node(node_id)
-            children = list(reversed(self.nodes[node_id]['children']))
-            for child_id in children:
-                self.send_remove_tree(child_id, node_id)
-                self.nodes[child_id]['parents'].remove(node_id)
-            # Remove node from cache
-            for parent_id in self.nodes[node_id]['parents']:
-                self.nodes[parent_id]['children'].remove(node_id)
-                self.__update_node(parent_id,direction="up")
-
-            del self.nodes[node_id]
-
-            for child_id in children:
-                self.__update_node(child_id,direction="down")
-            
-            for path in paths:
-                self.callback(action, node_id, path)
-
-        return completely_updated
-
-    def send_add_tree(self, node_id, parent_id):
-        paths = self.get_paths_for_node(parent_id)
-        queue = [(node_id, (node_id, ))]
-
-        while queue != []:
-            node_id, relative_path = queue.pop(0)
-
-            for start_path in paths:
-                path = start_path + relative_path
-                self.callback('added', node_id, path)
-
-            for child_id in self.nodes[node_id]['children']:
-                queue.append((child_id, relative_path + (child_id,)))
-
-    def send_remove_tree(self, node_id, parent_id):
-        paths = self.get_paths_for_node(parent_id)
-        stack = [(node_id, (node_id, ), True)]
-
-        while stack != []:
-            node_id, relative_path, first_time = stack.pop()
-
-            if first_time:
-                stack.append((node_id, relative_path, False))
-                for child_id in self.nodes[node_id]['children']:
-                    stack.append((child_id, relative_path + (child_id,), True))
-
-            else:
-                for start_path in paths:
-                    path = start_path + relative_path
-                    self.callback('deleted', node_id, path)
-
-    def test_validity(self):
-        for node_id in self.nodes:
-            for parent_id in self.nodes[node_id]['parents']:
-                assert node_id in self.nodes[parent_id]['children']
-
-            if self.nodes[node_id]['parents'] == []:
-                assert node_id == self.root_id
-
-            for parent_id in self.nodes[node_id]['children']:
-                assert node_id in self.nodes[parent_id]['parents']
-
-
-#### OTHER ####################################################################
-    def refilter(self):
-        # Find out it there is at least one flat filter
-        self.__flat = False
-        for filter_name in self.applied_filters:
-            filt = self.fbank.get_filter(filter_name)
-            if filt and not self.__flat:
-                self.__flat = filt.is_flat()
-
-        # Clean the tree
-        for node_id in reversed(self.nodes[self.root_id]['children']):
-            self.send_remove_tree(node_id, self.root_id)
-
-        self.nodes = {}
-        self.nodes[self.root_id] = {'parents': [], 'children': []}
-
-        # Build tree again
-        root_node = self.tree.get_root()
-        queue = root_node.get_children()
-
-        while queue != []:
-            node_id = queue.pop(0)
-            #FIXME: decide which is the best direction
-            self.__update_node(node_id, direction="both")
-
-            node = self.tree.get_node(node_id)
-            for child_id in node.get_children():
-                queue.append(child_id)
-
-    def __is_displayed(self, node_id):
-        """ Should be node displayed regardless of its current status? """
-        if node_id and self.tree.has_node(node_id):
-            for filter_name in self.applied_filters:
-                filt = self.fbank.get_filter(filter_name)
-                if filt:
-                    can_be_displayed = filt.is_displayed(node_id)
-                    if not can_be_displayed:
-                        return False
-                else:
-                    return False
-            return True
-        else:
-            return False
-
-    def is_displayed(self, node_id):
-        """ Is the node displayed at the moment? """
-
-        return node_id in self.nodes
-
-    def __node_children(self, node_id):
-        if node_id == self.root_id:
-            raise Exception("Requesting children for root node")
-
-        if not self.__flat:
-            if self.tree.has_node(node_id):
-                node = self.tree.get_node(node_id)
-            else:
-                node = None
-        else:
-            node = None
-
-        if not node:
-            return []
-
-        toreturn = []
-        for child_id in node.get_children():
-            if self.__is_displayed(child_id):
-                toreturn.append(child_id)
-
-        return toreturn
-
-    def __node_parents(self, node_id):
-        """ Returns parents of the given node. If node has no parent or 
-        no displyed parent, return the virtual root.
-        """
-        if node_id == self.root_id:
-            raise ValueError("Requested a parent of the root node")
-
-        parents_nodes = []
-        #we return only parents that are not root and displayed
-        if not self.__flat and self.tree.has_node(node_id):
-            node = self.tree.get_node(node_id)
-            for parent_id in node.get_parents():
-                if self.__is_displayed(parent_id):
-                    parents_nodes.append(parent_id)
-
-        # Add to root if it is an orphan
-        if parents_nodes == []:
-            parents_nodes = [self.root_id]
-
-        return parents_nodes
-        
-    #This is a crude hack which is more performant that other methods
-    def is_path_valid(self,p):
-#        print "is %s valid?" %str(p)
-        valid = True
-        i = 0
-        if len(p) == 1:
-            valid = False
-        else:
-            while valid and i < len(p) - 1:
-                child = p[i+1]
-                par = p[i]
-                if self.nodes.has_key(par):
-                    valid = (child in self.nodes[par]['children'])
-                else:
-                    valid = False
-                i += 1
-        return valid
-
-    def get_paths_for_node(self, node_id):
-#        cached = self.cache_paths.get(node_id,None)
-        #The cache improves performance a lot for "stairs"
-        #FIXME : the cache cannot detect if a new path has been added
-#        validcache = False
-#        if cached:
-#            validcache = True
-#            for p in cached:
-#                validcache = validcache and self.is_path_valid(p)
-#            if validcache:
-##                print "the valid cache is : %s" %str(cached)
-#                return cached
-
-        
-        if node_id == self.root_id or not self.is_displayed(node_id):
-            return [()]
-        else:
-            toreturn = []
-            for parent_id in self.nodes[node_id]['parents']:
-                if parent_id not in self.nodes:
-                    raise Exception("Parent %s does not exists" % parent_id)
-                if node_id not in self.nodes[parent_id]['children']:
-                    raise Exception("%s is not children of %s\n%s" % (node_id, parent_id,str(self.nodes)))
-
-                for parent_path in self.get_paths_for_node(parent_id):
-                    mypath = parent_path + (node_id,)
-                    toreturn.append(mypath)
-#            #Testing the cache
-#            if validcache and toreturn != cached:
-#                print "We return %s but %s was cached" %(str(toreturn),str(cached))
-            self.cache_paths[node_id] = toreturn
-            return toreturn
-
-    def print_tree(self, string=False):
-        """ Representation of tree in FilteredTree
-        
-        @param string: if set, instead of printing, return string for printing.
-        """
-
-        stack = [(self.root_id, "")]
-
-        output = "_"*30 + "\n" + "FilteredTree cache\n" + "_"*30 + "\n"
-
-        while stack != []:
-            node_id, prefix = stack.pop()
-
-            output += prefix + str(node_id) + '\n'
-
-            for child_id in reversed(self.nodes[node_id]['children']):
-                stack.append((child_id, prefix+" "))
-
-        output += "_"*30 + "\n"
-
-        if string:
-            return output
-        else:
-            print output
-
-    def get_all_nodes(self):
-        nodes = list(self.nodes.keys())
-        nodes.remove(self.root_id)
-        return nodes
-
-    def get_n_nodes(self, withfilters=[], include_transparent=True):
-        """
-        returns quantity of displayed nodes in this tree
-        if the withfilters is set, returns the quantity of nodes
-        that will be displayed if we apply those filters to the current
-        tree. It means that the currently applied filters are also taken into
-        account.
-        If include_transparent=False, we only take into account the applied filters
-        that doesn't have the transparent parameters.
-        """
-        if withfilters == [] and include_transparent:
-            # Use current cache
-            return len(self.nodes) - 1
-        elif withfilters != [] and include_transparent:
-            # Filter on the current nodes
-
-            filters = []
-            for filter_name in withfilters:
-                filt = self.fbank.get_filter(filter_name)
-                if filt:
-                    filters.append(filt)
-
-            total_count = 0
-            for node_id in self.nodes:
-                if node_id == self.root_id:
-                    continue
-
-                displayed = True
-                for filt in filters:
-                    displayed = filt.is_displayed(node_id)
-                    if not displayed:
-                        break
-                
-                if displayed:
-                    total_count += 1
-
-            return total_count
-        else:
-            # Recompute every node
-
-            # 1st step: build list of filters
-            filters = []
-            for filter_name in self.applied_filters:
-                filt = self.fbank.get_filter(filter_name)
-                if not filt:
-                    continue
-
-                # Skip transparent filters if needed
-                transparent = filt.is_transparent()
-                if not include_transparent and transparent:
-                    continue
-
-                filters.append(filt)
-
-            for filter_name in withfilters:
-                filt = self.fbank.get_filter(filter_name)
-                if filt:
-                    filters.append(filt)
-
-            total_count = 0
-            for node_id in self.tree.get_all_nodes():
-                displayed = True
-                for filt in filters:
-                    displayed = filt.is_displayed(node_id)
-                    if not displayed:
-                        break
-                
-                if displayed:
-                    total_count += 1
-
-            return total_count
-
-    def get_node_for_path(self, path):
-        if not path or path == ():
-            return None
-        node_id = path[-1]
-        #Both "if" should be benchmarked
-        if path in self.get_paths_for_node(node_id):
-#        if self.is_path_valid(path):
-            return node_id
-        else:
-            return None
-
-    def next_node(self, node_id, parent_id):
-        if node_id == self.root_id:
-            raise Exception("Calling next_node on the root node")
-
-        if node_id not in self.nodes:
-            raise Exception("Node %s is not displayed" % node_id)
-
-        parents = self.nodes[node_id]['parents']
-        if not parent_id:
-            parent_id = parents[0]
-        elif parent_id not in parents:
-            raise Exception("Node %s does not have parent %s" % (node_id, parent_id))
-
-        index = self.nodes[parent_id]['children'].index(node_id)
-        if index+1 < len(self.nodes[parent_id]['children']):
-            return self.nodes[parent_id]['children'][index+1]
-        else:
-            return None
-
-    def node_all_children(self, node_id=None):
-        if node_id is None:
-            node_id = self.root_id
-        return list(self.nodes[node_id]['children'])
-
-    def node_has_child(self, node_id):
-        return len(self.nodes[node_id]['children']) > 0
-
-    def node_n_children(self, node_id, recursive=False):
-        if node_id == None:
-            node_id = self.root_id
-        if not self.nodes.has_key(node_id):
-            return 0
-        if recursive:
-            total = 0
-            #We avoid recursion in a loop
-            #because the dict might be updated in the meantime
-            cids = list(self.nodes[node_id]['children'])   
-            for cid in cids: 
-                total += self.node_n_children(cid,recursive=True)
-                total += 1 #we count the node itself ofcourse
-            return total  
-        else:
-            return len(self.nodes[node_id]['children'])
-
-    def node_nth_child(self, node_id, n):
-        return self.nodes[node_id]['children'][n]
-
-    def node_parents(self, node_id):
-        if node_id not in self.nodes:
-            raise IndexError('Node %s is not displayed' % node_id)
-        parents = list(self.nodes[node_id]['parents'])
-        if self.root_id in parents:
-            parents.remove(self.root_id)
-        return parents
-
-    def get_current_state(self):
-        """ Allows to connect LibLarch widget on fly to FilteredTree
-        
-        Sends 'added' signal/callback for every nodes that is currently
-        in FilteredTree. After that, FilteredTree and TreeModel are
-        in the same state
-        """
-        for node_id in self.nodes[self.root_id]['children']:
-            self.send_add_tree(node_id, self.root_id)
-
-#### FILTERS ##################################################################
-    def list_applied_filters(self):
-        return list(self.applied_filters)
-
-    def apply_filter(self, filter_name, parameters=None, \
-                    reset=None, refresh=None):
-        """ Apply a new filter to the tree.
-
-        @param filter_name: The name of an registrered filter from filters_bank
-        @param parameters: Optional parameters to pass to the filter
-        @param reset: Should other filters be removed?
-        @param refresh: Should be refereshed the whole tree?
-                (performance optimization)
-        """
-        if reset:
-            self.applied_filters = []
-
-        if parameters:
-            filt = self.fbank.get_filter(filter_name)
-            if filt:
-                filt.set_parameters(parameters)
-            else:
-                raise ValueError("No filter of name %s in the bank" % filter_name)
-
-        if filter_name not in self.applied_filters:
-            self.applied_filters.append(filter_name)
-            if refresh:
-                self.refilter()
-            toreturn = True
-        else:
-            toreturn = False
-
-        return toreturn
-
-    def unapply_filter(self, filter_name, refresh=True):
-        """ Removes a filter from the tree.
-
-        @param filter_name: The name of an already added filter to remove
-        @param refresh: Should be refereshed the whole tree?
-                (performance optimization)
-        """
-        if filter_name in self.applied_filters:
-            self.applied_filters.remove(filter_name)
-            if refresh:
-                self.refilter()
-            return True
-        else:
-            return False
-
-    def reset_filters(self, refresh=True, transparent_only=False):
-        """
-        Clears all filters currently set on the tree.  Can't be called on 
-        the main tree.
-        Remove only transparents filters if transparent_only is True
-        """
-        if transparent_only:
-            for f in list(self.applied_filters):
-                filt = self.fbank.get_filter(f)
-                if filt:
-                    if filt.get_parameters('transparent'):
-                        self.applied_filters.remove(f)
-                else:
-                    print "bank is %s" % self.applied_filters
-                    raise IndexError('Applied filter %s doesnt' %f +\
-                                    'exist anymore in the bank')
-        else:
-            self.applied_filters = []
-        if refresh:
-            self.refilter()

=== removed file 'GTG/tools/liblarch/filters_bank.py'
--- GTG/tools/liblarch/filters_bank.py	2012-02-06 18:17:12 +0000
+++ GTG/tools/liblarch/filters_bank.py	1970-01-01 00:00:00 +0000
@@ -1,130 +0,0 @@
-# -*- coding: utf-8 -*-
-# -----------------------------------------------------------------------------
-# Gettings 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.
-#
-# 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/>.
-# 
-
-"""
-filters_bank stores all of GTG's filters in centralized place
-"""
-
-
-class Filter:
-    def __init__(self, func, req):
-        self.func = func
-        self.dic = {}
-        self.tree = req
-
-    def set_parameters(self, dic):
-        if dic:
-            self.dic = dic
-    
-    def is_displayed(self, node_id):
-        if self.tree.has_node(node_id):
-            task = self.tree.get_node(node_id)
-        else:
-            return False
-
-        if self.dic:
-            value = self.func(task, parameters=self.dic)
-        else:
-            value = self.func(task)
-
-        if 'negate' in self.dic and self.dic['negate']:
-            value = not value
-
-        return value
-        
-    def get_parameters(self, param):
-        return self.dic.get(param, None)
-
-    def is_flat(self):
-        """ Should be the final list flat """
-        return self.get_parameters('flat')
-
-    def is_transparent(self):
-        """ Is this filter transparent? """
-        return self.get_parameters('transparent')
-    
-class FiltersBank:
-    """
-    Stores filter objects in a centralized place.
-    """
-
-    def __init__(self,tree):
-        """
-        Create several stock filters:
-
-        workview - Tasks that are active, workable, and started
-        active - Tasks of status Active
-        closed - Tasks of status closed or dismissed
-        notag - Tasks with no tags
-        """
-        self.tree = tree
-        self.available_filters = {}
-        self.custom_filters = {}
-
-    ##########################################
-        
-    def get_filter(self,filter_name):
-        """ Get the filter object for a given name """
-        if self.available_filters.has_key(filter_name):
-            return self.available_filters[filter_name]
-        elif self.custom_filters.has_key(filter_name):
-            return self.custom_filters[filter_name]
-        else:
-            return None
-    
-    def list_filters(self):
-        """ List, by name, all available filters """
-        liste = self.available_filters.keys()
-        liste += self.custom_filters.keys()
-        return liste
-    
-    def add_filter(self,filter_name,filter_func,parameters=None):
-        """
-        Adds a filter to the filter bank 
-        Return True if the filter was added
-        Return False if the filter_name was already in the bank
-        """
-        if filter_name not in self.list_filters():
-            negate = False
-            if filter_name.startswith('!'):
-                negate = True
-                filter_name = filter_name[1:]
-            else:
-                filter_obj = Filter(filter_func,self.tree)
-                filter_obj.set_parameters(parameters)
-            self.custom_filters[filter_name] = filter_obj
-            return True
-        else:
-            return False
-        
-    def remove_filter(self,filter_name):
-        """
-        Remove a filter from the bank.
-        Only custom filters that were added here can be removed
-        Return False if the filter was not removed
-        """
-        if not self.available_filters.has_key(filter_name):
-            if self.custom_filters.has_key(filter_name):
-                self.unapply_filter(filter_name)
-                self.custom_filters.pop(filter_name)
-                return True
-            else:
-                return False
-        else:
-            return False

=== removed file 'GTG/tools/liblarch/processqueue.py'
--- GTG/tools/liblarch/processqueue.py	2012-02-06 18:17:12 +0000
+++ GTG/tools/liblarch/processqueue.py	1970-01-01 00:00:00 +0000
@@ -1,122 +0,0 @@
-# -*- coding: utf-8 -*-
-# -----------------------------------------------------------------------------
-# Getting Things Gnome! - a personal organizer for the GNOME desktop
-# Copyright (c) 2008-2011 - 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.
-#
-# 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/>.
-# -----------------------------------------------------------------------------
-
-
-import threading
-import gobject
-
-class SyncQueue:
-    """ Synchronized queue for processing requests"""
-
-    def __init__(self):
-        """ Initialize synchronized queue.
-
-        @param callback - function for processing requests"""
-        self._low_queue = []
-        self._queue = []
-        self._vip_queue = []
-        self._handler = None
-        self._lock = threading.Lock()
-        
-        self.count = 0
-        
-    def process_queue(self):
-        """ Process requests from queue """
-        for action in self.process():
-            func = action[0]
-            func(*action[1:])
-        # return True to process other requests as well
-        return True
-        
-    def low_push(self, *element):
-        """ Add a new element to the queue.
-
-        Schedule its processing if it is not already.  
-        vip element are in a priority queue. They will be processed first
-        (this comment was actually written in Berlin Airport, after having
-        to wait in an economy class queue)"""
-        self._lock.acquire()
-        self._low_queue.append(element)
-
-        if self._handler is None:
-            self._handler = gobject.idle_add(self.process_queue)
-        self._lock.release()
-
-    def push(self, *element):
-        """ Add a new element to the queue.
-
-        Schedule its processing if it is not already.  
-        """
-        self._lock.acquire()
-        lon = len(self._queue)
-        if element not in self._queue:
-            self._queue.append(element)
-
-        if self._handler is None:
-            self._handler = gobject.idle_add(self.process_queue)
-        self._lock.release()
-        
-    def priority_push(self, *element):
-        """ Add a new element to the queue.
-
-        Schedule its processing if it is not already.  
-        vip element are in a priority queue. They will be processed first
-        (this comment was actually written in Berlin Airport, after having
-        to wait in an economy class queue)"""
-        self._lock.acquire()
-        self._vip_queue.append(element)
-
-        if self._handler is None:
-            self._handler = gobject.idle_add(self.process_queue)
-        self._lock.release()
-        
-    def flush(self):
-        """Block until all elements of the queue are processed.
-        This is should be only used for testing purpose"""
-        while len(self._queue) > 0 or len(self._vip_queue) > 0 or\
-                                        len(self._low_queue) > 0 :
-            self._lock.acquire()
-            self._lock.release()
-        return True
-
-    def process(self):
-        """ Return elements to process
-        
-        At the moment, it returns just one element. In the future more
-        elements may be better to return (to speed it up).
-        
-        If there is no request left, disable processing. """
-
-        self._lock.acquire()
-        if len(self._vip_queue) > 0:
-            toreturn = [self._vip_queue.pop(0)]
-        elif len(self._queue) > 0:
-            toreturn = [self._queue.pop(0)]
-        elif len(self._low_queue) > 0:
-            toreturn = [self._low_queue.pop(0)]
-        else:
-            toreturn = []
-
-        if len(self._queue) == 0 and len(self._vip_queue) == 0 and\
-                                        len(self._low_queue) == 0 and\
-                                        self._handler is not None:
-            gobject.source_remove(self._handler)
-            self._handler = None
-        self._lock.release()
-        return toreturn

=== removed file 'GTG/tools/liblarch/tree.py'
--- GTG/tools/liblarch/tree.py	2012-02-06 18:17:12 +0000
+++ GTG/tools/liblarch/tree.py	1970-01-01 00:00:00 +0000
@@ -1,439 +0,0 @@
-# -*- coding: utf-8 -*-
-# -----------------------------------------------------------------------------
-# Liblarch
-# Copyright (c) 2010-2011 - Lionel Dricot & Izidor Matušov
-#
-# 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.
-#
-# 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/>.
-# -----------------------------------------------------------------------------
-
-import threading
-import processqueue
-from GTG.tools.liblarch.treenode import TreeNode
-
-class MainTree:
-    """ Tree which stores and handle all requests """
-
-    def __init__(self):
-        """ Initialize MainTree.
-
-        @param root - the "root" node which contains all nodes
-        """
-
-        self.nodes = {}
-        self.pending_relationships = []
-
-        self.__cllbcks = {}
-
-        self.root_id = 'root'
-        self.root = TreeNode(self.root_id)
-        self.root.set_tree(self)
-
-        self._queue = processqueue.SyncQueue()
-        self._origin_thread = threading.current_thread()
-
-    def __str__(self):
-        return "<Tree: root = '%s'>" % self.root
-
-    def get_root(self):
-        """ Return root node """
-        return self.root
-
-####### INTERFACE FOR CALLBACKS ###############################################
-    def register_callback(self, event, func):
-        """ Store function and return unique key which can be used to
-        unregister the callback later """
-
-        if not self.__cllbcks.has_key(event):
-            self.__cllbcks[event] = {}
-
-        callbacks = self.__cllbcks[event]
-        key = 0
-        while callbacks.has_key(key):
-            key += 1
-
-        callbacks[key] = func
-        return key
-
-    def deregister_callback(self, event, key):
-        """ Remove the callback identifed by key (from register_cllbck) """
-        try:
-            del self.__cllbcks[event][key]
-        except KeyError:
-            pass
-
-    def _callback(self, event, node_id):
-        """ Inform others about the event """
-        #We copy the dict to not loop on it while it could be modified
-        dic = dict(self.__cllbcks.get(event, {}))
-        for func in dic.itervalues():
-            func(node_id)
-
-####### INTERFACE FOR HANDLING REQUESTS #######################################
-    def add_node(self, node, parent_id=None, priority="low"):
-        self._external_request(self._add_node, priority, node, parent_id)
-
-    def remove_node(self, node_id, recursive=False):
-        self._external_request(self._remove_node, True, node_id, recursive)
-
-    def modify_node(self, node_id, priority="low"):
-        self._external_request(self._modify_node, priority, node_id)
-
-    def new_relationship(self, parent_id, child_id):
-        self._external_request(self._new_relationship, False, parent_id, child_id)
-
-    def break_relationship(self, parent_id, child_id):
-        self._external_request(self._break_relationship, False, parent_id, child_id)
-
-    def _external_request(self, request_type, priority, *args):
-        """ Put the reqest into queue and in the main thread handle it """
-        if priority == "high":
-            self._queue.priority_push(request_type, *args)
-        elif priority == "normal" or priority == "medium":
-            self._queue.push(request_type, *args)
-        else:
-            self._queue.low_push(request_type, *args)
-
-        #I'm really wondering what is this line about
-        #It doesn't seem right nor useful, except for unit tests.
-        if self._origin_thread == threading.current_thread():
-            self._queue.process_queue()
-
-    def refresh_all(self):
-        """ Refresh all nodes """
-        for node_id in self.nodes.keys():
-            self.modify_node(node_id)
-
-####### IMPLEMENTATION OF HANDLING REQUESTS ###################################
-    def _create_relationship(self, parent_id, child_id):
-        """ Create relationship without any checks """
-        parent = self.nodes[parent_id]
-        child = self.nodes[child_id]
-
-        if child_id not in parent.children:
-            parent.children.append(child_id)
-
-        if parent_id not in child.parents:
-            child.parents.append(parent_id)
-
-        if child_id in self.root.children:
-            self.root.children.remove(child_id)
-
-    def _destroy_relationship(self, parent_id, child_id):
-        """ Destroy relationship without any checks """
-        parent = self.nodes[parent_id]
-        child = self.nodes[child_id]
-
-        if child_id in parent.children:
-            parent.children.remove(child_id)
-
-        if parent_id in child.parents:
-            child.parents.remove(parent_id)
-
-    def _is_circular_relation(self, parent_id, child_id):
-        """ Would the new relation be circular?
-        
-        Go over every possible ancestors. If one of them is child_id,
-        this would be circular relation.
-        """
-
-        visited = []
-        ancestors = [parent_id]
-        while ancestors != []:
-            node_id = ancestors.pop(0)
-            if node_id == child_id:
-                return True
-            
-            if node_id not in self.nodes:
-                continue
-    
-            for ancestor_id in self.nodes[node_id].parents:
-                if ancestor_id not in visited:
-                    ancestors.append(ancestor_id)
-
-        return False
-        
-    def _add_node(self, node, parent_id):
-        """ Add a node to the tree
-
-        @param node - node to be added
-        @param parent_id - parent to add or it will be add to root
-        """
-        node_id = node.get_id()
-        if node_id in self.nodes:
-            print "Error: Node '%s' already exists" % node_id
-            return False
-
-        node.set_tree(self)
-        for relationship in node.pending_relationships:
-            if relationship not in self.pending_relationships:
-                self.pending_relationships.append(relationship)
-        node.pending_relationships = []
-
-        self.nodes[node_id] = node
-
-        add_to_root = True
-        parents_to_refresh = []
-        children_to_refresh = []
-
-        # Build pending relationships
-        for rel_parent_id, rel_child_id in list(self.pending_relationships):
-            # Adding as a child
-            if rel_child_id == node_id and rel_parent_id in self.nodes:
-                if not self._is_circular_relation(rel_parent_id, node_id):
-                    self._create_relationship(rel_parent_id, node_id)
-                    add_to_root = False
-                    parents_to_refresh.append(rel_parent_id)
-                else:
-                    print "Error: Detected pending circular relationship", \
-                        rel_parent_id, rel_child_id
-                self.pending_relationships.remove((rel_parent_id, rel_child_id))
-
-            # Adding as a parent
-            if rel_parent_id == node_id and rel_child_id in self.nodes:
-                if not self._is_circular_relation(node_id, rel_child_id):
-                    self._create_relationship(node_id, rel_child_id)
-                    children_to_refresh.append(rel_child_id)
-                else:
-                    print "Error: Detected pending circular relationship", \
-                        rel_parent_id, rel_child_id
-                self.pending_relationships.remove((rel_parent_id, rel_child_id))
-        
-        # Build relationship with given parent
-        if parent_id is not None:
-            if self._is_circular_relation(parent_id, node_id):
-                raise Exception('Creating circular relationship between %s and %s' % \
-                     (parent_id, node_id))
-            if parent_id in self.nodes:
-                self._create_relationship(parent_id, node_id)
-                add_to_root = False
-                parents_to_refresh.append(parent_id)
-            else:
-                self.pending_relationships.append((parent_id, node_id))
-
-        # Add at least to root
-        if add_to_root:
-            self.root.children.append(node_id)
-
-        # Send callbacks
-        #updating the parent and the children is handled by the FT
-        self._callback("node-added", node_id)
-        
-#        #The following callback is only needed in case we have a
-#        #Flat filter applied.
-#        for parent_id in parents_to_refresh:
-#            self._callback("node-modified", parent_id)
-
-        #this callback is really fast. No problem
-#        for child_id in children_to_refresh:
-#            #FIXME: why parent_id? this should be a bug!
-#            #removing this doesn't affect the tests. Why is it useful?
-#            self._callback("node-modified", child_id)
-
-    def _remove_node(self, node_id, recursive=False):
-        """ Remove node from tree """
-
-        if node_id not in self.nodes:
-            print "*** Warning *** Trying to remove a non-existing node"
-            return
-
-        # Do not remove root node
-        if node_id is None:
-            return
-
-        # Remove pending relationships with this node
-        for relation in list(self.pending_relationships):
-            if node_id in relation:
-                self.pending_relationships.remove(relation)
-
-        node = self.nodes[node_id]
-
-        # Handle parents
-        for parent_id in node.parents:
-            self._destroy_relationship(parent_id, node_id)
-            self._callback('node-modified', parent_id)
-
-        # Handle children
-        for child_id in list(node.children):
-            if recursive:
-                self._remove_node(child_id, True)
-            else:
-                self._destroy_relationship(node_id, child_id)
-                self._callback('node-modified', child_id)
-                if self.nodes[child_id].parents == []:
-                    self.root.children.append(child_id)
-
-        if node_id in self.root.children:
-            self.root.children.remove(node_id)
-
-        self.nodes.pop(node_id)
-        self._callback('node-deleted', node_id)
-
-    def _modify_node(self, node_id):
-        """ Force update of a node """
-        if node_id != self.root_id and node_id in self.nodes:
-            self._callback('node-modified', node_id)
-
-    def _new_relationship(self, parent_id, child_id):
-        """ Creates a new relationship 
-        
-        This method is used mainly from TreeNode"""
-
-        if (parent_id, child_id) in self.pending_relationships:
-            self.pending_relationships.remove((parent_id, child_id))
-
-        if not parent_id or not child_id or parent_id == child_id:
-            return False
-
-        if parent_id not in self.nodes or child_id not in self.nodes:
-            self.pending_relationships.append((parent_id, child_id))
-            return True
-
-        if self._is_circular_relation(parent_id, child_id):
-            self._destroy_relationship(parent_id, child_id)
-            raise Exception('Cannot build circular relationship between %s and %s' % (parent_id, child_id))
-
-
-        self._create_relationship(parent_id, child_id)
-
-        # Remove from root when having a new relationship
-        if child_id in self.root.children:
-            self.root.children.remove(child_id)
-
-        self._callback('node-modified', parent_id)
-        self._callback('node-modified', child_id)
-
-    def _break_relationship(self, parent_id, child_id):
-        """ Remove a relationship
-
-        This method is used mainly from TreeNode """
-        for rel_parent, rel_child in list(self.pending_relationships):
-            if rel_parent == parent_id and rel_child == child_id:
-                self.pending_relationships.remove((rel_parent, rel_child))
-
-        if not parent_id or not child_id or parent_id == child_id:
-            return False
-
-        if parent_id not in self.nodes or child_id not in self.nodes:
-            return False
-
-        self._destroy_relationship(parent_id, child_id)
-
-        # Move to root if beak the last parent
-        if self.nodes[child_id].get_parents() == []:
-            self.root.add_child(child_id)
-
-        self._callback('node-modified', parent_id)
-        self._callback('node-modified', child_id)
-
-
-####### INTERFACE FOR READING STATE OF TREE ###################################
-    def has_node(self, node_id):
-        """ Is this node_id in this tree? """
-        return node_id in self.nodes
-
-    def get_node(self, node_id=None):
-        """ Return node of tree or root node of this tree """
-        if node_id in self.nodes:
-            return self.nodes[node_id]
-        elif node_id == self.root_id or node_id is None:
-            return self.root
-        else:
-            raise ValueError("Node %s is not in the tree" % node_id)
-
-    def get_node_for_path(self, path):
-        """ Convert path into node_id
-        
-        @return node_id if path is valid, None otherwise
-        """
-        if not path or path == ():
-            return None
-        node_id = path[-1]
-        if path in self.get_paths_for_node(node_id):
-            return node_id
-        else:
-            return None
-        return node_id
-
-    def get_paths_for_node(self, node_id):
-        """ Get all paths for node_id """
-        if not node_id or node_id == self.root_id:
-            return [()]
-        elif node_id in self.nodes:
-            node = self.nodes[node_id]
-            if node.has_parent():
-                paths = []
-                for parent_id in node.get_parents():
-                    if parent_id not in self.nodes:
-                        continue
-                    for path in self.get_paths_for_node(parent_id):
-                        paths.append(path + (node_id,))
-                return paths
-            else:
-                return [(node_id,)]
-        else:
-            raise ValueError("Cannot get path for non existing node %s" % node_id)
-
-    def get_all_nodes(self):
-        """ Return list of all nodes in this tree """
-        return self.nodes.keys()
-
-    def next_node(self, node_id, parent_id=None):
-        """ Return the next sibling node or None if there is none
-        
-        @param  node_id - we look for siblings of this node
-        @param parent_id - specify which siblings should be used, 
-            if task has more parents. If None, random parent will be used
-        """
-        if node_id is None:
-            raise ValueError('node_id should be different than None')
-
-        node = self.get_node(node_id)
-        parents_id = node.get_parents()
-        if len(parents_id) == 0:
-            parid = self.root_id
-        elif parent_id in parents_id:
-            parid = parent_id
-        else:
-            parid = parents_id[0]
-
-        parent = self.get_node(parid)
-        if not parent:
-            raise ValueError('Parent does not exist')
-
-        index = parent.get_child_index(node_id)
-        if index == None:
-            error = 'children are : %s\n' %parent.get_children()
-            error += 'node %s is not a child of %s' %(node_id,parid)
-            raise IndexError(error)
-
-        if parent.get_n_children() > index+1:
-            return parent.get_nth_child(index+1)
-        else:
-            return None
-
-    def print_tree(self, string=False):
-        output = self.root_id + "\n"
-        stack = [(" ", child_id) for child_id in reversed(self.root.children)]
-
-        while stack != []:
-            prefix, node_id = stack.pop()
-            output += prefix + node_id + "\n"
-            prefix += " "
-            for child_id in reversed(self.nodes[node_id].get_children()):
-                stack.append((prefix, child_id))
-
-        if string:
-            return output
-        else:
-            print output,

=== removed file 'GTG/tools/liblarch/treenode.py'
--- GTG/tools/liblarch/treenode.py	2012-02-06 18:17:12 +0000
+++ GTG/tools/liblarch/treenode.py	1970-01-01 00:00:00 +0000
@@ -1,214 +0,0 @@
-# -*- coding: utf-8 -*-
-# -----------------------------------------------------------------------------
-# Liblarch
-# Copyright (c) 2010-2011 - Lionel Dricot & Izidor Matušov
-#
-# 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.
-#
-# 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/>.
-# -----------------------------------------------------------------------------
-
-class TreeNode:
-    """ Object just for a single node in Tree """
-    def __init__(self, node_id, parent=None):
-        """ Initializes node
-
-        @param node_id - unique identifier of node (str)
-        @param parent - node_id of parent
-        """
-        self.node_id = node_id
-        
-        self.parents_enabled = True
-        self.children_enabled = True
-        self.parents = []
-        self.children = []
-
-        self.tree = None
-        self.pending_relationships = []
-
-        if parent:
-            self.add_parent(parent)
-
-    def __str__(self):
-        return "<TreeNode: '%s'>" % (self.node_id)
-
-    def get_id(self):
-        """ Return node_id """
-        return self.node_id
-        
-    def modified(self,priority="low"):
-        """ Force to update node (because it has changed) """
-        if self.tree:
-            self.tree.modify_node(self.node_id,priority=priority)
-
-    def set_tree(self, tree):
-        """ Set tree which is should contain this node.
-        
-        This method should be called only from MainTree. It is not
-        part of public interface. """
-        self.tree = tree
-
-    def get_tree(self):
-        """ Return associated tree with this node """
-        return self.tree
-
-    def new_relationship(self, parent_id, child_id):
-        """ Create new relationship or save it for later if there is no tree """
-        if self.tree:
-            self.tree.new_relationship(parent_id, child_id)
-        else:
-            self.pending_relationships.append((parent_id, child_id))
-
-####### Parents ###############################################################
-    def set_parents_enabled(self,bol):
-        if not bol:
-            for p in self.get_parents():
-                self.remove_parent(p)
-        self.parents_enabled = bol
-        
-    def has_parents_enabled(self):
-        return self.parents_enabled
-
-    def add_parent(self, parent_id):
-        """ Add a new parent """
-        if parent_id != self.get_id() and self.parents_enabled \
-                                      and parent_id not in self.parents:
-            if not self.tree:
-                self.pending_relationships.append((parent_id, self.get_id()))
-            elif not self.tree.has_node(parent_id):
-                self.tree.pending_relationships.append((parent_id, self.get_id()))
-            else:
-                par = self.tree.get_node(parent_id)
-                if par.has_children_enabled():
-                    self.parents.append(parent_id)
-                    self.new_relationship(parent_id, self.node_id)
-
-    def set_parent(self, parent_id):
-        """ Remove other parents and set this parent as only parent """
-        if parent_id != self.get_id() and self.parents_enabled:
-            is_already_parent_flag = False
-            if not self.tree:
-                self.pending_relationships.append((parent_id, self.get_id()))
-            elif not self.tree.has_node(parent_id):
-                for p in self.get_parents():
-                    self.tree.break_relationship(p,self.get_id())
-                self.tree.pending_relationships.append((parent_id, self.get_id()))
-            else:
-                par = self.tree.get_node(parent_id)
-                if par.has_children_enabled():
-                    for node_id in self.parents:
-                        if node_id != parent_id:
-                            self.remove_parent(node_id)
-                        else:
-                            is_already_parent_flag = True
-                    if parent_id and not is_already_parent_flag:
-                        self.add_parent(parent_id)
-
-    def remove_parent(self, parent_id):
-        """ Remove parent """
-        if self.parents_enabled and parent_id in self.parents:
-            self.parents.remove(parent_id)
-            self.tree.break_relationship(parent_id, self.node_id)
-
-    def has_parent(self, parent_id=None):
-        """ Has parent/parents?
-
-        @param parent_id - None => has any parent?
-            not None => has this parent?
-        """
-        if self.parents_enabled:
-            if parent_id:
-                return self.tree.has_node(parent_id) and parent_id in self.parents
-            else:
-                return len(self.parents) > 0
-        else:
-            return False
-
-    def get_parents(self):
-        """ Return parents of node """
-        parents = []
-        if self.parents_enabled and self.tree:
-            for parent_id in self.parents:
-                if self.tree.has_node(parent_id):
-                    parents.append(parent_id)
-
-        return parents
-
-####### Children ##############################################################
-    def set_children_enabled(self,bol):
-        if not bol:
-            for c in self.get_children():
-                self.tree.break_relationship(self.get_id(),c)
-        self.children_enabled = bol
-        
-    def has_children_enabled(self):
-        return self.children_enabled
-        
-    def add_child(self, child_id):
-        """ Add a children to node """
-        if self.children_enabled and child_id != self.get_id():
-            if child_id not in self.children:
-                if not self.tree:
-                    self.pending_relationships.append((self.get_id(), child_id))
-                elif not self.tree.has_node(child_id):
-                    self.tree.pending_relationships.append((self.get_id(), child_id))
-                else:
-                    child = self.tree.get_node(child_id)
-                    if child.has_parents_enabled():
-                        self.children.append(child_id)
-                        self.new_relationship(self.node_id, child_id)
-            else:
-                print "%s was already in children of %s" % (child_id, self.node_id)
-
-    def has_child(self, child_id=None):
-        """ Has child/children?
-
-        @param child_id - None => has any child?
-            not None => has this child?
-        """
-        if self.children_enabled:
-            if child_id:
-                return child_id in self.children
-            else:
-                return bool(self.children)
-        else:
-            return False
-
-    def get_children(self):
-        """ Return children of nodes """
-        children = []
-        if self.children_enabled and self.tree:
-            for child_id in self.children:
-                if self.tree.has_node(child_id):
-                    children.append(child_id)
-
-        return children
-
-    def get_n_children(self):
-        """ Return count of children """
-        if self.children_enabled:
-            return len(self.get_children())
-        else:
-            return 0
-
-    def get_nth_child(self, index):
-        """ Return nth child """
-        try:
-            return self.children[index]
-        except(IndexError):
-            raise ValueError("Requested non-existing child")
-
-    def get_child_index(self, node_id):
-        if self.children_enabled and node_id in self.children:
-            return self.children.index(node_id)
-        else:
-            return None

=== modified file 'gtg'
--- gtg	2010-09-08 09:50:32 +0000
+++ gtg	2012-02-09 13:32:34 +0000
@@ -30,6 +30,8 @@
 import sys
 from optparse import OptionParser
 
+required_liblarch_api="1.0"
+
 
 def X_is_running():
     from gtk.gdk import Screen
@@ -39,6 +41,36 @@
     except RuntimeError:
         pass
     return False
+    
+#This funtion import liblarch from the system, then from the local folder
+#and, as a last resort, give the command to install it.
+def import_liblarch():
+    git_cmd= "git clone git://github.com/ploum/liblarch.git  ../liblarch"
+    try:
+        import liblarch
+        toreturn = True
+    except:
+        sys.path.append("../liblarch/")
+        try:
+            import liblarch
+            toreturn = True
+        except:
+	        print "GTG requires liblarch but liblarch is not installed."
+	        print "To install liblarch, run the following command in the current folder:"
+	        print "\n"
+	        print "   %s" %git_cmd
+	        print "\n"
+	        print "More informations about liblarch: https://live.gnome.org/liblarch/";
+	        toreturn = False
+	if toreturn:
+	    if not liblarch.is_compatible(required_liblarch_api):
+	        print "Your liblarch copy has its API at version %s" %liblarch.api
+	        print "but your GTG copy need liblarch API version %s" %required_liblarch_api
+	        print ""
+	        print "You may fix that by downloading the last version of liblarch with:"
+	        print "   %s"%git_cmd
+	        toreturn = False
+	return toreturn
 
 
 try:
@@ -64,7 +96,7 @@
         print "Could not open X display"
         sys.exit(1)
 
-    else:
+    elif import_liblarch():
         import GTG.gtg
         sys.exit(GTG.gtg.main(options, args))
 


Follow ups