Title: [chandler2] (grant)[180] Add a better API for single (or multiple) selection in chandler.core.Table
Revision
180
Author
grant
Date
2009-03-02 12:48:42 -0800 (Mon, 02 Mar 2009)

Log Message

Add a better API for single (or multiple) selection in chandler.core.Table

Modified Paths

Diff

Modified: trunk/Chandler-Platform/Table.txt (179 => 180)


--- trunk/Chandler-Platform/Table.txt	2009-03-02 20:44:21 UTC (rev 179)
+++ trunk/Chandler-Platform/Table.txt	2009-03-02 20:48:42 UTC (rev 180)
@@ -302,6 +302,60 @@
 line corresponding to the empty part of the scroll area of our
 hypothetical table.
 
+Row selections
+--------------
+By default, a :class:`Table` allows a single selected item, accessible via
+the :attr:`~Table.selected_item` API:
+
+>>> table.selected_item.lastName
+u'Topalov'
+>>> table.selected_item is table.items[0]
+True
+
+Note that :attr:`~Table.selected_item` is an optional attribute, so
+it's only set up when you access it. It's initialized by default to be
+the first element in :attr:`~Table.items`.
+
+We can change the selected item by assigning :attr:`~Table.selected_item`:
+
+>>> table.selected_item = players[0]
+>>> table.selected_item.lastName
+u'Morozevich'
+
+It's common enough that you want a :class:`Table` to allow more than
+one selected item, of course. There's an attribute to change that,
+:attr:`~Table.single_item_selection`, which defaults to ``True``
+
+>>> table.single_item_selection
+True
+
+but can be changed:
+
+>>> table.single_item_selection = False
+
+In this case, :attr:`~Table.selection` becomes a
+:class:`~peak.events.collections.SubSet` of items, and
+is empty by default:
+
+>>> table.selection
+SubSet([])
+
+>>> table.selection.update((players[1], players[2]))
+>>> sorted(p.lastName for p in table.selection)
+[u'Anand', u'Topalov']
+
+>>> table.selection.remove(players[1])
+>>> list(table.selection) == [players[2]]
+True
+
+Note that it's OK to use :attr:`~Table.selection` in the
+case of :attr:`~Table.single_item_selection` being ``True``:
+
+>>> table.single_item_selection = True
+>>> list(table.selection) == [table.selected_item]
+True
+
+
 TODO
 ----
 

Modified: trunk/Chandler-Platform/chandler/core.py (179 => 180)


--- trunk/Chandler-Platform/chandler/core.py	2009-03-02 20:44:21 UTC (rev 179)
+++ trunk/Chandler-Platform/chandler/core.py	2009-03-02 20:48:42 UTC (rev 180)
@@ -505,7 +505,9 @@
     subcomponents = Many(inverse=InteractionComponent.scope)
 
     def make_model_cell(self, attr):
-        return _RuleCell(lambda: trellis.Cells(self.model)[attr])
+        def get_cell():
+            return trellis.Cells(self.model)[attr]
+        return _RuleCell(get_cell)
 
     @staticmethod
     def feature_cells(**kw):
@@ -622,10 +624,39 @@
             self.items.sort_key = self.sort_column.sort_key
             self.items.reverse = not self.sort_column.sort_ascending
 
+    new_selection = trellis.attr(resetting_to=None)
+    single_item_selection = trellis.attr(True)
+
     @trellis.maintain(initially=None, optional=True)
+    def selection(self):
+        if self.single_item_selection:
+            return trellis.Set([self.selected_item])
+        selection = self.selection
+        new_selected_items = self.new_selection
+
+        if selection is None:
+            if new_selected_items is None:
+                new_selected_items = ()
+            selection = collections.SubSet(new_selected_items, base=self.model)
+        elif new_selected_items is not None:
+            # We are going to do some set arithmetic here to try
+            # to try to make sure we do an update with one
+            # atomic operation
+            diff = set(new_selected_items) # i.e. allow any iterable
+            diff = diff.difference(selection).union(selection.difference(diff))
+            selection.symmetric_difference_update(diff)
+
+        return selection
+
+    @trellis.maintain(initially=None, optional=True)
     def selected_item(self):
-        if self.selected_item is None or not self.selected_item in self.items:
-            return self.items[0] if self.items else None
+        if self.new_selection is not None:
+            return self.new_selection
+        elif self.selected_item is None:
+            try:
+                return iter(self.items).next()
+            except StopIteration, TypeError:
+                pass # i.e. return None
         return self.selected_item
 
     def get_cell_value(self, (row, col)):
_______________________________________________
commits mailing list
commits@osafoundation.org
http://lists.osafoundation.org/mailman/listinfo/commits

Reply via email to