[pygobject] Atomic inserts in Gtk.{List,Tree}Store overrides



commit bf8c95836e1cc1e1629937cbc69ea3027fb82746
Author: Martin Pitt <martin pitt ubuntu com>
Date:   Thu Mar 15 09:48:10 2012 +0100

    Atomic inserts in Gtk.{List,Tree}Store overrides
    
    Gtk.{List,Tree}Store's overrides provide append(), insert() etc. methods which
    take an optional data row array. If this is given, use insert_with_valuesv()
    instead of creating a new iter and then filling it with data. The latter sent a
    row-added signal, at which time the row was still empty, and a subsequent
    row-changed signal. With this we only get a single row-added signal with
    complete row data.
    
    Note that this does not change insert_{before,after}(), as there is no
    counterpart of insert_with_valuesv() which takes a TreeIter instead of a
    position. For those you will still get two signals, and have to deal with None
    values.
    
    https://bugzilla.gnome.org/show_bug.cgi?id=671610

 gi/overrides/Gtk.py     |   81 +++++++++++++++++++++++++++++------------------
 tests/test_overrides.py |   74 ++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 124 insertions(+), 31 deletions(-)
---
diff --git a/gi/overrides/Gtk.py b/gi/overrides/Gtk.py
index c2fd233..cb1a77a 100644
--- a/gi/overrides/Gtk.py
+++ b/gi/overrides/Gtk.py
@@ -785,7 +785,7 @@ class TreeModel(Gtk.TreeModel):
         if success:
             return parent_iter
 
-    def set_row(self, treeiter, row):
+    def _convert_row(self, row):
         # TODO: Accept a dictionary for row
         # model.append(None,{COLUMN_ICON: icon, COLUMN_NAME: name})
         if isinstance(row, str):
@@ -795,16 +795,24 @@ class TreeModel(Gtk.TreeModel):
         if len(row) != n_columns:
             raise ValueError('row sequence has the incorrect number of elements')
 
+        result = []
         for i in range(n_columns):
             value = row[i]
+            result.append(self._convert_value(i, value))
+        return result
+
+    def set_row(self, treeiter, row):
+        converted_row = self._convert_row(row)
+        for i in range(self.get_n_columns()):
+            value = row[i]
             if value is None:
                continue  # None means skip this row
 
             self.set_value(treeiter, i, value)
 
-    def _convert_value(self, treeiter, column, value):
+    def _convert_value(self, column, value):
             if value is None:
-                return
+                return None
 
             # we may need to convert to a basic type
             type_ = self.get_column_type(column)
@@ -926,22 +934,32 @@ class ListStore(Gtk.ListStore, TreeModel, TreeSortable):
         Gtk.ListStore.__init__(self)
         self.set_column_types(column_types)
 
-    def append(self, row=None):
-        treeiter = Gtk.ListStore.append(self)
-
+    def _do_insert(self, position, row):
         if row is not None:
-            self.set_row(treeiter, row)
+            row = self._convert_row(row)
+            columns = range(len(row))
+            treeiter = self.insert_with_valuesv(position, columns, row)
+        else:
+            treeiter = Gtk.ListStore.insert(self, position)
 
         return treeiter
 
-    def insert(self, position, row=None):
-        treeiter = Gtk.ListStore.insert(self, position)
+    def append(self, row=None):
+        if row:
+            return self._do_insert(-1, row)
+        # gtk_list_store_insert() does not know about the "position == -1"
+        # case, so use append() here
+        else:
+            return Gtk.ListStore.append(self)
 
-        if row is not None:
-            self.set_row(treeiter, row)
+    def prepend(self, row=None):
+        return self._do_insert(0, row)
 
-        return treeiter
+    def insert(self, position, row=None):
+        return self._do_insert(position, row)
 
+    # FIXME: sends two signals; check if this can use an atomic
+    # insert_with_valuesv()
     def insert_before(self, sibling, row=None):
         treeiter = Gtk.ListStore.insert_before(self, sibling)
 
@@ -950,6 +968,8 @@ class ListStore(Gtk.ListStore, TreeModel, TreeSortable):
 
         return treeiter
 
+    # FIXME: sends two signals; check if this can use an atomic
+    # insert_with_valuesv()
     def insert_after(self, sibling, row=None):
         treeiter = Gtk.ListStore.insert_after(self, sibling)
 
@@ -958,16 +978,8 @@ class ListStore(Gtk.ListStore, TreeModel, TreeSortable):
 
         return treeiter
 
-    def prepend(self, row=None):
-        treeiter = Gtk.ListStore.prepend(self)
-
-        if row is not None:
-            self.set_row(treeiter, row)
-
-        return treeiter
-
     def set_value(self, treeiter, column, value):
-        value = self._convert_value(treeiter, column, value)
+        value = self._convert_value(column, value)
         Gtk.ListStore.set_value(self, treeiter, column, value)
 
     def set(self, treeiter, *args):
@@ -1152,22 +1164,27 @@ class TreeStore(Gtk.TreeStore, TreeModel, TreeSortable):
         Gtk.TreeStore.__init__(self)
         self.set_column_types(column_types)
 
