Commit f57babe7 authored by Kai Willadsen's avatar Kai Willadsen

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.
parent e7b4ba9e
...@@ -158,6 +158,9 @@ class Differ(object): ...@@ -158,6 +158,9 @@ class Differ(object):
elif cs[1]: elif cs[1]:
yield cs[1] + (2,) yield cs[1] + (2,)
def sequences_identical(self):
return self.diffs == [[], []]
def _merge_blocks(self, using): def _merge_blocks(self, using):
LO, HI = 1,2 LO, HI = 1,2
lowc = min(using[0][ 0][LO], using[1][ 0][LO]) lowc = min(using[0][ 0][LO], using[1][ 0][LO])
......
...@@ -30,6 +30,7 @@ import diffutil ...@@ -30,6 +30,7 @@ import diffutil
import gnomeglade import gnomeglade
import misc import misc
import melddoc import melddoc
import msgarea
import paths import paths
import cairo import cairo
...@@ -64,7 +65,7 @@ class FileDiff(melddoc.MeldDoc, gnomeglade.Component): ...@@ -64,7 +65,7 @@ class FileDiff(melddoc.MeldDoc, gnomeglade.Component):
""" """
melddoc.MeldDoc.__init__(self, prefs) melddoc.MeldDoc.__init__(self, prefs)
gnomeglade.Component.__init__(self, paths.share_dir("glade2/filediff.glade"), "filediff", srcviewer.override) 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._update_regexes()
self.warned_bad_comparison = False self.warned_bad_comparison = False
if srcviewer: if srcviewer:
...@@ -593,6 +594,19 @@ class FileDiff(melddoc.MeldDoc, gnomeglade.Component): ...@@ -593,6 +594,19 @@ class FileDiff(melddoc.MeldDoc, gnomeglade.Component):
step = self.linediffer.set_sequences_iter(*lines) step = self.linediffer.set_sequences_iter(*lines)
while step.next() == None: while step.next() == None:
yield 1 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.scheduler.add_task( lambda: self.next_diff(gdk.SCROLL_DOWN, jump_to_first=True), True )
self.queue_draw() self.queue_draw()
self.scheduler.add_task(self._update_highlighting().next) self.scheduler.add_task(self._update_highlighting().next)
...@@ -603,6 +617,10 @@ class FileDiff(melddoc.MeldDoc, gnomeglade.Component): ...@@ -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) srcviewer.set_highlighting_enabled_from_file(self.textbuffer[i], files[i], self.prefs.use_syntax_highlighting)
yield 0 yield 0
def on_msgarea_identical_response(self, msgarea, respid):
for mgr in self.msgarea_mgr:
mgr.clear()
def _update_highlighting(self): def _update_highlighting(self):
for b in self.textbuffer: for b in self.textbuffer:
taglist = ["delete line", "conflict line", "replace line", "inline line"] taglist = ["delete line", "conflict line", "replace line", "inline line"]
...@@ -1019,10 +1037,12 @@ class FileDiff(melddoc.MeldDoc, gnomeglade.Component): ...@@ -1019,10 +1037,12 @@ class FileDiff(melddoc.MeldDoc, gnomeglade.Component):
if n != self.num_panes and n in (1,2,3): if n != self.num_panes and n in (1,2,3):
self.num_panes = n self.num_panes = n
toshow = self.scrolledwindow[:n] + self.fileentry[:n] toshow = self.scrolledwindow[:n] + self.fileentry[:n]
toshow += self.msgarea_mgr[:n]
toshow += self.linkmap[:n-1] + self.diffmap[:n] toshow += self.linkmap[:n-1] + self.diffmap[:n]
map( lambda x: x.show(), toshow ) map( lambda x: x.show(), toshow )
tohide = self.statusimage + self.scrolledwindow[n:] + self.fileentry[n:] tohide = self.statusimage + self.scrolledwindow[n:] + self.fileentry[n:]
tohide += self.msgarea_mgr[n:]
tohide += self.linkmap[n-1:] + self.diffmap[n:] tohide += self.linkmap[n-1:] + self.diffmap[n:]
map( lambda x: x.hide(), tohide ) map( lambda x: x.hide(), tohide )
......
...@@ -12,7 +12,7 @@ ...@@ -12,7 +12,7 @@
<child> <child>
<widget class="GtkTable" id="table"> <widget class="GtkTable" id="table">
<property name="visible">True</property> <property name="visible">True</property>
<property name="n_rows">2</property> <property name="n_rows">3</property>
<property name="n_columns">7</property> <property name="n_columns">7</property>
<child> <child>
<placeholder/> <placeholder/>
...@@ -83,8 +83,8 @@ ...@@ -83,8 +83,8 @@
<packing> <packing>
<property name="left_attach">1</property> <property name="left_attach">1</property>
<property name="right_attach">2</property> <property name="right_attach">2</property>
<property name="top_attach">1</property> <property name="top_attach">2</property>
<property name="bottom_attach">2</property> <property name="bottom_attach">3</property>
</packing> </packing>
</child> </child>
<child> <child>
...@@ -145,8 +145,8 @@ ...@@ -145,8 +145,8 @@
<packing> <packing>
<property name="left_attach">5</property> <property name="left_attach">5</property>
<property name="right_attach">6</property> <property name="right_attach">6</property>
<property name="top_attach">1</property> <property name="top_attach">2</property>
<property name="bottom_attach">2</property> <property name="bottom_attach">3</property>
</packing> </packing>
</child> </child>
<child> <child>
...@@ -169,8 +169,8 @@ ...@@ -169,8 +169,8 @@
<packing> <packing>
<property name="left_attach">3</property> <property name="left_attach">3</property>
<property name="right_attach">4</property> <property name="right_attach">4</property>
<property name="top_attach">1</property> <property name="top_attach">2</property>
<property name="bottom_attach">2</property> <property name="bottom_attach">3</property>
</packing> </packing>
</child> </child>
<child> <child>
...@@ -184,8 +184,8 @@ ...@@ -184,8 +184,8 @@
<packing> <packing>
<property name="left_attach">6</property> <property name="left_attach">6</property>
<property name="right_attach">7</property> <property name="right_attach">7</property>
<property name="top_attach">1</property> <property name="top_attach">2</property>
<property name="bottom_attach">2</property> <property name="bottom_attach">3</property>
<property name="x_options">GTK_FILL</property> <property name="x_options">GTK_FILL</property>
<property name="y_options">GTK_FILL</property> <property name="y_options">GTK_FILL</property>
</packing> </packing>
...@@ -207,8 +207,8 @@ ...@@ -207,8 +207,8 @@
<packing> <packing>
<property name="left_attach">2</property> <property name="left_attach">2</property>
<property name="right_attach">3</property> <property name="right_attach">3</property>
<property name="top_attach">1</property> <property name="top_attach">2</property>
<property name="bottom_attach">2</property> <property name="bottom_attach">3</property>
<property name="x_options">GTK_FILL</property> <property name="x_options">GTK_FILL</property>
<property name="y_options">GTK_FILL</property> <property name="y_options">GTK_FILL</property>
</packing> </packing>
...@@ -222,8 +222,8 @@ ...@@ -222,8 +222,8 @@
<signal name="button_press_event" handler="on_diffmap_button_press_event"/> <signal name="button_press_event" handler="on_diffmap_button_press_event"/>
</widget> </widget>
<packing> <packing>
<property name="top_attach">1</property> <property name="top_attach">2</property>
<property name="bottom_attach">2</property> <property name="bottom_attach">3</property>
<property name="x_options">GTK_FILL</property> <property name="x_options">GTK_FILL</property>
</packing> </packing>
</child> </child>
...@@ -244,12 +244,66 @@ ...@@ -244,12 +244,66 @@
<packing> <packing>
<property name="left_attach">4</property> <property name="left_attach">4</property>
<property name="right_attach">5</property> <property name="right_attach">5</property>
<property name="top_attach">1</property> <property name="top_attach">2</property>
<property name="bottom_attach">2</property> <property name="bottom_attach">3</property>
<property name="x_options">GTK_FILL</property> <property name="x_options">GTK_FILL</property>
<property name="y_options">GTK_FILL</property> <property name="y_options">GTK_FILL</property>
</packing> </packing>
</child> </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> </widget>
</child> </child>
<child> <child>
......
# 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()
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment