[meld] Add actions, toolbar and menu items, and keyboard shortcuts for merging



commit 60bfd93ecf252e9056d8c798cf58e752f40b1001
Author: Kai Willadsen <kai willadsen gmail com>
Date:   Mon Sep 28 06:33:24 2009 +1000

    Add actions, toolbar and menu items, and keyboard shortcuts for merging
    
    This commit uses the new cursor/chunk infrastructure and the
    old-but-newly-separated chunk actions to add gtk.Actions for merging files,
    and use those Actions in toolbar items and menu items. This also introduces
    keyboard shortcuts for these actions.
    
    Closes bgo#592332, and part of bgo#331523

 data/ui/filediff-ui.xml |   19 +++++++++++
 data/ui/meldapp-ui.xml  |    2 +
 meld/filediff.py        |   78 +++++++++++++++++++++++++++++++++++++++++++++-
 meld/melddoc.py         |    1 +
 4 files changed, 98 insertions(+), 2 deletions(-)
---
diff --git a/data/ui/filediff-ui.xml b/data/ui/filediff-ui.xml
index 6d18b30..2df3e7f 100644
--- a/data/ui/filediff-ui.xml
+++ b/data/ui/filediff-ui.xml
@@ -5,8 +5,27 @@
       <toolitem action="Undo"/>
       <toolitem action="Redo"/>
     </placeholder>
+    <placeholder name="SpecialActions">
+      <toolitem action="PushLeft"/>
+      <toolitem action="PushRight"/>
+      <toolitem action="PullLeft"/>
+      <toolitem action="PullRight"/>
+      <toolitem action="Delete"/>
+    </placeholder>
   </toolbar>
 
+  <menubar name="Menubar">
+    <menu action="EditMenu">
+      <placeholder name="EditActionsPlaceholder">
+        <menuitem action="PushLeft"/>
+        <menuitem action="PushRight"/>
+        <menuitem action="PullLeft"/>
+        <menuitem action="PullRight"/>
+        <menuitem action="Delete"/>
+      </placeholder>
+    </menu>
+  </menubar>
+
   <popup name="Popup">
     <menuitem action="Save" />
     <menuitem action="SaveAs" />
diff --git a/data/ui/meldapp-ui.xml b/data/ui/meldapp-ui.xml
index 68d7638..28c96b6 100644
--- a/data/ui/meldapp-ui.xml
+++ b/data/ui/meldapp-ui.xml
@@ -16,6 +16,8 @@
       <menuitem action="Copy"/>
       <menuitem action="Paste"/>
       <separator/>
+      <placeholder name="EditActionsPlaceholder" />
+      <separator/>
       <menuitem action="Find"/>
       <menuitem action="FindNext"/>
       <menuitem action="Replace"/>
diff --git a/meld/filediff.py b/meld/filediff.py
index ec123e7..294a644 100644
--- a/meld/filediff.py
+++ b/meld/filediff.py
@@ -1,4 +1,5 @@
 ### Copyright (C) 2002-2006 Stephen Kennedy <stevek gnome org>
+### Copyright (C) 2009-2010 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
@@ -177,6 +178,12 @@ class FileDiff(melddoc.MeldDoc, gnomeglade.Component):
         actions = (
             ("FileOpen",          gtk.STOCK_OPEN,       None,            None, _("Open selected"), self.on_open_activate),
             ("CreatePatch",       None,                 _("Create Patch"),  None, _("Create a patch"), self.make_patch),
+            ("PushLeft",  gtk.STOCK_GO_BACK,    _("Push to left"),    "<Alt>Left", _("Push current change to the left"), lambda x: self.push_change(-1)),
+            ("PushRight", gtk.STOCK_GO_FORWARD, _("Push to right"),   "<Alt>Right", _("Push current change to the right"), lambda x: self.push_change(1)),
+            # FIXME: using LAST and FIRST is terrible and unreliable icon abuse
+            ("PullLeft",  gtk.STOCK_GOTO_LAST,  _("Pull from left"),  "<Alt><Shift>Right", _("Pull change from the left"), lambda x: self.pull_change(-1)),
+            ("PullRight", gtk.STOCK_GOTO_FIRST, _("Pull from right"), "<Alt><Shift>Left", _("Pull change from the right"), lambda x: self.pull_change(1)),
+            ("Delete",    gtk.STOCK_DELETE,     _("Delete"),     "<Alt>Delete", _("Delete change"), self.delete_change),
             ("CopyAllLeft",       gtk.STOCK_GOTO_FIRST, _("Copy To Left"),  None, _("Copy all changes from right pane to left pane"), lambda x: self.copy_selected(-1)),
             ("CopyAllRight",      gtk.STOCK_GOTO_LAST,  _("Copy To Right"), None, _("Copy all changes from left pane to right pane"), lambda x: self.copy_selected(1)),
         )
@@ -190,6 +197,10 @@ class FileDiff(melddoc.MeldDoc, gnomeglade.Component):
         gnomeglade.connect_signal_handlers(self)
         self.findbar = self.findbar.get_data("pyobject")
         self.cursor = CursorDetails()
