[Pkg-bazaar-commits] ./bzr-gtk/unstable r3: Split the display in two with a pane, we'll use the bottom half to show

Scott James Remnant scott at netsplit.com
Fri Apr 10 07:15:00 UTC 2009


------------------------------------------------------------
revno: 3
committer: Scott James Remnant <scott at netsplit.com>
timestamp: Mon 2005-10-17 05:26:00 +0100
message:
  Split the display in two with a pane, we'll use the bottom half to show
  information about the current revision.  Add a Back and Forward button
  which figure out which revision is logically the next of previous and
  moves the cursor to it.  Handle the cursor-changed event to enable/disable
  the buttons (and soon update the bottom pane).
  
  Further split up graph.py so we can stash the internal lists to do the
  above; also it may allow us in future to produce partial graphs.
modified:
  branchwin.py
  graph.py
-------------- next part --------------
=== modified file 'branchwin.py'
--- a/branchwin.py	2005-10-17 01:07:49 +0000
+++ b/branchwin.py	2005-10-17 04:26:00 +0000
@@ -18,7 +18,7 @@
 
 from bzrlib.osutils import format_date
 
-from graph import graph
+from graph import distances, graph, same_branch
 from graphcell import CellRendererGraph
 
 
@@ -44,20 +44,36 @@
         icon = self.render_icon(gtk.STOCK_INDEX, gtk.ICON_SIZE_BUTTON)
         self.set_icon(icon)
 
+        self.accel_group = gtk.AccelGroup()
+        self.add_accel_group(self.accel_group)
+
         self.construct()
 
     def construct(self):
         """Construct the window contents."""
+        paned = gtk.VPaned()
+        paned.pack1(self.construct_top(), resize=True, shrink=False)
+        paned.pack2(self.construct_bottom(), resize=True, shrink=True)
+        self.add(paned)
+        paned.show()
+
+    def construct_top(self):
+        """Construct the top-half of the window."""
+        vbox = gtk.VBox(spacing=6)
+        vbox.set_border_width(12)
+        vbox.show()
+
         scrollwin = gtk.ScrolledWindow()
         scrollwin.set_policy(gtk.POLICY_NEVER, gtk.POLICY_AUTOMATIC)
         scrollwin.set_shadow_type(gtk.SHADOW_IN)
-        scrollwin.set_border_width(12)
-        self.add(scrollwin)
+        #scrollwin.set_border_width(12)
+        vbox.pack_start(scrollwin, expand=True, fill=True)
         scrollwin.show()
 
         self.treeview = gtk.TreeView()
         self.treeview.set_rules_hint(True)
         self.treeview.set_search_column(4)
+        self.treeview.connect("cursor-changed", self._treeview_cursor_cb)
         scrollwin.add(self.treeview)
         self.treeview.show()
 
@@ -96,6 +112,33 @@
         column.add_attribute(cell, "text", 6)
         self.treeview.append_column(column)
 
+        hbox = gtk.HBox(False, spacing=6)
+        vbox.pack_start(hbox, expand=False, fill=False)
+        hbox.show()
+
+        self.back_button = gtk.Button(stock=gtk.STOCK_GO_BACK)
+        self.back_button.add_accelerator("clicked", self.accel_group, ord('['),
+                                         0, 0)
+        self.back_button.connect("clicked", self._back_clicked_cb)
+        hbox.pack_start(self.back_button, expand=False, fill=True)
+        self.back_button.show()
+
+        self.fwd_button = gtk.Button(stock=gtk.STOCK_GO_FORWARD)
+        self.fwd_button.add_accelerator("clicked", self.accel_group, ord(']'),
+                                        0, 0)
+        self.fwd_button.connect("clicked", self._fwd_clicked_cb)
+        hbox.pack_start(self.fwd_button, expand=False, fill=True)
+        self.fwd_button.show()
+
+        return vbox
+
+    def construct_bottom(self):
+        """Construct the bottom half of the window."""
+        label = gtk.Label("test")
+        label.show()
+
+        return label
+
     def set_branch(self, branch, start):
         """Set the branch and start position for this window.
 
@@ -104,21 +147,70 @@
         treeview itself.
         """
         # [ revision, node, last_lines, lines, message, committer, timestamp ]
-        model = gtk.ListStore(gobject.TYPE_PYOBJECT, gobject.TYPE_PYOBJECT,
-                              gobject.TYPE_PYOBJECT, gobject.TYPE_PYOBJECT,
-                              str, str, str)
+        self.model = gtk.ListStore(gobject.TYPE_PYOBJECT,
+                                   gobject.TYPE_PYOBJECT,
+                                   gobject.TYPE_PYOBJECT,
+                                   gobject.TYPE_PYOBJECT,
+                                   str, str, str)
+        self.index = {}
+        index = 0
 
         last_lines = []
-        for revision, node, lines in graph(branch, start):
+        (revids, self.revisions, colours, self.children) \
+                 = distances(branch, start)
+        for revision, node, lines in graph(revids, self.revisions, colours):
             message = revision.message.split("\n")[0]
             if revision.committer is not None:
                 timestamp = format_date(revision.timestamp, revision.timezone)
             else:
                 timestamp = None
 
-            model.append([ revision, node, last_lines, lines,
-                           message, revision.committer, timestamp ])
+            self.model.append([ revision, node, last_lines, lines,
+                                message, revision.committer, timestamp ])
+            self.index[revision] = index
+            index += 1
+
             last_lines = lines
 
         self.set_title(os.path.basename(branch.base) + " - bzrk")
