[meld] Fix sensitivity of prev/next diff in VC and DirDiff (closes bgo#650181)



commit be078d2422622068e8194756c98226c7c88b7d2d
Author: Kai Willadsen <kai willadsen gmail com>
Date:   Sun Dec 4 11:06:11 2011 +1000

    Fix sensitivity of prev/next diff in VC and DirDiff (closes bgo#650181)
    
    Common code for finding the previous/next differing rows was moved to
    the tree module, and both VCView and DirDiff now use that approach.
    Previous/next diff is updated on tree cursor movement and used to set
    sensitivity of the corresponding actions.
    
    Currently there is no attempt to minimise the number of tree
    traversals done when the cursor moves. In some situations of very large
    trees with few changes, this may mean that scrolling through the tree
    with the keyboard will be very slow. There are certainly tricks that
    can be done with invalidation of the prev/next validity (TODO-ed in the
    code) that should improve the situation.

 data/ui/vcview.ui |    1 +
 meld/dirdiff.py   |   38 +++++++++++++++++++++++---------------
 meld/tree.py      |   17 +++++++++++++++++
 meld/vcview.py    |   34 ++++++++++++++++++++++------------
 4 files changed, 63 insertions(+), 27 deletions(-)
---
diff --git a/data/ui/vcview.ui b/data/ui/vcview.ui
index 1f3387d..60c5576 100644
--- a/data/ui/vcview.ui
+++ b/data/ui/vcview.ui
@@ -73,6 +73,7 @@
                     <property name="hover_expand">False</property>
                     <signal handler="on_row_activated" last_modification_time="Sat, 03 Aug 2002 23:32:49 GMT" name="row_activated"/>
                     <signal handler="on_button_press_event" last_modification_time="Sat, 30 Aug 2003 12:42:19 GMT" name="button_press_event"/>
+                    <signal handler="on_treeview_cursor_changed" name="cursor-changed" swapped="no"/>
                     <signal handler="on_treeview_popup_menu" name="popup-menu"/>
                   </object>
                 </child>
diff --git a/meld/dirdiff.py b/meld/dirdiff.py
index 8f105c3..2432de7 100644
--- a/meld/dirdiff.py
+++ b/meld/dirdiff.py
@@ -1,5 +1,5 @@
 ### Copyright (C) 2002-2006 Stephen Kennedy <stevek gnome org>
-### Copyright (C) 2009-2010 Kai Willadsen <kai willadsen gmail com>
+### Copyright (C) 2009-2011 Kai Willadsen <kai willadsen gmail com>
 
 ### 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
@@ -264,6 +264,7 @@ class DirDiff(melddoc.MeldDoc, gnomeglade.Component):
             self.focus_in_events.append(handler_id)
             handler_id = treeview.connect("focus-out-event", self.on_treeview_focus_out_event)
             self.focus_out_events.append(handler_id)
+        self.prev_path, self.next_path = None, None
         self.on_treeview_focus_out_event(None, None)
         self.treeview_focussed = None
 
@@ -322,8 +323,6 @@ class DirDiff(melddoc.MeldDoc, gnomeglade.Component):
         self._create_filter_menu_button(ui)
         self.ui_manager = ui
 
-        # FIXME: Add real sensitivity handling
-        self.emit("next-diff-changed", True, True)
         if self.treeview_focussed:
             self.scheduler.add_task(self.treeview_focussed.grab_focus)
             self.scheduler.add_task(self.on_treeview_cursor_changed)
@@ -702,6 +701,19 @@ class DirDiff(melddoc.MeldDoc, gnomeglade.Component):
         pane = self._get_focused_pane()
         if pane is None:
             return
+
+        cursor_path, cursor_col = self.treeview[pane].get_cursor()
+        if not cursor_path:
+            self.emit("next-diff-changed", False, False)
+        else:
+            # TODO: Only recalculate when needed;
+            # not self.prev_path < cursor_path < self.next_path is a start,
+            # but fails when we move off a changed row.
+            prev_path, next_path = self.model._find_next_prev_diff(cursor_path)
+            self.prev_path, self.next_path = prev_path, next_path
+            have_next_diffs = (prev_path is not None, next_path is not None)
+            self.emit("next-diff-changed", *have_next_diffs)
+
         paths = self._get_selected_paths(pane)
         if len(paths) > 0:
             def rwx(mode):
@@ -1090,20 +1102,16 @@ class DirDiff(melddoc.MeldDoc, gnomeglade.Component):
 
     def next_diff(self, direction):
         if self.treeview_focussed:
-            pane = self.treeview.index( self.treeview_focussed )
+            pane = self.treeview.index(self.treeview_focussed)
         else:
             pane = 0
-        start_iter = self.model.get_iter( (self._get_selected_paths(pane) or [(0,)])[-1] )
-
-        search = {gtk.gdk.SCROLL_UP : self.model.inorder_search_up}.get(direction, self.model.inorder_search_down)
-        for it in search( start_iter ):
-            state = self.model.get_state(it, pane)
-            if state not in (tree.STATE_NORMAL, tree.STATE_EMPTY):
-                curpath = self.model.get_path(it)
-                self.treeview[pane].expand_to_path(curpath)
-                self.treeview[pane].set_cursor(curpath)
-                return
+        if direction == gtk.gdk.SCROLL_UP:
+            path = self.prev_path
+        else:
+            path = self.next_path
+        if path:
+            self.treeview[pane].expand_to_path(path)
+            self.treeview[pane].set_cursor(path)
 
     def on_reload_activate(self, *extra):
         self.on_fileentry_activate(None)
-
diff --git a/meld/tree.py b/meld/tree.py
index d60f56e..2417f23 100644
--- a/meld/tree.py
+++ b/meld/tree.py
@@ -169,3 +169,20 @@ class DiffTreeStore(gtk.TreeStore):
                     raise StopIteration()
             yield it
 
+    def _find_next_prev_diff(self, start_path):
+        prev_path, next_path = None, None
+        start_iter = self.get_iter(start_path)
+
+        for it in self.inorder_search_up(start_iter):
+            state = self.get_state(it, 0)
+            if state not in (STATE_NORMAL, STATE_EMPTY):
+                prev_path = self.get_path(it)
+                break
+
+        for it in self.inorder_search_down(start_iter):
+            state = self.get_state(it, 0)
+            if state not in (STATE_NORMAL, STATE_EMPTY):
+                next_path = self.get_path(it)
+                break
+
+        return prev_path, next_path
diff --git a/meld/vcview.py b/meld/vcview.py
index 3c89f53..22c466e 100644
--- a/meld/vcview.py
+++ b/meld/vcview.py
@@ -1,4 +1,5 @@
 ### Copyright (C) 2002-2006 Stephen Kennedy <stevek gnome org>
+### Copyright (C) 2010-2011 Kai Willadsen <kai willadsen gmail com>
 
 ### 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
@@ -153,6 +154,7 @@ class VcView(melddoc.MeldDoc, gnomeglade.Component):
         self.treeview.get_selection().set_mode(gtk.SELECTION_MULTIPLE)
         self.treeview.set_headers_visible(1)
         self.treeview.set_search_equal_func(self.treeview_search_cb)
+        self.prev_path, self.next_path = None, None
         column = gtk.TreeViewColumn( _("Name") )
         renicon = ui.emblemcellrenderer.EmblemCellRenderer()
         rentext = gtk.CellRendererText()
@@ -211,8 +213,7 @@ class VcView(melddoc.MeldDoc, gnomeglade.Component):
 
     def on_container_switch_in_event(self, ui):
         melddoc.MeldDoc.on_container_switch_in_event(self, ui)
-        # FIXME: Add real sensitivity handling
-        self.emit("next-diff-changed", True, True)
+        self.scheduler.add_task(self.on_treeview_cursor_changed)
 
     def update_actions_sensitivity(self):
         """Disable actions that use not implemented VC plugin methods
@@ -293,6 +294,7 @@ class VcView(melddoc.MeldDoc, gnomeglade.Component):
         # need to scan the rest of the repository
         if os.path.isdir(self.vc.location):
             self.scheduler.add_task(self._search_recursively_iter(self.model.get_iter_root()).next)
+            self.scheduler.add_task(self.on_treeview_cursor_changed)
 
     def recompute_label(self):
         self.label_text = os.path.basename(self.location)
@@ -660,17 +662,25 @@ class VcView(melddoc.MeldDoc, gnomeglade.Component):
         item.show()
         menu.insert( item, 1 )
 
+    def on_treeview_cursor_changed(self, *args):
+        cursor_path, cursor_col = self.treeview.get_cursor()
+        if not cursor_path:
+            self.emit("next-diff-changed", False, False)
+        else:
+            # TODO: Only recalculate when needed; see DirDiff
+            prev_path, next_path = self.model._find_next_prev_diff(cursor_path)
+            self.prev_path, self.next_path = prev_path, next_path
+            have_next_diffs = (prev_path is not None, next_path is not None)
+            self.emit("next-diff-changed", *have_next_diffs)
+
     def next_diff(self, direction):
-        start_iter = self.model.get_iter((self._get_selected_paths() or [(0,)])[-1])
-
-        search = {gtk.gdk.SCROLL_UP : self.model.inorder_search_up}.get(direction, self.model.inorder_search_down)
-        for it in search( start_iter ):
-            state = self.model.get_state(it, 0)
-            if state not in (tree.STATE_NORMAL, tree.STATE_EMPTY):
-                curpath = self.model.get_path(it)
-                self.treeview.expand_to_path(curpath)
-                self.treeview.set_cursor(curpath)
-                return
+        if direction == gtk.gdk.SCROLL_UP:
+            path = self.prev_path
+        else:
+            path = self.next_path
+        if path:
+            self.treeview.expand_to_path(path)
+            self.treeview.set_cursor(path)
 
     def on_reload_activate(self, *extra):
         self.on_fileentry_activate(self.fileentry)



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