[meld] Notify the user when compared files are identical
- From: Kai Willadsen <kaiw src gnome org>
- To: svn-commits-list gnome org
- Subject: [meld] Notify the user when compared files are identical
- Date: Thu, 2 Jul 2009 01:11:51 +0000 (UTC)
commit f57babe725f92a05b47ce7ceaa512e9f7b8ba43d
Author: Kai Willadsen <kai willadsen gmail com>
Date: Mon Jun 29 11:26:07 2009 +1000
Notify the user when compared files are identical
Using the MsgArea python port taken from hotssh, we display a message when
there are no differences found between the compared files.
Fixes part of bgo#458372.
diffutil.py | 3 +
filediff.py | 22 +++++-
glade2/filediff.glade | 84 ++++++++++++++---
msgarea.py | 237 +++++++++++++++++++++++++++++++++++++++++++++++++
4 files changed, 330 insertions(+), 16 deletions(-)
---
diff --git a/diffutil.py b/diffutil.py
index 99077a6..8f9c63b 100644
--- a/diffutil.py
+++ b/diffutil.py
@@ -158,6 +158,9 @@ class Differ(object):
elif cs[1]:
yield cs[1] + (2,)
+ def sequences_identical(self):
+ return self.diffs == [[], []]
+
def _merge_blocks(self, using):
LO, HI = 1,2
lowc = min(using[0][ 0][LO], using[1][ 0][LO])
diff --git a/filediff.py b/filediff.py
index f5617bb..1e62eea 100644
--- a/filediff.py
+++ b/filediff.py
@@ -30,6 +30,7 @@ import diffutil
import gnomeglade
import misc
import melddoc
+import msgarea
import paths
import cairo
@@ -64,7 +65,7 @@ class FileDiff(melddoc.MeldDoc, gnomeglade.Component):
"""
melddoc.MeldDoc.__init__(self, prefs)
gnomeglade.Component.__init__(self, paths.share_dir("glade2/filediff.glade"), "filediff", srcviewer.override)
- self.map_widgets_into_lists( ["textview", "fileentry", "diffmap", "scrolledwindow", "linkmap", "statusimage"] )
+ self.map_widgets_into_lists( ["textview", "fileentry", "diffmap", "scrolledwindow", "linkmap", "statusimage", "msgarea_mgr"] )
self._update_regexes()
self.warned_bad_comparison = False
if srcviewer:
@@ -593,6 +594,19 @@ class FileDiff(melddoc.MeldDoc, gnomeglade.Component):
step = self.linediffer.set_sequences_iter(*lines)
while step.next() == None:
yield 1
+
+ if self.num_panes > 1 and self.linediffer.sequences_identical():
+ for index, mgr in enumerate(self.msgarea_mgr):
+ msgarea = mgr.new_from_text_and_icon(gtk.STOCK_INFO,
+ _("Files are identical"))
+ button = msgarea.add_stock_button_with_text(_("Hide"),
+ gtk.STOCK_CLOSE,
+ gtk.RESPONSE_CLOSE)
+ if index == 0:
+ button.props.label = _("Hi_de")
+ msgarea.connect("response", self.on_msgarea_identical_response)
+ msgarea.show_all()
+
self.scheduler.add_task( lambda: self.next_diff(gdk.SCROLL_DOWN, jump_to_first=True), True )
self.queue_draw()
self.scheduler.add_task(self._update_highlighting().next)
@@ -603,6 +617,10 @@ class FileDiff(melddoc.MeldDoc, gnomeglade.Component):
srcviewer.set_highlighting_enabled_from_file(self.textbuffer[i], files[i], self.prefs.use_syntax_highlighting)
yield 0
+ def on_msgarea_identical_response(self, msgarea, respid):
+ for mgr in self.msgarea_mgr:
+ mgr.clear()
+
def _update_highlighting(self):
for b in self.textbuffer:
taglist = ["delete line", "conflict line", "replace line", "inline line"]
@@ -1019,10 +1037,12 @@ class FileDiff(melddoc.MeldDoc, gnomeglade.Component):
if n != self.num_panes and n in (1,2,3):
self.num_panes = n
toshow = self.scrolledwindow[:n] + self.fileentry[:n]
+ toshow += self.msgarea_mgr[:n]
toshow += self.linkmap[:n-1] + self.diffmap[:n]
map( lambda x: x.show(), toshow )
tohide = self.statusimage + self.scrolledwindow[n:] + self.fileentry[n:]
+ tohide += self.msgarea_mgr[n:]
tohide += self.linkmap[n-1:] + self.diffmap[n:]
map( lambda x: x.hide(), tohide )
diff --git a/glade2/filediff.glade b/glade2/filediff.glade
index 05b8f3d..0dbffc5 100644
--- a/glade2/filediff.glade
+++ b/glade2/filediff.glade
@@ -12,7 +12,7 @@
<child>
<widget class="GtkTable" id="table">
<property name="visible">True</property>
- <property name="n_rows">2</property>
+ <property name="n_rows">3</property>
<property name="n_columns">7</property>
<child>
<placeholder/>
@@ -83,8 +83,8 @@
<packing>
<property name="left_attach">1</property>
<property name="right_attach">2</property>
- <property name="top_attach">1</property>
- <property name="bottom_attach">2</property>
+ <property name="top_attach">2</property>
+ <property name="bottom_attach">3</property>
</packing>
</child>
<child>
@@ -145,8 +145,8 @@
<packing>
<property name="left_attach">5</property>
<property name="right_attach">6</property>
- <property name="top_attach">1</property>
- <property name="bottom_attach">2</property>
+ <property name="top_attach">2</property>
+ <property name="bottom_attach">3</property>
</packing>
</child>
<child>
@@ -169,8 +169,8 @@
<packing>
<property name="left_attach">3</property>
<property name="right_attach">4</property>
- <property name="top_attach">1</property>
- <property name="bottom_attach">2</property>
+ <property name="top_attach">2</property>
+ <property name="bottom_attach">3</property>
</packing>
</child>
<child>
@@ -184,8 +184,8 @@
<packing>
<property name="left_attach">6</property>
<property name="right_attach">7</property>
- <property name="top_attach">1</property>
- <property name="bottom_attach">2</property>
+ <property name="top_attach">2</property>
+ <property name="bottom_attach">3</property>
<property name="x_options">GTK_FILL</property>
<property name="y_options">GTK_FILL</property>
</packing>
@@ -207,8 +207,8 @@
<packing>
<property name="left_attach">2</property>
<property name="right_attach">3</property>
- <property name="top_attach">1</property>
- <property name="bottom_attach">2</property>
+ <property name="top_attach">2</property>
+ <property name="bottom_attach">3</property>
<property name="x_options">GTK_FILL</property>
<property name="y_options">GTK_FILL</property>
</packing>
@@ -222,8 +222,8 @@
<signal name="button_press_event" handler="on_diffmap_button_press_event"/>
</widget>
<packing>
- <property name="top_attach">1</property>
- <property name="bottom_attach">2</property>
+ <property name="top_attach">2</property>
+ <property name="bottom_attach">3</property>
<property name="x_options">GTK_FILL</property>
</packing>
</child>
@@ -244,12 +244,66 @@
<packing>
<property name="left_attach">4</property>
<property name="right_attach">5</property>
- <property name="top_attach">1</property>
- <property name="bottom_attach">2</property>
+ <property name="top_attach">2</property>
+ <property name="bottom_attach">3</property>
<property name="x_options">GTK_FILL</property>
<property name="y_options">GTK_FILL</property>
</packing>
</child>
+ <child>
+ <widget class="Custom" id="msgarea_mgr0">
+ <property name="visible">True</property>
+ <property name="creation_function">msgarea.msgarea_mgr_create</property>
+ </widget>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="top_attach">1</property>
+ <property name="bottom_attach">2</property>
+ <property name="y_options">GTK_SHRINK | GTK_FILL</property>
+ </packing>
+ </child>
+ <child>
+ <widget class="Custom" id="msgarea_mgr1">
+ <property name="visible">True</property>
+ <property name="creation_function">msgarea.msgarea_mgr_create</property>
+ </widget>
+ <packing>
+ <property name="left_attach">3</property>
+ <property name="right_attach">4</property>
+ <property name="top_attach">1</property>
+ <property name="bottom_attach">2</property>
+ <property name="y_options">GTK_SHRINK | GTK_FILL</property>
+ </packing>
+ </child>
+ <child>
+ <widget class="Custom" id="msgarea_mgr2">
+ <property name="visible">True</property>
+ <property name="creation_function">msgarea.msgarea_mgr_create</property>
+ </widget>
+ <packing>
+ <property name="left_attach">5</property>
+ <property name="right_attach">6</property>
+ <property name="top_attach">1</property>
+ <property name="bottom_attach">2</property>
+ <property name="y_options">GTK_SHRINK | GTK_FILL</property>
+ </packing>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
</widget>
</child>
<child>
diff --git a/msgarea.py b/msgarea.py
new file mode 100644
index 0000000..14dcd36
--- /dev/null
+++ b/msgarea.py
@@ -0,0 +1,237 @@
+# This file is part of the Hotwire Shell user interface.
+#
+# Copyright (C) 2007,2008 Colin Walters <walters verbum org>
+#
+# 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
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+import os, sys, re, logging, string
+
+import gtk, gobject, pango
+
+_logger = logging.getLogger("hotwire.ui.MsgArea")
+
+# This file is a Python translation of gedit/gedit/gedit-message-area.c
+
+class MsgArea(gtk.HBox):
+ __gsignals__ = {
+ "response" : (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, (gobject.TYPE_INT,)),
+ "close" : (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, [])
+ }
+
+ def __init__(self, buttons, **kwargs):
+ super(MsgArea, self).__init__(**kwargs)
+
+ self.__contents = None
+ self.__changing_style = False
+
+ self.__main_hbox = gtk.HBox(False, 16) # FIXME: use style properties
+ self.__main_hbox.show()
+ self.__main_hbox.set_border_width(8) # FIXME: use style properties
+
+ self.__action_area = gtk.HBox(True, 4); # FIXME: use style properties
+ self.__action_area.show()
+ self.__main_hbox.pack_end (self.__action_area, False, True, 0)
+
+ self.pack_start(self.__main_hbox, True, True, 0)
+
+ self.set_app_paintable(True)
+
+ self.connect("expose-event", self.__paint)
+
+ # Note that we connect to style-set on one of the internal
+ # widgets, not on the message area itself, since gtk does
+ # not deliver any further style-set signals for a widget on
+ # which the style has been forced with gtk_widget_set_style()
+ self.__main_hbox.connect("style-set", self.__on_style_set)
+
+ self.add_buttons(buttons)
+
+ def __get_response_data(self, w, create):
+ d = w.get_data('hotwire-msg-area-data')
+ if (d is None) and create:
+ d = {'respid': None}
+ w.set_data('hotwire-msg-area-data', d)
+ return d
+
+ def __find_button(self, respid):
+ children = self.__actionarea.get_children()
+ for child in children:
+ rd = self.__get_response_data(child, False)
+ if rd is not None and rd['respid'] == respid:
+ return child
+
+ def __close(self):
+ cancel = self.__find_button(gtk.RESPONSE_CANCEL)
+ if cancel is None:
+ return
+ self.response(gtk.RESPONSE_CANCEL)
+
+ def __paint(self, w, event):
+ gtk.Style.paint_flat_box(w.style,
+ w.window,
+ gtk.STATE_NORMAL,
+ gtk.SHADOW_OUT,
+ None,
+ w,
+ "tooltip",
+ w.allocation.x + 1,
+ w.allocation.y + 1,
+ w.allocation.width - 2,
+ w.allocation.height - 2)
+
+ return False
+
+ def __on_style_set(self, w, style):
+ if self.__changing_style:
+ return
+ # This is a hack needed to use the tooltip background color
+ window = gtk.Window(gtk.WINDOW_POPUP);
+ window.set_name("gtk-tooltip")
+ window.ensure_style()
+ style = window.get_style()
+
+ self.__changing_style = True
+ self.set_style(style)
+ self.__changing_style = False
+
+ window.destroy()
+
+ self.queue_draw()
+
+ def __get_response_for_widget(self, w):
+ rd = self.__get_response_data(w, False)
+ if rd is None:
+ return gtk.RESPONSE_NONE
+ return rd['respid']
+
+ def __on_action_widget_activated(self, w):
+ response_id = self.__get_response_for_widget(w)
+ self.response(response_id)
+
+ def add_action_widget(self, child, respid):
+ rd = self.__get_response_data(child, True)
+ rd['respid'] = respid
+ if not isinstance(child, gtk.Button):
+ raise ValueError("Can only pack buttons as action widgets")
+ child.connect('clicked', self.__on_action_widget_activated)
+ if respid != gtk.RESPONSE_HELP:
+ self.__action_area.pack_start(child, False, False, 0)
+ else:
+ self.__action_area.pack_end(child, False, False, 0)
+
+ def set_contents(self, contents):
+ self.__contents = contents
+ self.__main_hbox.pack_start(contents, True, True, 0)
+
+
+ def add_button(self, btext, respid):
+ button = gtk.Button(stock=btext)
+ button.set_focus_on_click(False)
+ button.set_flags(gtk.CAN_DEFAULT)
+ button.show()
+ self.add_action_widget(button, respid)
+ return button
+
+ def add_buttons(self, args):
+ _logger.debug("init buttons: %r", args)
+ for (btext, respid) in args:
+ self.add_button(btext, respid)
+
+ def set_response_sensitive(self, respid, setting):
+ for child in self.__action_area.get_children():
+ rd = self.__get_response_data(child, False)
+ if rd is not None and rd['respid'] == respid:
+ child.set_sensitive(setting)
+ break
+
+ def set_default_response(self, respid):
+ for child in self.__action_area.get_children():
+ rd = self.__get_response_data(child, False)
+ if rd is not None and rd['respid'] == respid:
+ child.grab_default()
+ break
+
+ def response(self, respid):
+ self.emit('response', respid)
+
+ def add_stock_button_with_text(self, text, stockid, respid):
+ b = gtk.Button(label=text)
+ b.set_focus_on_click(False)
+ img = gtk.Image()
+ img.set_from_stock(stockid, gtk.ICON_SIZE_BUTTON)
+ b.set_image(img)
+ b.show_all()
+ self.add_action_widget(b, respid)
+ return b
+
+ def set_text_and_icon(self, stockid, primary_text, secondary_text=None):
+ hbox_content = gtk.HBox(False, 8)
+ hbox_content.show()
+
+ image = gtk.Image()
+ image.set_from_stock(stockid, gtk.ICON_SIZE_BUTTON)
+ image.show()
+ hbox_content.pack_start(image, False, False, 0)
+ image.set_alignment(0.5, 0.5)
+
+ vbox = gtk.VBox(False, 6)
+ vbox.show()
+ hbox_content.pack_start (vbox, True, True, 0)
+
+ primary_markup = "<b>%s</b>" % (primary_text,)
+ primary_label = gtk.Label(primary_markup)
+ primary_label.show()
+ vbox.pack_start(primary_label, True, True, 0)
+ primary_label.set_use_markup(True)
+ primary_label.set_line_wrap(True)
+ primary_label.set_alignment(0, 0.5)
+ primary_label.set_flags(gtk.CAN_FOCUS)
+ primary_label.set_selectable(True)
+
+ if secondary_text:
+ secondary_markup = "<small>%s</small>" % (secondary_text,)
+ secondary_label = gtk.Label(secondary_markup)
+ secondary_label.show()
+ vbox.pack_start(secondary_label, True, True, 0)
+ secondary_label.set_flags(gtk.CAN_FOCUS)
+ secondary_label.set_use_markup(True)
+ secondary_label.set_line_wrap(True)
+ secondary_label.set_selectable(True)
+ secondary_label.set_alignment(0, 0.5)
+
+ self.set_contents(hbox_content)
+
+class MsgAreaController(gtk.HBox):
+ def __init__(self):
+ super(MsgAreaController, self).__init__()
+
+ self.__msgarea = None
+
+ def clear(self):
+ if self.__msgarea is not None:
+ self.remove(self.__msgarea)
+ self.__msgarea.destroy()
+ self.__msgarea = None
+
+ def new_from_text_and_icon(self, stockid, primary, secondary=None, buttons=[]):
+ self.clear()
+ msgarea = self.__msgarea = MsgArea(buttons)
+ msgarea.set_text_and_icon(stockid, primary, secondary)
+ self.pack_start(msgarea, expand=True)
+ return msgarea
+
+def msgarea_mgr_create(str1, str2, int1, int2):
+ return MsgAreaController()
+
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]