/b-gtk/fix-viz

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/b-gtk/fix-viz
1 by Scott James Remnant
Commit the first version of bzrk.
1
# -*- coding: UTF-8 -*-
2
"""Branch window.
3
4
This module contains the code to manage the branch information window,
5
which contains both the revision graph and details panes.
6
"""
7
8
__copyright__ = "Copyright © 2005 Canonical Ltd."
9
__author__    = "Scott James Remnant <scott@ubuntu.com>"
10
11
12
import gtk
13
import gobject
14
import pango
256.2.29 by Gary van der Merwe
Implement a TreeModel that loads revisions incrementaly.
15
import treemodel
1 by Scott James Remnant
Commit the first version of bzrk.
16
298.2.1 by Daniel Schierbeck
Refactored the GTK window code, creating a single base window class that handles keyboard events.
17
from bzrlib.plugins.gtk.window import Window
1 by Scott James Remnant
Commit the first version of bzrk.
18
from bzrlib.osutils import format_date
19
256.2.5 by Gary van der Merwe
Oops - Renamed file without changeing import lines
20
from linegraph import linegraph, same_branch
1 by Scott James Remnant
Commit the first version of bzrk.
21
from graphcell import CellRendererGraph
256.2.29 by Gary van der Merwe
Implement a TreeModel that loads revisions incrementaly.
22
from treemodel import TreeModel
1 by Scott James Remnant
Commit the first version of bzrk.
23
24
298.2.1 by Daniel Schierbeck
Refactored the GTK window code, creating a single base window class that handles keyboard events.
25
class BranchWindow(Window):
1 by Scott James Remnant
Commit the first version of bzrk.
26
    """Branch window.
27
28
    This object represents and manages a single window containing information
29
    for a particular branch.
30
    """
31
275.1.6 by Daniel Schierbeck
Made Ctrl-W call gtk.main_quit if the window has no parent.
32
    def __init__(self, parent=None):
298.2.1 by Daniel Schierbeck
Refactored the GTK window code, creating a single base window class that handles keyboard events.
33
        Window.__init__(self, parent=parent)
1 by Scott James Remnant
Commit the first version of bzrk.
34
        self.set_border_width(0)
292.2.1 by Daniel Schierbeck
Changed title of the viz window to 'revision history'
35
        self.set_title("Revision history")
1 by Scott James Remnant
Commit the first version of bzrk.
36
37
        # Use three-quarters of the screen by default
38
        screen = self.get_screen()
4 by Scott James Remnant
Use the size of the first monitor rather than the entire screen
39
        monitor = screen.get_monitor_geometry(0)
40
        width = int(monitor.width * 0.75)
41
        height = int(monitor.height * 0.75)
1 by Scott James Remnant
Commit the first version of bzrk.
42
        self.set_default_size(width, height)
43
44
        # FIXME AndyFitz!
45
        icon = self.render_icon(gtk.STOCK_INDEX, gtk.ICON_SIZE_BUTTON)
46
        self.set_icon(icon)
47
3 by Scott James Remnant
Split the display in two with a pane, we'll use the bottom half to show
48
        self.accel_group = gtk.AccelGroup()
49
        self.add_accel_group(self.accel_group)
50
1 by Scott James Remnant
Commit the first version of bzrk.
51
        self.construct()
52
53
    def construct(self):
54
        """Construct the window contents."""
44 by David Allouche
reorganise branch window
55
        vbox = gtk.VBox(spacing=0)
56
        self.add(vbox)
57
58
        vbox.pack_start(self.construct_navigation(), expand=False, fill=True)
280.2.1 by Gary van der Merwe
Add a message to the viz window to indicate that graph is still loading.
59
        vbox.pack_start(self.construct_loading_msg(), expand=False, fill=True)
60
        
3 by Scott James Remnant
Split the display in two with a pane, we'll use the bottom half to show
61
        paned = gtk.VPaned()
62
        paned.pack1(self.construct_top(), resize=True, shrink=False)
7 by Scott James Remnant
Put some information about the highlighted revision in the bottom pane,
63
        paned.pack2(self.construct_bottom(), resize=False, shrink=True)