+        self.connect("current-diff-changed", self.on_current_diff_changed)
+        for t in self.textview:
+            t.connect("focus-in-event", self.on_current_diff_changed)
+            t.connect("focus-out-event", self.on_current_diff_changed)
 
     def on_focus_change(self):
         self.keymask = 0
@@ -249,12 +260,71 @@ class FileDiff(melddoc.MeldDoc, gnomeglade.Component):
 
         if line != self.cursor.line or force:
             chunk, prev, next = self.linediffer.locate_chunk(pane, line)
+            if chunk != self.cursor.chunk:
+                self.cursor.chunk = chunk
+                self.emit("current-diff-changed")
             if prev != self.cursor.prev or next != self.cursor.next:
                 self.emit("next-diff-changed", prev is not None,
                           next is not None)
-            self.cursor.chunk, self.cursor.prev, self.cursor.next = chunk, prev, next
+            self.cursor.prev, self.cursor.next = prev, next
         self.cursor.line, self.cursor.offset = line, offset
 
+    def on_current_diff_changed(self, widget, *args):
+        pane = self.cursor.pane
+        chunk_id = self.cursor.chunk
+        push_left, push_right, pull_left, pull_right, delete = (True,) * 5
+        if pane == -1 or chunk_id is None:
+            push_left, push_right, pull_left, pull_right, delete = (False,) * 5
+        else:
+            # Copy* and Delete are sensitive as long as there is something to
+            # copy/delete (i.e., not an empty chunk), and the direction exists.
+            if pane == 0 or pane == 2:
+                chunk = self.linediffer.get_chunk(chunk_id, pane)
+                push_left = pane == 2 and not chunk[1] == chunk[2]
+                push_right = pane == 0 and not chunk[1] == chunk[2]
+                pull_left = pane == 2 and not chunk[3] == chunk[4]
+                pull_right = pane == 0 and not chunk[3] == chunk[4]
+            elif pane == 1:
+                chunk0 = self.linediffer.get_chunk(chunk_id, pane, 0)
+                chunk2 = None
+                if self.num_panes == 3:
+                    chunk2 = self.linediffer.get_chunk(chunk_id, pane, 2)
+                push_left = chunk0 is not None and chunk0[1] != chunk0[2]
+                push_right = chunk2 is not None and chunk2[1] != chunk2[2]
+                pull_left = chunk0 is not None and not chunk0[3] == chunk0[4]
+                pull_right = chunk2 is not None and not chunk2[3] == chunk2[4]
+            delete = push_left or push_right
+        self.actiongroup.get_action("PushLeft").set_sensitive(push_left)
+        self.actiongroup.get_action("PushRight").set_sensitive(push_right)
+        self.actiongroup.get_action("PullLeft").set_sensitive(pull_left)
+        self.actiongroup.get_action("PullRight").set_sensitive(pull_right)
+        self.actiongroup.get_action("Delete").set_sensitive(delete)
+
+    def push_change(self, direction):
+        src = self._get_focused_pane()
+        dst = src + direction
+        chunk = self.linediffer.get_chunk(self.cursor.chunk, src, dst)
+        assert(src != -1 and self.cursor.chunk is not None)
+        assert(dst in (0, 1, 2))
+        assert(chunk is not None)
+        self.replace_chunk(src, dst, chunk)
+
+    def pull_change(self, direction):
+        dst = self._get_focused_pane()
+        src = dst + direction
+        chunk = self.linediffer.get_chunk(self.cursor.chunk, src, dst)
+        assert(dst != -1 and self.cursor.chunk is not None)
+        assert(src in (0, 1, 2))
+        assert(chunk is not None)
+        self.replace_chunk(src, dst, chunk)
+
+    def delete_change(self, widget):
+        pane = self._get_focused_pane()
+        chunk = self.linediffer.get_chunk(self.cursor.chunk, pane)
+        assert(pane != -1 and self.cursor.chunk is not None)
+        assert(chunk is not None)
+        self.delete_chunk(pane, chunk)
+
     def on_textview_focus_in_event(self, view, event):
         self.textview_focussed = view
         self.findbar.textview = view
@@ -264,7 +334,11 @@ class FileDiff(melddoc.MeldDoc, gnomeglade.Component):
         if self.num_panes > 1:
             pane = self.textbuffer.index(buffer)
             self.linediffer.change_sequence(pane, startline, sizechange, self._get_texts())
-            self.on_cursor_position_changed(buffer, None, True)
+            # FIXME: diff-changed signal for the current buffer would be cleaner
+            focused_pane = self._get_focused_pane()
+            if focused_pane != -1:
+                self.on_cursor_position_changed(self.textbuffer[focused_pane],
+                                                None, True)
             self.scheduler.add_task(self._update_highlighting().next)
             self.queue_draw()
 
diff --git a/meld/melddoc.py b/meld/melddoc.py
index 32223c6..4124f2d 100644
--- a/meld/melddoc.py
+++ b/meld/melddoc.py
@@ -33,6 +33,7 @@ class MeldDoc(gobject.GObject):
         'file-changed': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE, (gobject.TYPE_STRING,)),
         'create-diff': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE, (gobject.TYPE_PYOBJECT,)),
         'status-changed': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE, (gobject.TYPE_PYOBJECT,)),
+        'current-diff-changed': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE, ()),
         'next-diff-changed': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE, (bool, bool)),
     }
 



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