[meld] Refactor DirDiff to use DiffMap widget
- From: Kai Willadsen <kaiw src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [meld] Refactor DirDiff to use DiffMap widget
- Date: Sat, 26 Mar 2011 08:26:14 +0000 (UTC)
commit 8ee046edc6b582927573c6cdf00027c2443ace1f
Author: Kai Willadsen <kai willadsen gmail com>
Date: Mon Mar 7 17:53:42 2011 +1000
Refactor DirDiff to use DiffMap widget
This commit also changes DiffMap to accept a state->colour dictionary
for handling DirDiff's colouring requirements.
data/ui/dirdiff.ui | 15 +----
meld/diffmap.py | 10 ++--
meld/dirdiff.py | 145 ++++++++++++++++++----------------------------------
meld/filediff.py | 9 +++-
4 files changed, 64 insertions(+), 115 deletions(-)
---
diff --git a/data/ui/dirdiff.ui b/data/ui/dirdiff.ui
index 17ac2e7..a6a1212 100644
--- a/data/ui/dirdiff.ui
+++ b/data/ui/dirdiff.ui
@@ -73,13 +73,8 @@
</packing>
</child>
<child>
- <object class="GtkDrawingArea" id="diffmap1">
- <property name="width_request">20</property>
+ <object class="DiffMap" id="diffmap1">
<property name="visible">True</property>
- <property name="can_focus">False</property>
- <property name="events">GDK_BUTTON_PRESS_MASK</property>
- <signal name="expose-event" handler="on_diffmap_expose_event" swapped="no"/>
- <signal name="button-press-event" handler="on_diffmap_button_press_event" swapped="no"/>
</object>
<packing>
<property name="left_attach">6</property>
@@ -107,18 +102,14 @@
</packing>
</child>
<child>
- <object class="GtkDrawingArea" id="diffmap0">
- <property name="width_request">20</property>
+ <object class="DiffMap" id="diffmap0">
<property name="visible">True</property>
- <property name="can_focus">False</property>
- <property name="events">GDK_BUTTON_PRESS_MASK</property>
- <signal name="expose-event" handler="on_diffmap_expose_event" swapped="no"/>
- <signal name="button-press-event" handler="on_diffmap_button_press_event" swapped="no"/>
</object>
<packing>
<property name="top_attach">1</property>
<property name="bottom_attach">2</property>
<property name="x_options">GTK_FILL</property>
+ <property name="y_options">GTK_FILL</property>
</packing>
</child>
<child>
diff --git a/meld/diffmap.py b/meld/diffmap.py
index 1fac0b3..f723ac7 100644
--- a/meld/diffmap.py
+++ b/meld/diffmap.py
@@ -39,8 +39,9 @@ class DiffMap(gtk.DrawingArea):
self._h_offset = 0
self._scroll_y = 0
self._scroll_height = 0
+ self.ctab = {}
- def setup(self, scrollbar, change_chunk_fn):
+ def setup(self, scrollbar, change_chunk_fn, colour_map):
for (o, h) in self._handlers:
o.disconnect(h)
@@ -54,6 +55,7 @@ class DiffMap(gtk.DrawingArea):
self._handlers = [(scrollbar, scroll_style_hid),
(scrollbar, scroll_size_hid)]
self._difffunc = change_chunk_fn
+ self.ctab = colour_map
self.queue_draw()
def on_scrollbar_style_set(self, scrollbar, previous_style):
@@ -92,14 +94,10 @@ class DiffMap(gtk.DrawingArea):
context.rectangle(x0 - 1, -1, x1 + 2, height + 1)
context.clip()
- ctab = {"conflict": (1.0, 0.75294117647058822, 0.79607843137254897),
- "insert": (0.75686274509803919, 1.0, 0.75686274509803919),
- "replace": (0.8666666666666667, 0.93333333333333335, 1.0),
- "delete": (0.75686274509803919, 1.0, 0.75686274509803919)}
darken = lambda color: [x * 0.8 for x in color]
for c, y0, y1 in self._difffunc():
- color = ctab[c]
+ color = self.ctab[c]
y0, y1 = round(y0 * height) - 0.5, round(y1 * height) - 0.5
context.set_source_rgb(*color)
context.rectangle(x0, y0, x1, int(y1 - y0))
diff --git a/meld/dirdiff.py b/meld/dirdiff.py
index e8f4ce8..f853c30 100644
--- a/meld/dirdiff.py
+++ b/meld/dirdiff.py
@@ -207,6 +207,18 @@ class CanonicalListing(object):
class DirDiff(melddoc.MeldDoc, gnomeglade.Component):
"""Two or three way diff of directories"""
+ """Dictionary mapping tree states to corresponding difflib-like terms"""
+ chunk_type_map = {
+ tree.STATE_NORMAL: None,
+ tree.STATE_NOCHANGE: None,
+ tree.STATE_NEW: "insert",
+ tree.STATE_ERROR: "error",
+ tree.STATE_EMPTY: None,
+ tree.STATE_MODIFIED: "replace",
+ tree.STATE_CONFLICT: "conflict",
+ tree.STATE_MISSING: "delete",
+ }
+
def __init__(self, prefs, num_panes):
melddoc.MeldDoc.__init__(self, prefs)
gnomeglade.Component.__init__(self, paths.ui_dir("dirdiff.ui"), "dirdiff")
@@ -963,11 +975,48 @@ class DirDiff(melddoc.MeldDoc, gnomeglade.Component):
return event.state==0
return 0
+ def get_state_traversal(self, diffmapindex):
+ def tree_state_iter():
+ treeindex = (0, self.num_panes-1)[diffmapindex]
+ treeview = self.treeview[treeindex]
+ row_states = []
+ def recurse_tree_states(rowiter):
+ row_states.append(self.model.get_state(rowiter.iter, treeindex))
+ if treeview.row_expanded(rowiter.path):
+ for row in rowiter.iterchildren():
+ recurse_tree_states(row)
+ recurse_tree_states(iter(self.model).next())
+ row_states.append(None)
+
+ numlines = float(len(row_states) - 1)
+ chunkstart, laststate = 0, row_states[0]
+ for index, state in enumerate(row_states):
+ if state != laststate:
+ action = self.chunk_type_map[laststate]
+ if action is not None:
+ yield (action, chunkstart / numlines, index / numlines)
+ chunkstart, laststate = index, state
+ return tree_state_iter
+
def set_num_panes(self, n):
if n != self.num_panes and n in (1,2,3):
self.model = DirDiffTreeStore(n)
for i in range(n):
self.treeview[i].set_model(self.model)
+
+ colour_map = {
+ "conflict": (1.0, 0.75294117647058822, 0.79607843137254897),
+ "error": (0.9882352941176, 0.9137254901960, 0.30980392156862),
+ "insert": (0.75686274509803919, 1.0, 0.75686274509803919),
+ "replace": (0.8666666666666667, 0.93333333333333335, 1.0),
+ "delete": (1.0, 1.0, 1.0),
+ }
+
+ for (w, i) in zip(self.diffmap, (0, n - 1)):
+ scroll = self.scrolledwindow[i].get_vscrollbar()
+ idx = 1 if i else 0
+ w.setup(scroll, self.get_state_traversal(idx), colour_map)
+
toshow = self.scrolledwindow[:n] + self.fileentry[:n]
toshow += self.linkmap[:n-1] + self.diffmap[:n]
toshow += self.vbox[:n] + self.msgarea_mgr[:n]
@@ -1000,102 +1049,6 @@ class DirDiff(melddoc.MeldDoc, gnomeglade.Component):
self.diffmap[0].queue_draw()
self.diffmap[1].queue_draw()
- def on_diffmap_expose_event(self, area, event):
- diffmapindex = self.diffmap.index(area)
- treeindex = (0, self.num_panes-1)[diffmapindex]
- treeview = self.treeview[treeindex]
-
- def traverse_states(root):
- todo = [root]
- model = self.model
- while len(todo):
- it = todo.pop(0)
- #print model.value_path(it, treeindex), model.get_state(it, treeindex)
- yield model.get_state(it, treeindex)
- path = model.get_path(it)
- if treeview.row_expanded(path):
- children = []
- child = model.iter_children(it)
- while child:
- children.append(child)
- child = model.iter_next(child)
- todo = children + todo
- yield None # end marker
-
- chunks = []
- laststate = None
- lastlines = 0
- numlines = -1
- for state in traverse_states( self.model.get_iter_root() ):
- if state != laststate:
- chunks.append( (lastlines, laststate) )
- laststate = state
- lastlines = 1
- else:
- lastlines += 1
- numlines += 1
-
- if not hasattr(area, "meldgc"):
- assert area.window
- gcd = area.window.new_gc()
- gcd.set_rgb_fg_color( gdk.color_parse(self.prefs.color_delete_bg) )
- gcc = area.window.new_gc()
- gcc.set_rgb_fg_color( gdk.color_parse(self.prefs.color_replace_bg) )
- gce = area.window.new_gc()
- gce.set_rgb_fg_color( gdk.color_parse("yellow") )
- gcm = area.window.new_gc()
- gcm.set_rgb_fg_color( gdk.color_parse("white") )
- gcb = area.window.new_gc()
- gcb.set_rgb_fg_color( gdk.color_parse("black") )
- area.meldgc = [None, # ignore
- None, # none
- None, # normal
- None, # nochange
- gce, # error
- None, # empty
- gcd, # new
- gcc, # modified
- gcc, # conflict
- gcc, # removed
- gcm, # missing
- gcb ] # border
- assert len(area.meldgc) - 1 == tree.STATE_MAX
-
- #TODO need gutter of scrollbar - how do we get that?
- size_of_arrow = 14
- hperline = float( area.get_allocation().height - 3*size_of_arrow) / numlines
- scaleit = lambda x,s=hperline,o=size_of_arrow: x*s+o
- x0 = 4
- x1 = area.get_allocation().width - 2*x0
-
- window = area.window
- window.clear()
-
- start = 0
- for c in chunks[1:]:
- end = start + c[0]
- s,e = [int(x) for x in (math.floor(scaleit(start)), math.ceil(scaleit(end))) ]
- gc = area.meldgc[c[1]]
- if gc:
- window.draw_rectangle( gc, 1, x0, s, x1, e-s)
- window.draw_rectangle( area.meldgc[-1], 0, x0, s, x1, e-s)
- start = end
-
- def on_diffmap_button_press_event(self, area, event):
- #TODO need gutter of scrollbar - how do we get that?
- if event.button == 1:
- size_of_arrow = 14
- diffmapindex = self.diffmap.index(area)
- index = (0, self.num_panes-1)[diffmapindex]
- height = area.get_allocation().height
- fraction = (event.y - size_of_arrow) / (height - 3.75*size_of_arrow)
- adj = self.scrolledwindow[index].get_vadjustment()
- val = fraction * adj.upper - adj.page_size/2
- upper = adj.upper - adj.page_size
- adj.set_value( max( min(upper, val), 0) )
- return 1
- return 0
-
def on_file_changed(self, changed_filename):
"""When a file has changed, try to find it in our tree
and update its status if necessary
diff --git a/meld/filediff.py b/meld/filediff.py
index d79fcfd..7f17695 100644
--- a/meld/filediff.py
+++ b/meld/filediff.py
@@ -1398,9 +1398,16 @@ class FileDiff(melddoc.MeldDoc, gnomeglade.Component):
yield c[0], y0 / max_y, (y + h) / max_y
return coords_by_chunk
+ colour_map = {
+ "conflict": (1.0, 0.75294117647058822, 0.79607843137254897),
+ "insert": (0.75686274509803919, 1.0, 0.75686274509803919),
+ "replace": (0.8666666666666667, 0.93333333333333335, 1.0),
+ "delete": (0.75686274509803919, 1.0, 0.75686274509803919)
+ }
+
for (w, i) in zip(self.diffmap, (0, self.num_panes - 1)):
scroll = self.scrolledwindow[i].get_vscrollbar()
- w.setup(scroll, coords_iter(i))
+ w.setup(scroll, coords_iter(i), colour_map)
for i in range(self.num_panes):
if self.bufferdata[i].modified:
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]