3 by Scott James Remnant
Split the display in two with a pane, we'll use the bottom half to show
64
        paned.show()
44 by David Allouche
reorganise branch window
65
        vbox.pack_start(paned, expand=True, fill=True)
66
        vbox.set_focus_child(paned)
67
68
        vbox.show()
280.2.1 by Gary van der Merwe
Add a message to the viz window to indicate that graph is still loading.
69
    
70
    def construct_loading_msg(self):
71
        image_loading = gtk.image_new_from_stock(gtk.STOCK_REFRESH,
72
                                                 gtk.ICON_SIZE_BUTTON)
73
        image_loading.show()
74
        
75
        label_loading = gtk.Label(_("Please wait, loading ancestral graph..."))
76
        label_loading.set_alignment(0.0, 0.5)        
77
        label_loading.show()
78
        
79
        self.loading_msg_box = gtk.HBox()
80
        self.loading_msg_box.set_spacing(5)
81
        self.loading_msg_box.set_border_width(5)        
82
        self.loading_msg_box.pack_start(image_loading, False, False)
83
        self.loading_msg_box.pack_start(label_loading, True, True)
84
        self.loading_msg_box.show()
85
        
86
        return self.loading_msg_box
3 by Scott James Remnant
Split the display in two with a pane, we'll use the bottom half to show
87
88
    def construct_top(self):
89
        """Construct the top-half of the window."""
1 by Scott James Remnant
Commit the first version of bzrk.
90
        scrollwin = gtk.ScrolledWindow()
91
        scrollwin.set_policy(gtk.POLICY_NEVER, gtk.POLICY_AUTOMATIC)
92
        scrollwin.set_shadow_type(gtk.SHADOW_IN)
93
        scrollwin.show()
94
95
        self.treeview = gtk.TreeView()
96
        self.treeview.set_rules_hint(True)
97
        self.treeview.set_search_column(4)
280.1.2 by Daniel Schierbeck
Switched to handle the 'changed' signal from the treeview's treeselection instead of the 'cursor-changed' signal from the treeview itself, allowing more flexibility (particularly the ability to handle programmatic selections)
98
        self.treeview.get_selection().connect("changed", self._treeselection_changed_cb)
47 by Wouter van Heyst
rename _treeview_clicked_cb to correcter _treeview_row_activated_cb
99
        self.treeview.connect("row-activated", self._treeview_row_activated_cb)
226 by Jelmer Vernooij
Add context menu in bzrk.
100
        self.treeview.connect("button-release-event", 
101
                self._treeview_row_mouseclick)
256.4.4 by Gary van der Merwe
Use fixed-height-mode on treeview so that revisions data is only
102
        self.treeview.set_property('fixed-height-mode', True)
1 by Scott James Remnant
Commit the first version of bzrk.
103
        scrollwin.add(self.treeview)
104
        self.treeview.show()
105
256.2.27 by Gary van der Merwe
Show Revision No in tree
106
        cell = gtk.CellRendererText()
256.4.4 by Gary van der Merwe
Use fixed-height-mode on treeview so that revisions data is only
107
        cell.set_property("width-chars", 15)
256.4.1 by Gary van der Merwe
* Set a width and use ellips on Revision No column.
108
        cell.set_property("ellipsize", pango.ELLIPSIZE_END)
256.2.27 by Gary van der Merwe
Show Revision No in tree
109
        column = gtk.TreeViewColumn("Revision No")
110
        column.set_resizable(True)
256.4.4 by Gary van der Merwe
Use fixed-height-mode on treeview so that revisions data is only
111
        column.set_sizing(gtk.TREE_VIEW_COLUMN_FIXED)
112
        column.set_fixed_width(cell.get_size(self.treeview)[2])
256.2.27 by Gary van der Merwe
Show Revision No in tree
113
        column.pack_start(cell, expand=True)
256.2.29 by Gary van der Merwe
Implement a TreeModel that loads revisions incrementaly.
114
        column.add_attribute(cell, "text", treemodel.REVNO)
256.2.27 by Gary van der Merwe
Show Revision No in tree
115
        self.treeview.append_column(column)
116
256.4.1 by Gary van der Merwe
* Set a width and use ellips on Revision No column.
117
        self.graph_cell = CellRendererGraph()