-    def append(self, parent, row=None):
-        treeiter = Gtk.TreeStore.append(self, parent)
-
+    def _do_insert(self, parent, position, row):
         if row is not None:
-            self.set_row(treeiter, row)
+            row = self._convert_row(row)
+            columns = range(len(row))
+            treeiter = self.insert_with_values(parent, position, columns, row)
+        else:
+            treeiter = Gtk.TreeStore.insert(self, parent, position)
 
         return treeiter
 
-    def insert(self, parent, position, row=None):
-        treeiter = Gtk.TreeStore.insert(self, parent, position)
+    def append(self, parent, row=None):
+        return self._do_insert(parent, -1, row)
 
-        if row is not None:
-            self.set_row(treeiter, row)
+    def prepend(self, parent, row=None):
+        return self._do_insert(parent, 0, row)
 
-        return treeiter
+    def insert(self, parent, position, row=None):
+        return self._do_insert(parent, position, row)
 
+    # FIXME: sends two signals; check if this can use an atomic
+    # insert_with_valuesv()
     def insert_before(self, parent, sibling, row=None):
         treeiter = Gtk.TreeStore.insert_before(self, parent, sibling)
 
@@ -1176,6 +1193,8 @@ class TreeStore(Gtk.TreeStore, TreeModel, TreeSortable):
 
         return treeiter
 
+    # FIXME: sends two signals; check if this can use an atomic
+    # insert_with_valuesv()
     def insert_after(self, parent, sibling, row=None):
         treeiter = Gtk.TreeStore.insert_after(self, parent, sibling)
 
@@ -1185,7 +1204,7 @@ class TreeStore(Gtk.TreeStore, TreeModel, TreeSortable):
         return treeiter
 
     def set_value(self, treeiter, column, value):
-        value = self._convert_value(treeiter, column, value)
+        value = self._convert_value(column, value)
         Gtk.TreeStore.set_value(self, treeiter, column, value)
 
     def set(self, treeiter, *args):
diff --git a/tests/test_overrides.py b/tests/test_overrides.py
index 1613c6d..5ea02e7 100644
--- a/tests/test_overrides.py
+++ b/tests/test_overrides.py
@@ -999,6 +999,43 @@ class TestGtk(unittest.TestCase):
 
         self.assertEquals(i, 99)
 
+    def test_tree_store_signals(self):
+        tree_store = Gtk.TreeStore(int, bool)
+
+        def on_row_inserted(tree_store, tree_path, tree_iter, signal_list):
+            signal_list.append('row-inserted')
+
+        def on_row_changed(tree_store, tree_path, tree_iter, signal_list):
+            signal_list.append('row-changed')
+
+        signals = []
+        tree_store.connect('row-inserted', on_row_inserted, signals)
+        tree_store.connect('row-changed', on_row_changed, signals)
+
+        # adding rows with and without data should only call one signal
+        tree_store.append(None, (0, False))
+        self.assertEqual(signals, ['row-inserted'])
+
+        signals.pop()
+        tree_store.append(None)
+        self.assertEqual(signals, ['row-inserted'])
+
+        signals.pop()
+        tree_store.prepend(None, (0, False))
+        self.assertEqual(signals, ['row-inserted'])
+
+        signals.pop()
+        tree_store.prepend(None)
+        self.assertEqual(signals, ['row-inserted'])
+
+        signals.pop()
+        tree_store.insert(None, 1, (0, False))
+        self.assertEqual(signals, ['row-inserted'])
+
+        signals.pop()
+        tree_store.insert(None, 1)
+        self.assertEqual(signals, ['row-inserted'])
+
     def test_list_store(self):
         class TestPyObject(object):
             pass
@@ -1188,6 +1225,43 @@ class TestGtk(unittest.TestCase):
 
         self.assertEquals(i, 102)
 
+    def test_list_store_signals(self):
+        list_store = Gtk.ListStore(int, bool)
+
+        def on_row_inserted(list_store, tree_path, tree_iter, signal_list):
+            signal_list.append('row-inserted')
+
+        def on_row_changed(list_store, tree_path, tree_iter, signal_list):
+            signal_list.append('row-changed')
+
+        signals = []
+        list_store.connect('row-inserted', on_row_inserted, signals)
+        list_store.connect('row-changed', on_row_changed, signals)
+
+        # adding rows with and without data should only call one signal
+        list_store.append((0, False))
+        self.assertEqual(signals, ['row-inserted'])
+
+        signals.pop()
+        list_store.append()
+        self.assertEqual(signals, ['row-inserted'])
+
+        signals.pop()
+        list_store.prepend((0, False))
+        self.assertEqual(signals, ['row-inserted'])
+
+        signals.pop()
+        list_store.prepend()
+        self.assertEqual(signals, ['row-inserted'])
+
+        signals.pop()
+        list_store.insert(1, (0, False))
+        self.assertEqual(signals, ['row-inserted'])
+
+        signals.pop()
+        list_store.insert(1)
+        self.assertEqual(signals, ['row-inserted'])
+
     def test_tree_path(self):
         p1 = Gtk.TreePath()
         p2 = Gtk.TreePath.new_first()



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]