-        self.treeview.set_model(model)
+        self.treeview.set_model(self.model)
+
+    def _treeview_cursor_cb(self, *args):
+        """Callback for when the treeview cursor changes."""
+        (path, col) = self.treeview.get_cursor()
+        revision = self.model[path][0]
+
+        self.back_button.set_sensitive(len(self.children[revision]) > 0)
+        self.fwd_button.set_sensitive(len(revision.parent_ids) > 0)
+
+    def _back_clicked_cb(self, *args):
+        """Callback for when the back button is clicked."""
+        (path, col) = self.treeview.get_cursor()
+        revision = self.model[path][0]
+        if not len(self.children[revision]):
+            return
+
+        for child in self.children[revision]:
+            if same_branch(child, revision):
+                self.treeview.set_cursor(self.index[child])
+                break
+        else:
+            prev = list(self.children[revision])[0]
+            self.treeview.set_cursor(self.index[prev])
+
+    def _fwd_clicked_cb(self, *args):
+        """Callback for when the forward button is clicked."""
+        (path, col) = self.treeview.get_cursor()
+        revision = self.model[path][0]
+        if not len(revision.parent_ids):
+            return
+
+        for parent_id in revision.parent_ids:
+            parent = self.revisions[parent_id]
+            if same_branch(revision, parent):
+                self.treeview.set_cursor(self.index[parent])
+                break
+        else:
+            next = self.revisions[revision.parent_ids[0]]
+            self.treeview.set_cursor(self.index[next])
+

=== modified file 'graph.py'
--- a/graph.py	2005-10-17 03:23:43 +0000
+++ b/graph.py	2005-10-17 04:26:00 +0000
@@ -30,35 +30,17 @@
         self.message = self.revision_id
 
 
-def graph(branch, start):
-    """Produce a directed graph of a bzr branch.
+def distances(branch, start):
+    """Sort the revisions.
 
     Traverses the branch revision tree starting at start and produces an
     ordered list of revisions such that a revision always comes after
-    any revision it is the parent of.  It also tries to make a reasonably
-    not-too-stupid decision whether a parent revision is on the same
-    logical branch, as that information is not available with bzr.
-
-    For each revision it then yields a tuple of (revision, node, lines).
-    If the revision is only referenced in the branch and not present in the
-    store, revision will be a DummyRevision object, otherwise it is the bzr
-    Revision object with the meta-data for the revision.
-
-    Node is a tuple of (column, colour) with column being a zero-indexed
-    column number of the graph that this revision represents and colour
-    being a zero-indexed colour (which doesn't specify any actual colour
-    in particular) to draw the node in.
-
-    Lines is a list of tuples which represent lines you should draw away
-    from the revision, if you also need to draw lines into the revision
-    you should use the lines list from the previous iteration.  Each
-    typle in the list is in the form (start, end, colour) with start and
-    end being zero-indexed column numbers and colour as in node.
-
-    It's up to you how to actually draw the nodes and lines (straight,
-    curved, kinked, etc.) and to pick the actual colours for each index.
+    any revision it is the parent of.
+
+    Returns a tuple of (revids, revisions, colours, children)
     """
     revisions = { start: branch.get_revision(start) }
+    children = { revisions[start]: set() }
     distances = { start: 0 }
     colours = { start: 0 }
     last_colour = 0
@@ -82,6 +64,7 @@
             # Get the parent from the cache, or put it in the cache
             try:
                 parent = revisions[parent_id]
+                children[parent].add(revision)
             except KeyError:
                 try:
                     parent = revisions[parent_id] \
@@ -89,6 +72,8 @@
                 except NoSuchRevision:
                     parent = revisions[parent_id] = DummyRevision(parent_id)
 
+                children[parent] = set([ revision ])
+
             # Penalise revisions a little at a fork if we think they're on
             # the same branch -- this makes the few few (at least) revisions
             # of a branch appear straight after the fork
@@ -104,12 +89,33 @@
 
             todo.add(parent_id)
 
-    # Now iterate the revisions again, but this time in list order rather
-    # than traversing the tree, and build up the graph lines.  We do this
-    # by keeping a list of "hanging parents", which can only be removed
-    # once we encounter the revision being hung.
-    hanging = [ start ]
-    for revid in sorted(distances, key=distances.get):
+    return ( sorted(distances, key=distances.get), revisions, colours,
+             children )
+
+def graph(revids, revisions, colours):
+    """Produce a directed graph of a bzr branch.
+
+    For each revision it then yields a tuple of (revision, node, lines).
+    If the revision is only referenced in the branch and not present in the
+    store, revision will be a DummyRevision object, otherwise it is the bzr
+    Revision object with the meta-data for the revision.
+
+    Node is a tuple of (column, colour) with column being a zero-indexed
+    column number of the graph that this revision represents and colour
+    being a zero-indexed colour (which doesn't specify any actual colour
+    in particular) to draw the node in.
+
+    Lines is a list of tuples which represent lines you should draw away
+    from the revision, if you also need to draw lines into the revision
+    you should use the lines list from the previous iteration.  Each
+    typle in the list is in the form (start, end, colour) with start and
+    end being zero-indexed column numbers and colour as in node.
+
+    It's up to you how to actually draw the nodes and lines (straight,
+    curved, kinked, etc.) and to pick the actual colours for each index.
+    """
+    hanging = revids[:1]
+    for revid in revids:
         lines = []
         node = None
 



More information about the Pkg-bazaar-commits mailing list