256.4.4 by Gary van der Merwe
Use fixed-height-mode on treeview so that revisions data is only
118
        self.graph_column = gtk.TreeViewColumn()
119
        self.graph_column.set_resizable(True)
120
        self.graph_column.set_sizing(gtk.TREE_VIEW_COLUMN_FIXED)
121
        self.graph_column.pack_start(self.graph_cell, expand=False)
122
        self.graph_column.add_attribute(self.graph_cell, "node", treemodel.NODE)
123
        self.graph_column.add_attribute(self.graph_cell, "in-lines", treemodel.LAST_LINES)
124
        self.graph_column.add_attribute(self.graph_cell, "out-lines", treemodel.LINES)
125
        self.treeview.append_column(self.graph_column)
1 by Scott James Remnant
Commit the first version of bzrk.
126
127
        cell = gtk.CellRendererText()
298 by Daniel Schierbeck
Resized the Message and Committer columns in the revision history view.
128
        cell.set_property("width-chars", 65)
1 by Scott James Remnant
Commit the first version of bzrk.
129
        cell.set_property("ellipsize", pango.ELLIPSIZE_END)
130
        column = gtk.TreeViewColumn("Message")
131
        column.set_resizable(True)
256.4.4 by Gary van der Merwe
Use fixed-height-mode on treeview so that revisions data is only
132
        column.set_sizing(gtk.TREE_VIEW_COLUMN_FIXED)
133
        column.set_fixed_width(cell.get_size(self.treeview)[2])
1 by Scott James Remnant
Commit the first version of bzrk.
134
        column.pack_start(cell, expand=True)
256.2.29 by Gary van der Merwe
Implement a TreeModel that loads revisions incrementaly.
135
        column.add_attribute(cell, "text", treemodel.MESSAGE)
1 by Scott James Remnant
Commit the first version of bzrk.
136
        self.treeview.append_column(column)
137
138
        cell = gtk.CellRendererText()
298 by Daniel Schierbeck
Resized the Message and Committer columns in the revision history view.
139
        cell.set_property("width-chars", 15)
1 by Scott James Remnant
Commit the first version of bzrk.
140
        cell.set_property("ellipsize", pango.ELLIPSIZE_END)
141
        column = gtk.TreeViewColumn("Committer")
142
        column.set_resizable(True)
256.4.4 by Gary van der Merwe
Use fixed-height-mode on treeview so that revisions data is only
143
        column.set_sizing(gtk.TREE_VIEW_COLUMN_FIXED)
144
        column.set_fixed_width(cell.get_size(self.treeview)[2])
1 by Scott James Remnant
Commit the first version of bzrk.
145
        column.pack_start(cell, expand=True)
256.2.29 by Gary van der Merwe
Implement a TreeModel that loads revisions incrementaly.
146
        column.add_attribute(cell, "text", treemodel.COMMITER)
1 by Scott James Remnant
Commit the first version of bzrk.
147
        self.treeview.append_column(column)
148
44 by David Allouche
reorganise branch window
149
        return scrollwin
150
151
    def construct_navigation(self):
152
        """Construct the navigation buttons."""
153
        frame = gtk.Frame()
154
        frame.set_shadow_type(gtk.SHADOW_OUT)
155
        frame.show()
156
        
157
        hbox = gtk.HBox(spacing=12)
158
        frame.add(hbox)
3 by Scott James Remnant
Split the display in two with a pane, we'll use the bottom half to show
159
        hbox.show()
160
161
        self.back_button = gtk.Button(stock=gtk.STOCK_GO_BACK)
44 by David Allouche
reorganise branch window
162
        self.back_button.set_relief(gtk.RELIEF_NONE)
3 by Scott James Remnant
Split the display in two with a pane, we'll use the bottom half to show
163
        self.back_button.add_accelerator("clicked", self.accel_group, ord('['),
164
                                         0, 0)
165
        self.back_button.connect("clicked", self._back_clicked_cb)
166
        hbox.pack_start(self.back_button, expand=False, fill=True)
167
        self.back_button.show()
168
169
        self.fwd_button = gtk.Button(stock=gtk.STOCK_GO_FORWARD)
