[Dextrose] [PATCH 2/5][dx3][sugar] multi-selection listview

Martin Abente martin.abente.lahaye at gmail.com
Tue Jun 7 17:46:23 EDT 2011


Implements the selection list view, by adding a new toggle cell
renderer and a new column to the "_add_column" method.

Fires a "select-toggled" signal to communicate the selection
status.

Adds a view-level selection cache. This is necessary because
the view can change from/to different mount points and we
want to store/restore every mount point selection state.

Applies a "_is_visible" filter to the journal-model created,
updated and deleted callbacks. This filter will avoid
unnecessary view redraws when the the object_id does not belong
to the current mount point.

Signed-off-by: Martin Abente <martin.abente.lahaye at gmail.com>
---
 src/jarabe/journal/listview.py |   76 +++++++++++++++++++++++++++++++++++++--
 1 files changed, 72 insertions(+), 4 deletions(-)

diff --git a/src/jarabe/journal/listview.py b/src/jarabe/journal/listview.py
index 0aee1b7..a0296ef 100644
--- a/src/jarabe/journal/listview.py
+++ b/src/jarabe/journal/listview.py
@@ -65,7 +65,10 @@ class BaseListView(gtk.Bin):
     __gtype_name__ = 'JournalBaseListView'
 
     __gsignals__ = {
-        'clear-clicked': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE, ([])),
+        'clear-clicked':    (gobject.SIGNAL_RUN_FIRST,
+                            gobject.TYPE_NONE, ([])),
+        'select-toggled':   (gobject.SIGNAL_RUN_FIRST,
+                            gobject.TYPE_NONE, ([bool]))
     }
 
     def __init__(self):
@@ -117,16 +120,56 @@ class BaseListView(gtk.Bin):
         model.updated.connect(self.__model_updated_cb)
         model.deleted.connect(self.__model_deleted_cb)
 
+        # Multi-selection stuff
+        self._selection_cache = set()
+
+    def get_mountpoint(self):
+        return self._query.get('mountpoints', [''])[0]
+
+    def _is_viewable(self, object_id=None):
+        mount_point = self.get_mountpoint()
+
+        if not object_id or \
+            not mount_point:
+                return False
+        elif not object_id.startswith('/') and \
+            mount_point is '/':
+                return True
+        elif object_id.startswith(mount_point) and \
+            mount_point is not '/':
+                return True
+        else:
+            return False
+
     def __model_created_cb(self, sender, **kwargs):
-        self._set_dirty()
+        object_id = kwargs.get('object_id', None)
+        if self._is_viewable(object_id):
+            self._set_dirty()
 
     def __model_updated_cb(self, sender, **kwargs):
-        self._set_dirty()
+        object_id = kwargs.get('object_id', None)
+        if self._is_viewable(object_id):
+            self._set_dirty()
 
     def __model_deleted_cb(self, sender, **kwargs):
-        self._set_dirty()
+        object_id = kwargs.get('object_id', None)
+        if self._is_viewable(object_id):
+            self._set_dirty()
 
     def _add_columns(self):
+
+        cell_select = gtk.CellRendererToggle()
+        cell_select.props.indicator_size = style.zoom(26)
+        cell_select.props.activatable = True
+        cell_select.connect('toggled', self.__selected_cb)
+
+        column = gtk.TreeViewColumn()
+        column.props.sizing = gtk.TREE_VIEW_COLUMN_FIXED
+        column.props.fixed_width = style.GRID_CELL_SIZE
+        column.pack_start(cell_select)
+        column.add_attribute(cell_select, "active", ListModel.COLUMN_SELECT)
+        self.tree_view.append_column(column)
+
         cell_favorite = CellRendererFavorite(self.tree_view)
         cell_favorite.connect('clicked', self.__favorite_clicked_cb)
 
@@ -244,6 +287,9 @@ class BaseListView(gtk.Bin):
         else:
             cell.props.xo_color = None
 
+    def __selected_cb(self, cell, path):
+        self._model.toggle_selection(path)
+
     def __favorite_clicked_cb(self, cell, path):
         row = self._model[path]
         metadata = model.get(row[ListModel.COLUMN_UID])
@@ -255,6 +301,9 @@ class BaseListView(gtk.Bin):
             metadata['keep'] = '1'
         model.write(metadata, update_mtime=False)
 
+    def get_model(self):
+        return self._model
+
     def update_with_query(self, query_dict):
         logging.debug('ListView.update_with_query')
         if 'order_by' not in query_dict:
@@ -275,14 +324,33 @@ class BaseListView(gtk.Bin):
 
         if self._model is not None:
             self._model.stop()
+            self._manage_selection_cache()
         self._dirty = False
 
         self._model = ListModel(self._query)
+        self._model.connect('select', self.__model_select_cb)
         self._model.connect('ready', self.__model_ready_cb)
         self._model.connect('progress', self.__model_progress_cb)
         self._model.setup()
 
+    def _manage_selection_cache(self):
+        # Discard from cache elements that might not be selected anymore
+        self._selection_cache = \
+            self._selection_cache.difference(self._model._query_set_cache)
+        # Add to cache elements that are selected
+        self._selection_cache = \
+            self._selection_cache.union(self._model.get_selection())
+
+    def __model_select_cb(self, tree_model, status, refresh_view):
+        if refresh_view:
+            self._refresh_view(tree_model)
+        self.emit('select-toggled', status)
+
     def __model_ready_cb(self, tree_model):
+        self._model.add_selection(self._selection_cache)
+        self._refresh_view(tree_model)
+
+    def _refresh_view(self, tree_model):
         self._stop_progress_bar()
 
         self._scroll_position = self.tree_view.props.vadjustment.props.value
-- 
1.7.4.4



More information about the Dextrose mailing list