[gedit-plugins] git: Correctly update the view activatable



commit c3cbeb1f9473615c37c09e4b978e7d90106fe530
Author: Garrett Regier <garrettregier gmail com>
Date:   Sun Aug 17 19:48:30 2014 -0700

    git: Correctly update the view activatable
    
    Don't just rediff the repository's contents when the focus is
    returned to the window and update the view when the file
    monitor emits a changed event for the location. Finally,
    disable the file monitors when the window loses focus and
    then do a full update when it returns. This prevents us
    from doing pointless updates and allows us to react to git
    commands made while the window didn't have focus.

 plugins/git/git/viewactivatable.py   |   14 +++++---
 plugins/git/git/windowactivatable.py |   58 +++++++++++++++++++++++++++------
 2 files changed, 56 insertions(+), 16 deletions(-)
---
diff --git a/plugins/git/git/viewactivatable.py b/plugins/git/git/viewactivatable.py
index 68ba6c8..e32a163 100644
--- a/plugins/git/git/viewactivatable.py
+++ b/plugins/git/git/viewactivatable.py
@@ -55,9 +55,10 @@ class GitViewActivatable(GObject.Object, Gedit.ViewActivatable):
         self.diff_renderer = DiffRenderer()
         self.gutter = self.view.get_gutter(Gtk.TextWindowType.LEFT)
 
+        # Note: GitWindowActivatable will call
+        #       update_location() for us when needed
         self.view_signals = [
-            self.view.connect('notify::buffer', self.on_notify_buffer),
-            self.view.connect('focus-in-event', self.update_location)
+            self.view.connect('notify::buffer', self.on_notify_buffer)
         ]
 
         self.buffer = None
@@ -94,15 +95,18 @@ class GitViewActivatable(GObject.Object, Gedit.ViewActivatable):
 
         self.buffer = view.get_buffer()
 
-        # The changed signal is connected to in update_location()
+        # The changed signal is connected to in update_location().
+        # The saved signal is pointless as the window activatable
+        # will see the change and call update_location().
         self.buffer_signals = [
-            self.buffer.connect('loaded', self.update_location),
-            self.buffer.connect('saved', self.update_location)
+            self.buffer.connect('loaded', self.update_location)
         ]
 
         # We wait and let the loaded signal call
         # update_location() as the buffer is currently empty
 
+    # TODO: This can be called many times and by idles,
+    #       should instead do the work in another thread
     def update_location(self, *args):
         self.location = self.buffer.get_file().get_location()
 
diff --git a/plugins/git/git/windowactivatable.py b/plugins/git/git/windowactivatable.py
index db07c28..b200cbf 100644
--- a/plugins/git/git/windowactivatable.py
+++ b/plugins/git/git/windowactivatable.py
@@ -141,11 +141,13 @@ class GitWindowActivatable(GObject.Object, Gedit.WindowActivatable):
 
         self.file_nodes = FileNodes()
         self.monitors = {}
+        self.has_focus = True
 
         self.gobject_signals = {
             self.window: [
                 self.window.connect('tab-removed', self.tab_removed),
-                self.window.connect('focus-in-event', self.focus_in_event)
+                self.window.connect('focus-in-event', self.focus_in_event),
+                self.window.connect('focus-out-event', self.focus_out_event)
             ],
 
             # GeditMessageBus.connect() shadows GObject.connect()
@@ -242,16 +244,30 @@ class GitWindowActivatable(GObject.Object, Gedit.WindowActivatable):
             self.git_status_thread.push(repo, location)
 
     def focus_in_event(self, window, event):
+        # Enables the file monitors so they can cause things
+        # to update again. We disabled them when the focus
+        # was lost and we will instead do a full update now.
+        self.has_focus = True
+
         self.app_activatable.clear_repositories()
 
         for view_activatable in self.view_activatables:
-            view_activatable.update()
+            # Must reload the location's contents, not just rediff
+            GLib.idle_add(view_activatable.update_location)
 
         for location in self.file_nodes:
+            # Still need to update the git status
+            # as the file could now be in .gitignore
             repo = self.get_repository(location)
             if repo is not None:
                 self.git_status_thread.push(repo, location)
 
+    def focus_out_event(self, window, event):
+        # Disables the file monitors so they don't
+        # cause anything to update. We will do a
+        # full update when we have focus again.
+        self.has_focus = False
+
     def unregistered(self, bus, object_path, method):
         # Avoid warnings like crazy if the file browser becomes disabled
         if object_path == '/plugins/filebrowser' and method == 'root_changed':
@@ -351,14 +367,34 @@ class GitWindowActivatable(GObject.Object, Gedit.WindowActivatable):
         self.monitors[location.get_uri()] = monitor
         monitor.connect('changed', self.monitor_changed)
 
-    def monitor_changed(self, monitor, file, other_file, event_type):
-        # Only monitor for changes as the file browser will monitor
-        # file created and deleted files and emit inserted and deleted
-        if event_type == Gio.FileMonitorEvent.CHANGED:
-            for f in (file, other_file):
-                if f is not None and f in self.file_nodes:
-                    repo = self.get_repository(f)
-                    if repo is not None:
-                        self.git_status_thread.push(repo, f)
+    def monitor_changed(self, monitor, file_a, file_b, event_type):
+        # Don't update anything as we will do
+        # a full update when we have focus again
+        if not self.has_focus:
+            return
+
+        # Only monitor for changes as the file browser
+        # will emit signals for the other event types
+        if event_type != Gio.FileMonitorEvent.CHANGED:
+            return
+
+        for f in (file_a, file_b):
+            if f is None:
+                continue
+
+            # Must let the view activatable know
+            # that its location's contents have changed
+            view_activatable = self.get_view_activatable_by_location(f)
+            if view_activatable is not None:
+                # Must reload the location's contents, not just rediff
+                GLib.idle_add(view_activatable.update_location)
+
+                # Still need to update the git status
+                # as the file could now be in .gitignore
+
+            if f in self.file_nodes:
+                repo = self.get_repository(f)
+                if repo is not None:
+                    self.git_status_thread.push(repo, f)
 
 # ex:ts=4:et:


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