44 by David Allouche
reorganise branch window
170
        self.fwd_button.set_relief(gtk.RELIEF_NONE)
3 by Scott James Remnant
Split the display in two with a pane, we'll use the bottom half to show
171
        self.fwd_button.add_accelerator("clicked", self.accel_group, ord(']'),
172
                                        0, 0)
173
        self.fwd_button.connect("clicked", self._fwd_clicked_cb)
174
        hbox.pack_start(self.fwd_button, expand=False, fill=True)
175
        self.fwd_button.show()
176
44 by David Allouche
reorganise branch window
177
        return frame
3 by Scott James Remnant
Split the display in two with a pane, we'll use the bottom half to show
178
179
    def construct_bottom(self):
180
        """Construct the bottom half of the window."""
147 by Jelmer Vernooij
Remove a bunch of duplicate functionality.
181
        from bzrlib.plugins.gtk.logview import LogView
256.2.23 by Gary van der Merwe
Show Children
182
        self.logview = LogView(None, True, [], True)
44 by David Allouche
reorganise branch window
183
        (width, height) = self.get_size()
147 by Jelmer Vernooij
Remove a bunch of duplicate functionality.
184
        self.logview.set_size_request(width, int(height / 2.5))
185
        self.logview.show()
186
        self.logview.set_show_callback(self._show_clicked_cb)
187
        self.logview.set_go_callback(self._go_clicked_cb)
188
        return self.logview
3 by Scott James Remnant
Split the display in two with a pane, we'll use the bottom half to show
189
40 by David Allouche
remove --robust, pyflakes fixes, update README
190
    def set_branch(self, branch, start, maxnum):
1 by Scott James Remnant
Commit the first version of bzrk.
191
        """Set the branch and start position for this window.
192
193
        Creates a new TreeModel and populates it with information about
194
        the new branch before updating the window title and model of the
195
        treeview itself.
196
        """
10 by Scott James Remnant
Add an extra window type, clicking the little icons next to a parent
197
        self.branch = branch
292.2.1 by Daniel Schierbeck
Changed title of the viz window to 'revision history'
198
        self.set_title(branch.nick + " - revision history")
265.1.1 by Gary van der Merwe
Show bzr viz interface quickly.
199
        gobject.idle_add(self.populate_model, start, maxnum)
200
201
    def populate_model(self, start, maxnum):
256.4.1 by Gary van der Merwe
* Set a width and use ellips on Revision No column.
202
        (linegraphdata, index, columns_len) = linegraph(self.branch,
203
                                                        start,
204
                                                        maxnum)
256.2.29 by Gary van der Merwe
Implement a TreeModel that loads revisions incrementaly.
205
        self.model = TreeModel(self.branch, linegraphdata)
256.4.1 by Gary van der Merwe
* Set a width and use ellips on Revision No column.
206
        self.graph_cell.columns_len = columns_len
256.4.4 by Gary van der Merwe
Use fixed-height-mode on treeview so that revisions data is only
207
        width = self.graph_cell.get_size(self.treeview)[2]
208
        self.graph_column.set_fixed_width(width)
209
        self.graph_column.set_max_width(width)
256.2.21 by Gary van der Merwe
Refactor so that line graph is more contained.
210
        self.index = index
3 by Scott James Remnant
Split the display in two with a pane, we'll use the bottom half to show
211
        self.treeview.set_model(self.model)
280.1.1 by Daniel Schierbeck
Select the tip revision when opening the visualization window
212
        self.treeview.get_selection().select_path(0)
280.2.1 by Gary van der Merwe
Add a message to the viz window to indicate that graph is still loading.
213
        self.loading_msg_box.hide()
265.1.1 by Gary van der Merwe
Show bzr viz interface quickly.
214
        return False
215
    
280.1.2 by Daniel Schierbeck
Switched to handle the 'changed' signal from the treeview's treeselection instead of the 'cursor-changed' signal from the treeview itself, allowing more flexibility (particularly the ability to handle programmatic selections)
216
    def _treeselection_changed_cb(self, selection, *args):
217
        """Callback for when the treeview changes."""
218
        (model, selected_rows) = selection.get_selected_rows()
