Commit 970df745 authored by steve9000's avatar steve9000

Fix scrolling bug after the last difference.

Changed notebook label handling to use signals from the component.
Add modified marker to file labels.
Fixed button pixmaps.
parent 75b6ef61
* make textview drop destination for files (but dont lose text d&d)
*
* make textview drop destination for files from file manager (but dont lose text d&d)
* fix diff3 view - conflicting lines sometimes incorrectly displayed
* add diff3 merge bar - only currently in diff2 view
* add diff3 automerge - works like cvs update
* add CVS,SVN browser pane
* add directory diff{2,3}
* write proper user documentation
* write proper webpage with more screenshots
* visibly mark buffers as modified
* accessibility
* i18n
#! python
import math
import gtk
import gobject
import diffutil
import gnomeglade
import misc
import undo
#XXX
import difflib
################################################################################
#
# Local Functions
......@@ -59,6 +63,20 @@ class BufferDeletionAction:
def redo(self):
b = self.buffer
b.delete( b.get_iter_at_offset( self.offset), b.get_iter_at_offset(self.offset + len(self.text)) )
################################################################################
#
# BufferModifiedAction
#
################################################################################
class BufferModifiedAction:
"""A helper set modified flag on a text buffer"""
def __init__(self, buffer, app):
self.buffer, self.app = buffer, app
self.app.set_buffer_modified(self.buffer, 1)
def undo(self):
self.app.set_buffer_modified(self.buffer, 0)
def redo(self):
self.app.set_buffer_modified(self.buffer, 1)
################################################################################
#
......@@ -68,6 +86,10 @@ class BufferDeletionAction:
class FileDiff(gnomeglade.Component):
"""Two or three way diff of text files"""
__gsignals__ = {
'label-changed': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE, (gobject.TYPE_STRING,))
}
def __init__(self, numpanes, statusbar):
self.__gobject_init__()
gnomeglade.Component.__init__(self, misc.appdir("glade2/filediff.glade"), "filediff")
......@@ -105,15 +127,25 @@ class FileDiff(gnomeglade.Component):
self.undosequence.begin_group()
def on_text_end_user_action(self, *buffer):
self.undosequence.end_group()
def on_text_insert_text(self, buffer, iter, text, textlen):
if not self.undosequence_busy:
self.undosequence.begin_group()
if buffer.get_data("modified") != 1:
self.undosequence.add_action( BufferModifiedAction(buffer, self) )
self.undosequence.add_action( BufferInsertionAction(buffer, iter.get_offset(), text) )
self.undosequence.end_group()
self._queue_refresh()
def on_text_delete_range(self, buffer, iter0, iter1):
if not self.undosequence_busy:
self.undosequence.begin_group()
if buffer.get_data("modified") != 1:
self.undosequence.add_action( BufferModifiedAction(buffer, self) )
text = buffer.get_text(iter0, iter1, 0)
self.undosequence.add_action( BufferDeletionAction(buffer, iter0.get_offset(), text) )
self.undosequence.end_group()
self._queue_refresh()
def undo(self):
if self.undosequence.can_undo():
self.undosequence_busy = 1
......@@ -144,6 +176,16 @@ class FileDiff(gnomeglade.Component):
entry.set_filename(filename)
view.set_editable(editable)
self.undosequence.clear()
self.set_buffer_modified(buffer, 0)
def label_changed(self):
filenames = []
for i in range(self.numpanes):
f = self.fileentry[i].get_full_path(0) or ""
m = self.textview[i].get_buffer().get_data("modified") and "*" or ""
filenames.append( f+m )
labeltext = " : ".join( misc.shorten_names(*filenames)) + " "
self.emit("label-changed", labeltext)
def set_file(self, filename, pane):
self.fileentry[pane].set_filename(filename)
......@@ -165,9 +207,14 @@ class FileDiff(gnomeglade.Component):
status = "Error writing to %s (%s)." % (name,e)
else:
self.undosequence.clear()
self.set_buffer_modified(buf, 0)
status = "Saved %s." % name
self.statusbar.add_status(status)
def set_buffer_modified(self, buf, yesno):
buf.set_data("modified", yesno)
self.label_changed()
def save(self):
for i in range(self.numpanes):
t = self.textview[i]
......@@ -250,7 +297,7 @@ class FileDiff(gnomeglade.Component):
line /= (adjustment.upper - adjustment.lower)
for (i,adj) in others:
mbegin,mend, obegin,oend = 0,0,0,0
mbegin,mend, obegin,oend = 0, self._get_line_count(master), 0, self._get_line_count(i)
# look for the chunk containing 'line'
for c in self.linediffs.pair_changes(master, i):
c = c[1:]
......@@ -477,7 +524,7 @@ class FileDiff(gnomeglade.Component):
if f0>htotal: # we've gone past last visible
break
if f0 < event.y and event.y < f0 + ph:
self.pixbuf1.render_to_drawable( window, gcfg, 0,0, 0, f0, -1,-1, 0,0,0)
#self.pixbuf1.render_to_drawable( window, gcfg, 0,0, 0, f0, -1,-1, 0,0,0)
self.mouse_chunk = (0, c)
break
else:
......@@ -491,7 +538,7 @@ class FileDiff(gnomeglade.Component):
if t0>htotal: # we've gone past last visible
break
if t0 < event.y and event.y < t0 + ph:
self.pixbuf0.render_to_drawable( window, gcfg, 0,0, wtotal-pw, t0, -1,-1, 0,0,0)
#self.pixbuf0.render_to_drawable( window, gcfg, 0,0, wtotal-pw, t0, -1,-1, 0,0,0)
self.mouse_chunk = (1, c)
break
......@@ -530,3 +577,4 @@ class FileDiff(gnomeglade.Component):
self._queue_refresh(0)
self.mouse_chunk = None
gobject.type_register(FileDiff)
/* XPM */
static char * apply1_xpm[] = {
"21 16 81 1",
"21 16 77 1",
" c None",
". c #FFFFFF",
"+ c #F9F9F9",
"@ c #EBEBEB",
"# c #EEEEEE",
"$ c #F6F6F6",
"% c #FCFCFC",
"& c #F0F0F0",
"* c #E5E5E5",
"= c #E0E0E0",
"- c #787978",
"; c #989898",
"> c #C7C7C7",
", c #BFBFBF",
"' c #A6A7A6",
") c #858585",
"! c #646464",
"~ c #464646",
"{ c #2E2F2E",
"] c #343434",
"^ c #717271",
"/ c #BBBBBB",
"( c #666766",
"_ c #5F605F",
": c #494A49",
"< c #2D2D2D",
"[ c #070707",
"} c #2A2A2A",
"| c #272727",
"1 c #202020",
"2 c #6B6B6B",
"3 c #C9C9C9",
"4 c #727372",
"5 c #4E4F4E",
"6 c #1B1B1B",
"7 c #2B2B2B",
"8 c #262626",
"9 c #060606",
"0 c #282828",
"a c #171717",
"b c #131313",
"c c #1C1C1C",
"d c #707170",
"e c #474747",
"f c #0B0B0B",
"g c #252525",
"h c #F8F8F8",
"i c #1E1E1E",
"j c #0C0C0C",
"k c #191919",
"l c #686968",
"m c #595959",
"n c #0D0D0D",
"o c #010101",
"p c #212121",
"q c #E8E8E8",
"r c #636463",
"s c #181918",
"t c #020202",
"u c #434443",
"v c #1D1D1D",
"w c #0A0A0A",
"x c #5D5E5D",
"y c #171817",
"z c #000000",
"A c #3E3F3E",
"B c #121212",
"C c #040404",
"D c #F7F7F7",
"E c #2F302F",
"F c #585858",
"G c #848484",
"H c #4C4C4C",
"I c #454545",
"J c #E4E4E4",
"K c #4A4A4A",
"L c #0F0F0F",
"M c #151515",
"N c #080808",
"O c #111111",
"P c #0B0C0B",
".....................",
"......+@#$%.....+&@*=",
".. -;> ,')!~",
".. {]^/ (_:<[",
".. }|123 456789",
".. 0abc23 de0fg89",
".h 1ij9k23 lm|nop89",
".qrs9t9k23 duvwtop89",
".*xyoz9k23 dABCzop89",
".qrs9t9k23 duvwtop89",
".h 1ij9k23 lm|nop89",
".. 0abc23 de0fg89",
".. }|123 456789",
".. {]^/ (_:<[",
".D EFG H(Ig9",
".JKzzzt[LMNzzzzzNOP9o"};
". c #A6A6A6",
"+ c #B5B5B5",
"@ c #707070",
"# c #888888",
"$ c #C2C2C2",
"% c #CECECE",
"& c #424342",
"* c #7D7E7D",
"= c #B4B4B4",
"- c #888988",
"; c #606060",
"> c #BEBEBE",
", c #CCCCCC",
"' c #2E2F2E",
") c #343434",
"! c #717271",
"~ c #BBBBBB",
"{ c #666766",
"] c #5F605F",
"^ c #494A49",
"/ c #646464",
"( c #C0C0C0",
"_ c #D2D2D2",
": c #2A2A2A",
"< c #272727",
"[ c #202020",
"} c #6B6B6B",
"| c #C9C9C9",
"1 c #727372",
"2 c #4E4F4E",
"3 c #1B1B1B",
"4 c #2B2B2B",
"5 c #C7C7C7",
"6 c #DBDBDB",
"7 c #282828",
"8 c #171717",
"9 c #131313",
"0 c #1C1C1C",
"a c #707170",
"b c #474747",
"c c #0B0B0B",
"d c #252525",
"e c #1E1E1E",
"f c #0C0C0C",
"g c #060606",
"h c #191919",
"i c #686968",
"j c #595959",
"k c #0D0D0D",
"l c #010101",
"m c #212121",
"n c #6D6E6D",
"o c #3A3B3A",
"p c #181918",
"q c #020202",
"r c #434443",
"s c #1D1D1D",
"t c #0A0A0A",
"u c #171817",
"v c #000000",
"w c #3E3F3E",
"x c #121212",
"y c #040404",
"z c #797979",
"A c #AAAAAA",
"B c #6C6C6C",
"C c #B3B3B3",
"D c #898A89",
"E c #949494",
"F c #7C7C7C",
"G c #9D9D9D",
"H c #A3A3A3",
"I c #8F908F",
"J c #757575",
"K c #7F7F7F",
"L c #989898",
" .+ @#$%",
" &*= -;@>,",
" ')!~ {]^/(_",
" :<[}| 1234;56",
" 7890}| ab7cd;56",
" [efgh}| ij<klm;56",
"nopgqgh}| arstqlm;56",
"noulvgh}| awxyvlm;56",
"nopgqgh}| arstqlm;56",
" [efgh}| ij<klm;56",
" 7890}| ab7cd;56",
" :<[}| 1234;56",
" ')!~ {]^/(_",
" &zA -;BC(",
" DE @FGH",
" I JKLG"};
......@@ -356,6 +356,7 @@
<property name="visible">True</property>
<property name="label">gtk-execute</property>
<property name="use_stock">True</property>
<signal name="clicked" handler="on_foo_clicked" last_modification_time="Sat, 27 Jul 2002 19:37:05 GMT"/>
</widget>
</child>
......
......@@ -42,6 +42,11 @@ which has focus.
Control+W to close current tab and control+Q to quit the app.
</p>
<p>
Messages such as being unable to load or save files appear in the status
bar in the bottom of the window.
</p>
<h2>Command line usage</h2>
<p>
......
#! /usr/bin/env python2.2
# system
import os
......@@ -13,8 +12,9 @@ import gnome
import gnomeglade
import filediff
import misc
#import cvsview
version = "0.4.1"
version = "0.4.2"
################################################################################
#
......@@ -96,6 +96,23 @@ class MeldStatusBar:
# MeldApp
#
################################################################################
class NotebookLabel(gtk.HBox):
def __init__(self, text="", onclose=None):
gtk.HBox.__init__(self)
self.label = gtk.Label(text)
self.button = gtk.Button("X")
self.button.set_size_request(14,14) #TODO font height
self.pack_start( self.label )
self.pack_start( self.button )
self.show_all()
if onclose:
self.button.connect("clicked", onclose)
################################################################################
#
# MeldApp
#
################################################################################
class MeldApp(gnomeglade.App):
def __init__(self, files):
......@@ -119,20 +136,21 @@ class MeldApp(gnomeglade.App):
def switch_page(self, notebook, page, which):
olddoc = self.current_doc()
if olddoc:
oldseq = olddoc.undosequence
oldseq.disconnect(oldseq.can_undo_id)
oldseq.disconnect(oldseq.can_redo_id)
newdoc = notebook.get_nth_page(which).get_data("pyobject") #TODO why pyobject?
newseq = newdoc.undosequence
newseq.can_undo_id = newseq.connect("can-undo", self.on_can_undo_doc)
newseq.can_redo_id = newseq.connect("can-redo", self.on_can_redo_doc)
self.button_undo.set_sensitive(newseq.can_undo())
self.button_redo.set_sensitive(newseq.can_redo())
for i in range(3):
sensitive = newdoc.numpanes > i
self.menu_file_save_file[i].set_sensitive(sensitive)
if hasattr(newdoc, "undosequence"):
newseq = newdoc.undosequence
self.button_undo.set_sensitive(newseq.can_undo())
self.button_redo.set_sensitive(newseq.can_redo())
for i in range(3):
sensitive = newdoc.numpanes > i
self.menu_file_save_file[i].set_sensitive(sensitive)
else:
self.button_undo.set_sensitive(0)
self.button_redo.set_sensitive(0)
for i in range(3):
self.menu_file_save_file[i].set_sensitive(0)
nbl = self.notebook.get_tab_label( newdoc._widget ) #TODO why ._widget?
self.set_title( nbl.label.get_text() )
#
# global
......@@ -177,12 +195,9 @@ class MeldApp(gnomeglade.App):
index = self.menu_file_save_file.index(menuitem)
self.current_doc().save_file(index)
def on_files_doc_loaded(self, component, file0, file1):
l = self.notebook.get_tab_label( component._widget ) #TODO why ._widget?
if l:
f0 = os.path.basename(file0)
f1 = os.path.basename(file1)
l.set_text("%s : %s" % (f0,f1))
def on_doc_label_changed(self, component, text):
nbl = self.notebook.get_tab_label( component._widget ) #TODO why ._widget?
nbl.label.set_text(text)
def on_can_undo_doc(self, undosequence, can):
self.button_undo.set_sensitive(can)
......@@ -191,47 +206,32 @@ class MeldApp(gnomeglade.App):
#
# methods
#
def _create_label(self, page, *files):
l = gtk.HBox()
l.pack_start( gtk.Label(" : ".join( misc.shorten_names(*files)) + " " ) )
b = gtk.Button("X")
b.set_size_request(14,14) #TODO font height
b.connect("clicked", lambda b: self._remove_page(page))
l.pack_start(b)
l.show_all()
return l
def _remove_page(self, page):
i = self.notebook.page_num(page._widget)
assert(i>=0)
self.notebook.remove_page(i)
def append_filediff2(self, file0, file1):
d = filediff.FileDiff(2, self.statusbar)
label = self._create_label(d, file0, file1)
self.notebook.append_page( d._widget, label) #TODO why ._widget?
self.notebook.next_page()
d.set_file(file0, 0)
d.set_file(file1, 1)
d.refresh()
d.undosequence.clear()
self.append_filediff( (file0, file1) )
def append_filediff3(self, file0, file1, file2):
d = filediff.FileDiff(3, self.statusbar)
label = self._create_label(d, file0, file1, file2)
self.notebook.append_page( d._widget, label) #TODO why ._widget?
self.notebook.next_page()
d.set_file(file0,0)
d.set_file(file1,1)
d.set_file(file2,2)
d.refresh()
d.undosequence.clear()
self.append_filediff( (file0, file1, file2) )
def append_filediff(self, files):
if len(files)==2:
apply(self.append_filediff2, files)
elif len(files)==3:
apply(self.append_filediff3, files)
else:
raise "wrong number of arguments"
assert len(files)==2 or len(files)==3
nfiles = len(files)
doc = filediff.FileDiff(nfiles, self.statusbar)
for i in range(nfiles):
doc.set_file(files[i],i)
seq = doc.undosequence
seq.clear()
seq.connect("can-undo", self.on_can_undo_doc)
seq.connect("can-redo", self.on_can_redo_doc)
nbl = NotebookLabel(onclose=lambda b: self._remove_page(doc))
self.notebook.append_page( doc._widget, nbl) #TODO why ._widget?
self.notebook.next_page()
doc.connect("label-changed", self.on_doc_label_changed)
doc.label_changed()
doc.refresh()
def on_down_doc_clicked(self, *args):
self.current_doc().next_diff( gtk.gdk.SCROLL_DOWN)
......@@ -241,9 +241,16 @@ class MeldApp(gnomeglade.App):
def on_save_doc_clicked(self, *args):
self.current_doc().save()
def on_button_activate(self, *args):
def on_foo_clicked(self, *args):
pass
#self.current_doc().save()
#print "foo"
#doc = cvsview.CvsView()
#nbl = NotebookLabel(onclose=lambda b: self._remove_page(doc))
#self.notebook.append_page( doc._widget, nbl) #TODO why ._widget?
#self.notebook.next_page()
#doc.connect("label-changed", self.on_doc_label_changed)
#doc.label_changed()
#doc.refresh()
def on_menu_help_meld_home_page_activate(self, button):
gnome.url_show("http://meld.sourceforge.net")
......
#! python
import gobject
################################################################################
......@@ -85,7 +87,7 @@ class UndoSequence(gobject.GObject):
def begin_group(self):
if self.group:
self.group.start_group()
self.group.begin_group()
else:
self.group = UndoSequence()
......
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