* Scott Scriven <[EMAIL PROTECTED]> wrote:
> The changes are available in my branch:
>
> lp:~toykeeper/bzr-gtk/bzr-vis-enhancements/
And, if people prefer a merge directive, it's attached.
A few changes are included, but they're all related:
- Added an optional diff panel to vis.
- Made vis remember its window size, panel sizes, and toolbar
state.
- Removed some redundant screen redrawing vis.
- Fixed overflowing labels/buttons in vis.
-- Scott
# Bazaar merge directive format 2 (Bazaar 0.90)
# revision_id: [EMAIL PROTECTED]
# target_branch: https://code.launchpad.net/~bzr-gtk/bzr-gtk/trunk
# testament_sha1: 890fb27ec71013aa98051752412ed977a2642caf
# timestamp: 2008-07-12 03:34:50 -0600
# source_branch: https://code.launchpad.net/~bzr-gtk/bzr-gtk/trunk
# base_revision_id: [EMAIL PROTECTED]
#
# Begin patch
=== modified file 'NEWS'
--- NEWS 2008-07-01 21:56:25 +0000
+++ NEWS 2008-07-11 17:36:56 +0000
@@ -11,6 +11,12 @@
* Add "Send Merge Directive" button in bzr viz. (Jelmer Vernooij)
+ * Added an optional diff panel to bzr vis. (Scott Scriven)
+
+ * Made bzr vis remember whether the toolbar is visible. (Scott Scriven)
+
+ * Made bzr vis remember window and panel sizes. (Scott Scriven)
+
BUG FIXES
* Replace _() calls by _i18n() calls. (Vincent Ladeuil, #187283)
@@ -30,6 +36,10 @@
* List network drives in Olive. (Kevin Light, #244308)
+ * Removed some redundant screen redrawing in bzr vis. (Scott Scriven)
+
+ * Fixed overflowing labels in bzr vis. (Scott Scriven)
+
CHANGES
* Moved notify icon code to separate script. (Jelmer Vernooij)
=== modified file 'branchview/treeview.py'
--- branchview/treeview.py 2008-06-30 20:11:24 +0000
+++ branchview/treeview.py 2008-07-10 06:23:54 +0000
@@ -325,6 +325,7 @@
if set_tooltip is not None:
set_tooltip(treemodel.MESSAGE)
+ self._prev_cursor_path = None
self.treeview.connect("cursor-changed",
self._on_selection_changed)
@@ -400,7 +401,8 @@
def _on_selection_changed(self, treeview):
"""callback for when the treeview changes."""
(path, focus) = treeview.get_cursor()
- if path is not None:
+ if (path is not None) and (path != self._prev_cursor_path):
+ self._prev_cursor_path = path # avoid emitting twice per click
self.iter = self.model.get_iter(path)
self.emit('revision-selected')
=== modified file 'diff.py'
--- diff.py 2008-05-22 02:33:40 +0000
+++ diff.py 2008-07-10 07:33:13 +0000
@@ -330,9 +330,10 @@
# text view
def set_diff_text_sections(self, sections):
- self.diff_view = DiffFileView()
+ if not hasattr(self, 'diff_view'):
+ self.diff_view = DiffFileView()
+ self.pack2(self.diff_view)
self.diff_view.show()
- self.pack2(self.diff_view)
for oldname, newname, patch in sections:
self.diff_view._diffs[newname] = str(patch)
if newname is None:
@@ -346,8 +347,9 @@
Compares the two trees and populates the window with the
differences.
"""
- self.diff_view = DiffView()
- self.pack2(self.diff_view)
+ if not hasattr(self, 'diff_view'):
+ self.diff_view = DiffView()
+ self.pack2(self.diff_view)
self.diff_view.show()
self.diff_view.set_trees(rev_tree, parent_tree)
self.rev_tree = rev_tree
@@ -380,6 +382,7 @@
self.model.append(titer, [ path, path ])
self.treeview.expand_all()
+ self.diff_view.show_diff(None)
def set_file(self, file_path):
"""Select the current file to display"""
=== modified file 'revisionview.py'
--- revisionview.py 2008-06-29 19:18:34 +0000
+++ revisionview.py 2008-07-11 15:46:32 +0000
@@ -509,7 +509,7 @@
table.resize(max(len(revids), 1), 2)
for idx, revid in enumerate(revids):
- align = gtk.Alignment(0.0, 0.0)
+ align = gtk.Alignment(0.0, 0.0, 1, 1)
widgets.append(align)
table.attach(align, 1, 2, idx, idx + 1,
gtk.EXPAND | gtk.FILL, gtk.FILL)
@@ -532,12 +532,16 @@
hbox.pack_start(button, expand=False, fill=True)
button.show()
- button = gtk.Button(revid)
+ button = gtk.Button()
+ revid_label = gtk.Label(str(revid))
+ revid_label.set_ellipsize(pango.ELLIPSIZE_MIDDLE)
+ revid_label.set_alignment(0.0, 0.5)
+ button.add(revid_label)
button.connect("clicked",
lambda w, r: self.set_revision(self._repository.get_revision(r)), revid)
button.set_use_underline(False)
- hbox.pack_start(button, expand=False, fill=True)
- button.show()
+ hbox.pack_start(button, expand=True, fill=True)
+ button.show_all()
def _create_general(self):
vbox = gtk.VBox(False, 6)
@@ -566,102 +570,91 @@
self.table.set_col_spacings(6)
self.table.show()
- align = gtk.Alignment(1.0, 0.5)
+ row = 0
+
label = gtk.Label()
+ label.set_alignment(1.0, 0.5)
label.set_markup("<b>Revision Id:</b>")
- align.add(label)
- self.table.attach(align, 0, 1, 0, 1, gtk.FILL, gtk.FILL)
- align.show()
+ self.table.attach(label, 0, 1, row, row+1, gtk.FILL, gtk.FILL)
label.show()
- align = gtk.Alignment(0.0, 0.5)
revision_id = gtk.Label()
+ revision_id.set_ellipsize(pango.ELLIPSIZE_MIDDLE)
+ revision_id.set_alignment(0.0, 0.5)
revision_id.set_selectable(True)
self.connect('notify::revision',
lambda w, p: revision_id.set_text(self._revision.revision_id))
- align.add(revision_id)
- self.table.attach(align, 1, 2, 0, 1, gtk.EXPAND | gtk.FILL, gtk.FILL)
- align.show()
+ self.table.attach(revision_id, 1, 2, row, row+1, gtk.EXPAND | gtk.FILL, gtk.FILL)
revision_id.show()
- align = gtk.Alignment(1.0, 0.5)
+ row += 1
self.author_label = gtk.Label()
+ self.author_label.set_alignment(1.0, 0.5)
self.author_label.set_markup("<b>Author:</b>")
- align.add(self.author_label)
- self.table.attach(align, 0, 1, 1, 2, gtk.FILL, gtk.FILL)
- align.show()
+ self.table.attach(self.author_label, 0, 1, row, row+1, gtk.FILL, gtk.FILL)
self.author_label.show()
- align = gtk.Alignment(0.0, 0.5)
self.author = gtk.Label()
+ self.author.set_ellipsize(pango.ELLIPSIZE_END)
+ self.author.set_alignment(0.0, 0.5)
self.author.set_selectable(True)
- align.add(self.author)
- self.table.attach(align, 1, 2, 1, 2, gtk.EXPAND | gtk.FILL, gtk.FILL)
- align.show()
+ self.table.attach(self.author, 1, 2, row, row+1, gtk.EXPAND | gtk.FILL, gtk.FILL)
self.author.show()
self.author.hide()
- align = gtk.Alignment(1.0, 0.5)
+ row += 1
label = gtk.Label()
+ label.set_alignment(1.0, 0.5)
label.set_markup("<b>Committer:</b>")
- align.add(label)
- self.table.attach(align, 0, 1, 2, 3, gtk.FILL, gtk.FILL)
- align.show()
+ self.table.attach(label, 0, 1, row, row+1, gtk.FILL, gtk.FILL)
label.show()
- align = gtk.Alignment(0.0, 0.5)
self.committer = gtk.Label()
+ self.committer.set_ellipsize(pango.ELLIPSIZE_END)
+ self.committer.set_alignment(0.0, 0.5)
self.committer.set_selectable(True)
- align.add(self.committer)
- self.table.attach(align, 1, 2, 2, 3, gtk.EXPAND | gtk.FILL, gtk.FILL)
- align.show()
+ self.table.attach(self.committer, 1, 2, row, row+1, gtk.EXPAND | gtk.FILL, gtk.FILL)
self.committer.show()
- align = gtk.Alignment(0.0, 0.5)
+ row += 1
label = gtk.Label()
+ label.set_alignment(1.0, 0.5)
label.set_markup("<b>Branch nick:</b>")
- align.add(label)
- self.table.attach(align, 0, 1, 3, 4, gtk.FILL, gtk.FILL)
+ self.table.attach(label, 0, 1, row, row+1, gtk.FILL, gtk.FILL)
label.show()
- align.show()
- align = gtk.Alignment(0.0, 0.5)
self.branchnick_label = gtk.Label()
+ self.branchnick_label.set_ellipsize(pango.ELLIPSIZE_MIDDLE)
+ self.branchnick_label.set_alignment(0.0, 0.5)
self.branchnick_label.set_selectable(True)
- align.add(self.branchnick_label)
- self.table.attach(align, 1, 2, 3, 4, gtk.EXPAND | gtk.FILL, gtk.FILL)
+ self.table.attach(self.branchnick_label, 1, 2, row, row+1, gtk.EXPAND | gtk.FILL, gtk.FILL)
self.branchnick_label.show()
- align.show()
- align = gtk.Alignment(1.0, 0.5)
+ row += 1
label = gtk.Label()
+ label.set_alignment(1.0, 0.5)
label.set_markup("<b>Timestamp:</b>")
- align.add(label)
- self.table.attach(align, 0, 1, 4, 5, gtk.FILL, gtk.FILL)
- align.show()
+ self.table.attach(label, 0, 1, row, row+1, gtk.FILL, gtk.FILL)
label.show()
- align = gtk.Alignment(0.0, 0.5)
self.timestamp = gtk.Label()
+ self.timestamp.set_ellipsize(pango.ELLIPSIZE_END)
+ self.timestamp.set_alignment(0.0, 0.5)
self.timestamp.set_selectable(True)
- align.add(self.timestamp)
- self.table.attach(align, 1, 2, 4, 5, gtk.EXPAND | gtk.FILL, gtk.FILL)
- align.show()
+ self.table.attach(self.timestamp, 1, 2, row, row+1, gtk.EXPAND | gtk.FILL, gtk.FILL)
self.timestamp.show()
- align = gtk.Alignment(1.0, 0.5)
+ row += 1
self.tags_label = gtk.Label()
+ self.tags_label.set_alignment(1.0, 0.5)
self.tags_label.set_markup("<b>Tags:</b>")
- align.add(self.tags_label)
- align.show()
- self.table.attach(align, 0, 1, 5, 6, gtk.FILL, gtk.FILL)
+ self.table.attach(self.tags_label, 0, 1, row, row+1, gtk.FILL, gtk.FILL)
self.tags_label.show()
- align = gtk.Alignment(0.0, 0.5)
self.tags_list = gtk.Label()
- align.add(self.tags_list)
- self.table.attach(align, 1, 2, 5, 6, gtk.EXPAND | gtk.FILL, gtk.FILL)
- align.show()
+ self.tags_list.set_ellipsize(pango.ELLIPSIZE_MIDDLE)
+ self.tags_list.set_alignment(0.0, 0.5)
+ self.table.attach(self.tags_list, 1, 2, row, row+1, gtk.EXPAND | gtk.FILL, gtk.FILL)
self.tags_list.show()
self.connect('notify::revision', self._add_tags)
=== modified file 'viz/branchwin.py'
--- viz/branchwin.py 2008-07-01 21:54:21 +0000
+++ viz/branchwin.py 2008-07-11 17:25:46 +0000
@@ -48,6 +48,8 @@
self.maxnum = maxnum
self.config = GlobalConfig()
+ self._sizes = {} # window and widget sizes
+
if self.config.get_user_option('viz-compact-view') == 'yes':
self.compact_view = True
else:
@@ -60,7 +62,13 @@
monitor = screen.get_monitor_geometry(0)
width = int(monitor.width * 0.75)
height = int(monitor.height * 0.75)
+ # user-configured window size
+ size = self._load_size('viz-window-size')
+ if size:
+ width, height = size
self.set_default_size(width, height)
+ self.set_size_request(width/3, height/3)
+ self.connect("size-allocate", self._on_size_allocate, 'viz-window-size')
# FIXME AndyFitz!
icon = self.render_icon(gtk.STOCK_INDEX, gtk.ICON_SIZE_BUTTON)
@@ -104,13 +112,15 @@
self.add(vbox)
self.paned = gtk.VPaned()
- self.paned.pack1(self.construct_top(), resize=True, shrink=False)
- self.paned.pack2(self.construct_bottom(), resize=False, shrink=True)
+ self.paned.pack1(self.construct_top(), resize=False, shrink=True)
+ self.paned.pack2(self.construct_bottom(), resize=True, shrink=False)
self.paned.show()
- vbox.pack_start(self.construct_menubar(), expand=False, fill=True)
- vbox.pack_start(self.construct_navigation(), expand=False, fill=True)
-
+ nav = self.construct_navigation()
+ menubar = self.construct_menubar()
+ vbox.pack_start(menubar, expand=False, fill=True)
+ vbox.pack_start(nav, expand=False, fill=True)
+
vbox.pack_start(self.paned, expand=True, fill=True)
vbox.set_focus_child(self.paned)
@@ -161,14 +171,24 @@
view_menu_toolbar = gtk.CheckMenuItem("Show Toolbar")
view_menu_toolbar.set_active(True)
+ if self.config.get_user_option('viz-toolbar-visible') == 'False':
+ view_menu_toolbar.set_active(False)
+ self.toolbar.hide()
view_menu_toolbar.connect('toggled', self._toolbar_visibility_changed)
view_menu_compact = gtk.CheckMenuItem("Show Compact Graph")
view_menu_compact.set_active(self.compact_view)
view_menu_compact.connect('activate', self._brokenlines_toggled_cb)
+ view_menu_diffs = gtk.CheckMenuItem("Show Diffs")
+ view_menu_diffs.set_active(True)
+ if self.config.get_user_option('viz-show-diffs') == 'False':
+ view_menu_diffs.set_active(False)
+ view_menu_diffs.connect('toggled', self._diff_visibility_changed)
+
view_menu.add(view_menu_toolbar)
view_menu.add(view_menu_compact)
+ view_menu.add(view_menu_diffs)
view_menu.add(gtk.SeparatorMenuItem())
self.mnu_show_revno_column = gtk.CheckMenuItem("Show Revision _Number Column")
@@ -275,6 +295,15 @@
align = gtk.Alignment(0.0, 0.0, 1.0, 1.0)
align.set_padding(5, 0, 0, 0)
align.add(self.treeview)
+ # user-configured size
+ size = self._load_size('viz-graph-size')
+ if size:
+ width, height = size
+ align.set_size_request(width, height)
+ else:
+ (width, height) = self.get_size()
+ align.set_size_request(width, int(height / 2.5))
+ align.connect('size-allocate', self._on_size_allocate, 'viz-graph-size')
align.show()
return align
@@ -302,15 +331,34 @@
def construct_bottom(self):
"""Construct the bottom half of the window."""
+ self.bottom_hpaned = gtk.HPaned()
+ (width, height) = self.get_size()
+ self.bottom_hpaned.set_size_request(20, 20) # shrinkable
+
from bzrlib.plugins.gtk.revisionview import RevisionView
self.revisionview = RevisionView(branch=self.branch)
- (width, height) = self.get_size()
- self.revisionview.set_size_request(width, int(height / 2.5))
+ self.revisionview.set_size_request(width/3, int(height / 2.5))
+ # user-configured size
+ size = self._load_size('viz-revisionview-size')
+ if size:
+ width, height = size
+ self.revisionview.set_size_request(width, height)
+ self.revisionview.connect('size-allocate', self._on_size_allocate, 'viz-revisionview-size')
self.revisionview.show()
self.revisionview.set_show_callback(self._show_clicked_cb)
self.revisionview.connect('notify::revision', self._go_clicked_cb)
self.treeview.connect('tag-added', lambda w, t, r: self.revisionview.update_tags())
- return self.revisionview
+ self.bottom_hpaned.pack1(self.revisionview)
+
+ from bzrlib.plugins.gtk.diff import DiffWidget
+ self.diff = DiffWidget()
+ self.bottom_hpaned.pack2(self.diff)
+
+ self.bottom_hpaned.show_all()
+ if self.config.get_user_option('viz-show-diffs') == 'False':
+ self.diff.hide()
+
+ return self.bottom_hpaned
def _tag_selected_cb(self, menuitem, revid):
self.treeview.set_revision_id(revid)
@@ -367,7 +415,9 @@
self.revisionview.set_revision(revision)
self.revisionview.set_children(children)
-
+
+ self.update_diff_panel(revision, parents)
+
def _tree_revision_activated(self, widget, path, col):
# TODO: more than one parent
"""Callback for when a treeview row gets activated."""
@@ -439,9 +489,23 @@
def _toolbar_visibility_changed(self, col):
if col.get_active():
- self.toolbar.show()
+ self.toolbar.show()
else:
self.toolbar.hide()
+ self.config.set_user_option('viz-toolbar-visible', col.get_active())
+
+ def _diff_visibility_changed(self, col):
+ if col.get_active():
+ self.diff.show()
+ # make sure the diff isn't zero-width
+ alloc = self.diff.get_allocation()
+ if alloc.width < 10:
+ width, height = self.get_size()
+ self.revisionview.set_size_request(width/3, int(height / 2.5))
+ else:
+ self.diff.hide()
+ self.config.set_user_option('viz-show-diffs', str(col.get_active()))
+ self.update_diff_panel()
def _show_about_cb(self, w):
dialog = AboutDialog()
@@ -473,6 +537,34 @@
self.go_menu_tags.show_all()
+ def _load_size(self, name):
+ """Read and parse 'name' from self.config.
+ The value is a string, formatted as WIDTHxHEIGHT
+ Returns None, or (width, height)
+ """
+ size = self.config.get_user_option(name)
+ if size:
+ width, height = [int(num) for num in size.split('x')]
+ # avoid writing config every time we start
+ self._sizes[name] = (width, height)
+ return width, height
+ return None
+
+ def _on_size_allocate(self, widget, allocation, name):
+ """When window has been resized, save the new size."""
+ width, height = 0, 0
+ if name in self._sizes:
+ width, height = self._sizes[name]
+
+ size_changed = (width != allocation.width) or \
+ (height != allocation.height)
+
+ if size_changed:
+ width, height = allocation.width, allocation.height
+ self._sizes[name] = (width, height)
+ value = '%sx%s' % (width, height)
+ self.config.set_user_option(name, value)
+
def show_diff(self, revid=None, parentid=None):
"""Open a new window to show a diff between the given revisions."""
from bzrlib.plugins.gtk.diff import DiffWindow
@@ -489,3 +581,25 @@
window.show()
+ def update_diff_panel(self, revision=None, parents=None):
+ """Show the current revision in the diff panel."""
+ if self.config.get_user_option('viz-show-diffs') == 'False':
+ return
+
+ if not revision: # default to selected row
+ revision = self.treeview.get_revision()
+ if (not revision) or (revision == NULL_REVISION):
+ return
+
+ if not parents: # default to selected row's parents
+ parents = self.treeview.get_parents()
+ if len(parents) == 0:
+ parent_id = None
+ else:
+ parent_id = parents[0]
+
+ rev_tree = self.branch.repository.revision_tree(revision.revision_id)
+ parent_tree = self.branch.repository.revision_tree(parent_id)
+
+ self.diff.set_diff(rev_tree, parent_tree)
+ self.diff.show_all()
# Begin bundle
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
Wr/9/+LuSKcKEgVTSntg
--
bzr-gtk mailing list
[email protected]
Modify settings or unsubscribe at:
https://lists.canonical.com/mailman/listinfo/bzr-gtk