219
        if len(selected_rows) > 0:
256.2.62 by Gary van der Merwe
Merge Trunk.
220
            iter = self.model.get_iter(selected_rows[0])
221
            revision = self.model.get_value(iter, treemodel.REVISION)
222
            parents = self.model.get_value(iter, treemodel.PARENTS)
223
            children = self.model.get_value(iter, treemodel.CHILDREN)
224
            
225
            self.back_button.set_sensitive(len(parents) > 0)
226
            self.fwd_button.set_sensitive(len(children) > 0)
280.1.2 by Daniel Schierbeck
Switched to handle the 'changed' signal from the treeview's treeselection instead of the 'cursor-changed' signal from the treeview itself, allowing more flexibility (particularly the ability to handle programmatic selections)
227
            tags = []
228
            if self.branch.supports_tags():
229
                tagdict = self.branch.tags.get_reverse_tag_dict()
230
                if tagdict.has_key(revision.revision_id):
231
                    tags = tagdict[revision.revision_id]
256.2.62 by Gary van der Merwe
Merge Trunk.
232
            self.logview.set_revision(revision, tags, children)
7 by Scott James Remnant
Put some information about the highlighted revision in the bottom pane,
233
3 by Scott James Remnant
Split the display in two with a pane, we'll use the bottom half to show
234
    def _back_clicked_cb(self, *args):
235
        """Callback for when the back button is clicked."""
236
        (path, col) = self.treeview.get_cursor()
237
        revision = self.model[path][0]
256.2.4 by Gary van der Merwe
First go at using bzrlib graph code
238
        parents = self.model[path][4]
239
        if not len(parents):
3 by Scott James Remnant
Split the display in two with a pane, we'll use the bottom half to show
240
            return
241
256.2.4 by Gary van der Merwe
First go at using bzrlib graph code
242
        for parent_id in parents:
243
            parent = self.revisions[self.index[parent_id]]
3 by Scott James Remnant
Split the display in two with a pane, we'll use the bottom half to show
244
            if same_branch(revision, parent):
256.2.4 by Gary van der Merwe
First go at using bzrlib graph code
245
                self.treeview.set_cursor(self.index[parent_id])
3 by Scott James Remnant
Split the display in two with a pane, we'll use the bottom half to show
246
                break
247
        else:
256.2.4 by Gary van der Merwe
First go at using bzrlib graph code
248
            self.treeview.set_cursor(self.index[parents[0]])
13 by Scott James Remnant
Keep the focus on the treeview
249
        self.treeview.grab_focus()
3 by Scott James Remnant
Split the display in two with a pane, we'll use the bottom half to show
250
5 by Scott James Remnant
Reverse the meaning of the Back and Forward buttons so Back actually
251
    def _fwd_clicked_cb(self, *args):
252
        """Callback for when the forward button is clicked."""
253
        (path, col) = self.treeview.get_cursor()
254
        revision = self.model[path][0]
256.2.4 by Gary van der Merwe
First go at using bzrlib graph code
255
        children = self.model[path][5]
256
        if not len(children):
5 by Scott James Remnant
Reverse the meaning of the Back and Forward buttons so Back actually
257
            return
258
256.2.4 by Gary van der Merwe
First go at using bzrlib graph code
259
        for child_id in children:
260
            child = self.revisions[self.index[child_id]]
5 by Scott James Remnant
Reverse the meaning of the Back and Forward buttons so Back actually
261
            if same_branch(child, revision):
256.2.4 by Gary van der Merwe
First go at using bzrlib graph code
262
                self.treeview.set_cursor(self.index[child_id])
5 by Scott James Remnant
Reverse the meaning of the Back and Forward buttons so Back actually
263
                break
264
        else:
256.2.4 by Gary van der Merwe
First go at using bzrlib graph code
265
            self.treeview.set_cursor(self.index[children[0]])
13 by Scott James Remnant
Keep the focus on the treeview
266
        self.treeview.grab_focus()
7 by Scott James Remnant
Put some information about the highlighted revision in the bottom pane,
267
147 by Jelmer Vernooij
Remove a bunch of duplicate functionality.
268
    def _go_clicked_cb(self, revid):
