[hamster-applet] try to maintain location in the window by avoiding full refresh where possible. fixes bug 625223



commit e00b23603961522f0633372f4f3b0f6a58226f1c
Author: Toms Bauģis <toms baugis gmail com>
Date:   Sun Jul 25 18:19:28 2010 +0100

    try to maintain location in the window by avoiding full refresh where possible. fixes bug 625223

 src/hamster/widgets/facttree.py |  182 ++++++++++++++++++++++++++++-----------
 1 files changed, 132 insertions(+), 50 deletions(-)
---
diff --git a/src/hamster/widgets/facttree.py b/src/hamster/widgets/facttree.py
index 12351b6..9017267 100644
--- a/src/hamster/widgets/facttree.py
+++ b/src/hamster/widgets/facttree.py
@@ -30,25 +30,59 @@ from .tags import Tag
 import pango
 
 def parent_painter(column, cell, model, iter):
-    fact = model.get_value(iter, 0)
-    parent_info = model.get_value(iter, 1)
+    row = model.get_value(iter, 0)
 
-    if fact is None:
-        parent_info["first"] = model.get_path(iter) == (0,) # first row
-        cell.set_property('data', parent_info)
+    if isinstance(row, FactRow):
+        cell.set_property('data', row)
     else:
-        cell.set_property('data', fact)
+        row.first = model.get_path(iter) == (0,) # first row
+        cell.set_property('data', row)
 
 def action_painter(column, cell, model, iter):
     cell.set_property('xalign', 1)
     cell.set_property('yalign', 0)
 
-    if model.get_value(iter, 0) is None:
+    if isinstance(model.get_value(iter, 0), GroupRow):
         cell.set_property("stock_id", "")
     else:
         cell.set_property("stock_id", "gtk-edit")
 
 