7 by Scott James Remnant
Put some information about the highlighted revision in the bottom pane,
269
        """Callback for when the go button for a parent is clicked."""
256.2.4 by Gary van der Merwe
First go at using bzrlib graph code
270
        self.treeview.set_cursor(self.index[revid])
13 by Scott James Remnant
Keep the focus on the treeview
271
        self.treeview.grab_focus()
7 by Scott James Remnant
Put some information about the highlighted revision in the bottom pane,
272
152 by Jelmer Vernooij
Cleanup some more code.
273
    def show_diff(self, branch, revid, parentid):
274
        """Open a new window to show a diff between the given revisions."""
275
        from bzrlib.plugins.gtk.diff import DiffWindow
298.2.1 by Daniel Schierbeck
Refactored the GTK window code, creating a single base window class that handles keyboard events.
276
        window = DiffWindow(parent=self)
226 by Jelmer Vernooij
Add context menu in bzrk.
277
        (parent_tree, rev_tree) = branch.repository.revision_trees([parentid, 
278
                                                                   revid])
152 by Jelmer Vernooij
Cleanup some more code.
279
        description = revid + " - " + branch.nick
280
        window.set_diff(description, rev_tree, parent_tree)
281
        window.show()
282
147 by Jelmer Vernooij
Remove a bunch of duplicate functionality.
283
    def _show_clicked_cb(self, revid, parentid):
7 by Scott James Remnant
Put some information about the highlighted revision in the bottom pane,
284
        """Callback for when the show button for a parent is clicked."""
152 by Jelmer Vernooij
Cleanup some more code.
285
        self.show_diff(self.branch, revid, parentid)
13 by Scott James Remnant
Keep the focus on the treeview
286
        self.treeview.grab_focus()
46 by Wouter van Heyst
show diff on row activation, LP# 44591
287
226 by Jelmer Vernooij
Add context menu in bzrk.
288
    def _treeview_row_mouseclick(self, widget, event):
289
        from bzrlib.plugins.gtk.revisionmenu import RevisionPopupMenu
228 by Jelmer Vernooij
Remove unused code, prefer questions to check boxes.
290
        if event.button == 3:
291
            menu = RevisionPopupMenu(self.branch.repository, 
230 by Jelmer Vernooij
Initial work towards supporting multiple revisions.
292
                [x.revision_id for x in self.selected_revisions()],
293
                self.branch)
228 by Jelmer Vernooij
Remove unused code, prefer questions to check boxes.
294
            menu.popup(None, None, None, event.button, event.get_time())
226 by Jelmer Vernooij
Add context menu in bzrk.
295
296
    def selected_revision(self, path):
256.2.63 by Gary van der Merwe
Fix bug with revision menu.
297
        return self.model[path][treemodel.REVISION]
226 by Jelmer Vernooij
Add context menu in bzrk.
298
299
    def selected_revisions(self):
300
        return [self.selected_revision(path) for path in \
301
                self.treeview.get_selection().get_selected_rows()[1]]
302
47 by Wouter van Heyst
rename _treeview_clicked_cb to correcter _treeview_row_activated_cb
303
    def _treeview_row_activated_cb(self, widget, path, col):
46 by Wouter van Heyst
show diff on row activation, LP# 44591
304
        # TODO: more than one parent
47 by Wouter van Heyst
rename _treeview_clicked_cb to correcter _treeview_row_activated_cb
305
        """Callback for when a treeview row gets activated."""
289.1.1 by Gary van der Merwe
Fix vizchanges regression: Dbl click on a revision was not bringing up
306
        revision_id = self.model[path][treemodel.REVID]
307
        parents = self.model[path][treemodel.PARENTS]
308
        if len(parents) == 0:
74 by Jelmer Vernooij
Fix exception when double-clicking revision without parents.
309
            # Ignore revisions without parent
310
            return
289.1.1 by Gary van der Merwe
Fix vizchanges regression: Dbl click on a revision was not bringing up
311
        parent_id = parents[0]
312
        self.show_diff(self.branch, revision_id, parent_id)
46 by Wouter van Heyst
show diff on row activation, LP# 44591
313
        self.treeview.grab_focus()