+
+class GroupRow(object):
+    def __init__(self, label, date, duration):
+        self.label = label
+        self.duration = duration
+        self.date = date
+        self.first = False # will be set by the painter, used
+
+    def __eq__(self, other):
+        return isinstance(other, GroupRow) \
+           and self.label == other.label \
+           and self.duration == other.duration \
+           and self.date == other.date
+
+    def __hash__(self):
+        return 1
+
+class FactRow(object):
+    def __init__(self, fact):
+        self.fact = fact
+        self.id = fact['id']
+        self.name = fact['name']
+        self.category = fact['category']
+        self.description = fact['description']
+        self.tags = fact['tags']
+        self.start_time = fact['start_time']
+        self.end_time = fact['end_time']
+        self.delta = fact['delta']
+
+    def __eq__(self, other):
+        return isinstance(other, FactRow) and other.id == self.id
+
+    def __hash__(self):
+        return self.id
+
 class FactTree(gtk.TreeView):
     __gsignals__ = {
         "edit-clicked": (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, (gobject.TYPE_PYOBJECT, )),
@@ -62,7 +96,7 @@ class FactTree(gtk.TreeView):
         self.set_show_expanders(False)
 
         # fact (None for parent), duration, parent data (if any)
-        self.store_model = gtk.ListStore(gobject.TYPE_PYOBJECT, gobject.TYPE_PYOBJECT)
+        self.store_model = gtk.ListStore(gobject.TYPE_PYOBJECT)
         self.set_model(self.store_model)
 
 
@@ -100,6 +134,8 @@ class FactTree(gtk.TreeView):
         self._test_layout = _test_context.create_layout()
         font = pango.FontDescription(gtk.Style().font_desc.to_string())
         self._test_layout.set_font_description(font)
+        self.prev_rows = []
+        self.new_rows = []
 
 
     def fix_row_heights(self):
@@ -109,41 +145,40 @@ class FactTree(gtk.TreeView):
             self.columns_autosize()
 
     def clear(self):
-        self.store_model.clear()
+        #self.store_model.clear()
         self.longest_activity_category = 0
         self.longest_interval = 0
         self.longest_duration = 0
 
     def update_longest_dimensions(self, fact):
-        interval = "%s -" % fact["start_time"].strftime("%H:%M")
-        if fact["end_time"]:
-            interval = "%s %s" % (interval, fact["end_time"].strftime("%H:%M"))
+        interval = "%s -" % fact.start_time.strftime("%H:%M")
+        if fact.end_time:
+            interval = "%s %s" % (interval, fact.end_time.strftime("%H:%M"))
         self._test_layout.set_markup(interval)
         w, h = self._test_layout.get_pixel_size()
         self.longest_interval = max(self.longest_interval, w + 20)
 
 
-        self._test_layout.set_markup("%s - <small>%s</small> " % (stuff.escape_pango(fact["name"]), stuff.escape_pango(fact["category"])))
+        self._test_layout.set_markup("%s - <small>%s</small> " % (stuff.escape_pango(fact.name),
+                                                                  stuff.escape_pango(fact.category)))
         w, h = self._test_layout.get_pixel_size()
         self.longest_activity_category = max(self.longest_activity_category, w + 10)
 
-        self._test_layout.set_markup("%s" % stuff.format_duration(fact["delta"]))
+        self._test_layout.set_markup("%s" % stuff.format_duration(fact.delta))
         w, h = self._test_layout.get_pixel_size()
         self.longest_duration = max(self.longest_duration, w)
 
 
     def add_fact(self, fact):
+        fact = FactRow(fact)
         self.update_longest_dimensions(fact)
-        self.store_model.append([fact, None])
+        self.new_rows.append(fact)
 
 
     def add_group(self, group_label, group_date, facts):
-        total = stuff.duration_minutes([fact["delta"] for fact in facts])
+        total_duration = stuff.duration_minutes([fact["delta"] for fact in facts])
 
-        # adds group of facts with the given label
-        self.store_model.append([None, dict(date = group_date,
-                                            label = group_label,
-                                            duration = total)])
+        self.new_rows.append(GroupRow(group_label, group_date, total_duration))
 
         for fact in facts:
             self.add_fact(fact)
@@ -164,12 +199,15 @@ class FactTree(gtk.TreeView):
         row = self.get_row(path)
         if not row: return None
 
-        if row[0]:
-            return row[0]['id']
+        if isinstance(row[0], FactRow):
+            return row[0].id
         else:
-            return row[1]['label']
+            return row[0].label
+
 
     def detach_model(self):
+        self.prev_rows = list(self.new_rows)
+        self.new_rows = []
         # ooh, somebody is going for refresh!
         # let's save selection too - maybe it will come handy
         self.store_selection()
@@ -178,12 +216,53 @@ class FactTree(gtk.TreeView):
 
 
         # and now do what we were asked to
-        self.set_model()
+        #self.set_model()
+        self.clear()
 
 
     def attach_model(self):
+        print "*" * 20
+        prev_rows = set(self.prev_rows)
+        new_rows = set(self.new_rows)
+        common = set(prev_rows) & set(new_rows)
+
+        if common: # do full refresh only if we don't recognize any rows
+            gone = prev_rows - new_rows
+            if gone:
+                all_rows = len(self.store_model)
+                rows = list(self.store_model)
+                rows.reverse()
+
+                for i, row in enumerate(rows):
+                    if row[0] in gone:
+                        print "removing row"
+                        self.store_model.remove(self.store_model.get_iter(all_rows - i-1))
+
+                self.prev_rows = [row[0] for row in self.store_model]
+
+            new = new_rows - prev_rows
+            if new:
+                for i, row in enumerate(self.new_rows):
+                    if i <= len(self.store_model) - 1:
+                        if row == self.store_model[i][0]:
+                            continue
+
+                        print "adding new row"
+                        self.store_model.insert_before(self.store_model.get_iter(i), (row,))
+                    else:
+                        self.store_model.append((row, ))
+
+
+        else:
+            self.store_model.clear()
+            for row in self.new_rows:
+                self.store_model.append((row, ))
+
+
+
+
         # attach model is also where we calculate the bounding box widths
-        self.set_model(self.store_model)
+        #self.set_model(self.store_model)
 
         #self.parent.set_policy(gtk.POLICY_NEVER, gtk.POLICY_AUTOMATIC)
 
@@ -258,7 +337,11 @@ class FactTree(gtk.TreeView):
         selection = self.get_selection()
         (model, iter) = selection.get_selected()
         if iter:
-            return model[iter][0] or model[iter][1]["date"]
+            data = model[iter][0]
+            if isinstance(data, FactRow):
+                return data.fact
+            else:
+                return data.date
         else:
             return None
 
@@ -302,10 +385,11 @@ class FactTree(gtk.TreeView):
             data = model[path][0]
 
             self.set_tooltip_text(None)
-            if data and "id" in data:
+
+            if isinstance(data, FactRow):
                 renderer = view.get_column(0).get_cell_renderers()[0]
 
-                label = data["description"]
+                label = data.description
                 self.set_tooltip_text(label)
 
             self.trigger_tooltip_query()
@@ -376,7 +460,7 @@ class FactCellRenderer(gtk.GenericCellRenderer):
 
         context = window.cairo_create()
 
-        if "id" in self.data:
+        if isinstance(self.data, FactRow):
             fact, parent = self.data, None
         else:
             parent, fact = self.data, None
@@ -390,14 +474,14 @@ class FactCellRenderer(gtk.GenericCellRenderer):
             text_color = self.normal_color
             # if we are selected, change font color appropriately
             if current_fact and isinstance(current_fact, dt.date) \
-               and current_fact == parent["date"]:
+               and current_fact == parent.date:
                 text_color = self.selected_color
 
             self.date_label.color = text_color
-            self.date_label.text = "<b>%s</b>" % stuff.escape_pango(parent["label"])
+            self.date_label.text = "<b>%s</b>" % stuff.escape_pango(parent.label)
             self.date_label.x = 5
 
-            if self.data["first"]:
+            if self.data.first:
                 y = 5
             else:
                 y = 20
@@ -406,7 +490,7 @@ class FactCellRenderer(gtk.GenericCellRenderer):
 
 
             self.duration_label.color = text_color
-            self.duration_label.text = "<b>%s</b>" % stuff.format_duration(parent["duration"])
+            self.duration_label.text = "<b>%s</b>" % stuff.format_duration(parent.duration)
             self.duration_label.x = width - self.duration_label.width
             self.duration_label.y = y
 
@@ -437,16 +521,16 @@ class FactCellRenderer(gtk.GenericCellRenderer):
         selected = False
         # if we are selected, change font color appropriately
         if current_fact and isinstance(current_fact, dt.date) == False \
-           and current_fact["id"] == fact["id"]:
+           and current_fact["id"] == fact.id:
             text_color = self.selected_color
             selected = True
 
 
 
         """ start time and end time at beginning of column """
-        interval = fact["start_time"].strftime("%H:%M -")
-        if fact["end_time"]:
-            interval = "%s %s" % (interval, fact["end_time"].strftime("%H:%M"))
+        interval = fact.start_time.strftime("%H:%M -")
+        if fact.end_time:
+            interval = "%s %s" % (interval, fact.end_time.strftime("%H:%M"))
 
         self.interval_label.text = interval
         self.interval_label.color = text_color
@@ -455,7 +539,7 @@ class FactCellRenderer(gtk.GenericCellRenderer):
 
 
         """ duration at the end """
-        self.duration_label.text = stuff.format_duration(fact["delta"])
+        self.duration_label.text = stuff.format_duration(fact.delta)
         self.duration_label.color = text_color
         self.duration_label.x = cell_width - self.duration_label.width
         self.duration_label.y = 2
@@ -473,8 +557,8 @@ class FactCellRenderer(gtk.GenericCellRenderer):
         category_width = 0
 
         self.category_label.text = ""
-        if fact["category"]:
-            self.category_label.text = " - <small>%s</small>" % stuff.escape_pango(fact["category"])
+        if fact.category:
+            self.category_label.text = " - <small>%s</small>" % stuff.escape_pango(fact.category)
             if not selected:
                 category_color = graphics.Colors.contrast(text_color,  100)
 
@@ -486,9 +570,7 @@ class FactCellRenderer(gtk.GenericCellRenderer):
 
         self.activity_label.color = text_color
         self.activity_label.width = None
-        self.activity_label.text = stuff.escape_pango(fact["name"])
-        #activity_label = g.create_layout()
-        #activity_label.set_markup(stuff.escape_pango(fact["name"]))
+        self.activity_label.text = stuff.escape_pango(fact.name)
 
         # if activity label does not fit, we will shrink it
         if self.activity_label.width > cell_width - category_width:
@@ -513,19 +595,19 @@ class FactCellRenderer(gtk.GenericCellRenderer):
         x = cell_start + activity_width + category_width + 12
 
         current_height = 0
-        if fact["tags"]:
+        if fact.tags:
             # try putting tags on same line if they fit
             # otherwise move to the next line
             tags_end = cell_start + cell_width
 
-            tag = Tag(fact["tags"][0])
+            tag = Tag(fact.tags[0])
 
             if x + tag.width > tags_end:
                 x = cell_start
                 y = self.activity_label.height + 4
 
 
-            for i, tag in enumerate(fact["tags"]):
+            for i, tag in enumerate(fact.tags):
                 tag = Tag(tag)
 
                 if x + tag.width >= tags_end:
@@ -547,8 +629,8 @@ class FactCellRenderer(gtk.GenericCellRenderer):
         # see if we can fit in single line
         # if not, put description under activity
         self.description_label.text = ""
-        if fact["description"]:
-            self.description_label.text = "<small>%s</small>" % stuff.escape_pango(fact["description"])
+        if fact.description:
+            self.description_label.text = "<small>%s</small>" % stuff.escape_pango(fact.description)
             self.description_label.color = text_color
             self.description_label.wrap = pango.WRAP_WORD
 
@@ -573,8 +655,8 @@ class FactCellRenderer(gtk.GenericCellRenderer):
 
 
     def on_get_size(self, widget, cell_area):
-        if "id" not in self.data:
-            if self.data["first"]:
+        if isinstance(self.data, GroupRow):
+            if self.data.first:
                 return (0, 0, 0, int((self.default_size + 10) * 1.5))
             else:
                 return (0, 0, 0, (self.default_size + 10) * 2)



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