/b-gtk/fix-viz

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/b-gtk/fix-viz
301 by Daniel Schierbeck
Initial work on extracting the TreeView from the branch window.
1
# -*- coding: UTF-8 -*-
2
"""Revision history view.
3
4
"""
5
6
__copyright__ = "Copyright © 2005 Canonical Ltd."
7
__author__    = "Daniel Schierbeck <daniel.schierbeck@gmail.com>"
8
314 by Daniel Schierbeck
Moved branch locking into treeview.
9
import sys
10
import string
301 by Daniel Schierbeck
Initial work on extracting the TreeView from the branch window.
11
import gtk
12
import gobject
13
import pango
14
import re
303 by Daniel Schierbeck
Made basic signaling work.
15
import treemodel
301 by Daniel Schierbeck
Initial work on extracting the TreeView from the branch window.
16
17
from linegraph import linegraph, same_branch
18
from graphcell import CellRendererGraph
19
from treemodel import TreeModel
330.4.3 by Daniel Schierbeck
Switched to using NULL_REVISION instead of None.
20
from bzrlib.revision import NULL_REVISION
301 by Daniel Schierbeck
Initial work on extracting the TreeView from the branch window.
21
303 by Daniel Schierbeck
Made basic signaling work.
22
class TreeView(gtk.ScrolledWindow):
301 by Daniel Schierbeck
Initial work on extracting the TreeView from the branch window.
23
346 by Daniel Schierbeck
Added revno-column-visible property to treeview.
24
    __gproperties__ = {
352 by Daniel Schierbeck
Added branch property to treeview.
25
        'branch': (gobject.TYPE_PYOBJECT,
26
                   'Branch',
27
                   'The Bazaar branch being visualized',
28
                   gobject.PARAM_CONSTRUCT_ONLY | gobject.PARAM_WRITABLE),
29
356 by Daniel Schierbeck
Made revision a property on TreeView.
30
        'revision': (gobject.TYPE_PYOBJECT,
31
                     'Revision',
32
                     'The currently selected revision',
33
                     gobject.PARAM_READWRITE),
34
346 by Daniel Schierbeck
Added revno-column-visible property to treeview.
35
        'revno-column-visible': (gobject.TYPE_BOOLEAN,
36
                                 'Revision number',
37
                                 'Show revision number column',
38
                                 True,
357 by Daniel Schierbeck
Added support for showing the date column in the viz.
39
                                 gobject.PARAM_READWRITE),
40
41
        'date-column-visible': (gobject.TYPE_BOOLEAN,
42
                                 'Revision number',
43
                                 'Show revision number column',
44
                                 False,
346 by Daniel Schierbeck
Added revno-column-visible property to treeview.
45
                                 gobject.PARAM_READWRITE)
357 by Daniel Schierbeck
Added support for showing the date column in the viz.
46
346 by Daniel Schierbeck
Added revno-column-visible property to treeview.
47
    }
48
307 by Daniel Schierbeck
Made load notification work again.
49
    __gsignals__ = {
345 by Daniel Schierbeck
Made treeview columns instance variables.
50
        'revisions-loaded': (gobject.SIGNAL_RUN_FIRST, 
51
                             gobject.TYPE_NONE,
52
                             ()),
53
        'revision-selected': (gobject.SIGNAL_RUN_FIRST,
54
                              gobject.TYPE_NONE,
55
                              ())
307 by Daniel Schierbeck
Made load notification work again.
56
    }
57
329 by Jelmer Vernooij
Make broken_line_length setting from higher up.
58
    def __init__(self, branch, start, maxnum, broken_line_length=None):
322 by Jelmer Vernooij
Add docstrings.
59
        """Create a new TreeView.
60
61
        :param branch: Branch object for branch to show.
62
        :param start: Revision id of top revision.
63
        :param maxnum: Maximum number of revisions to display, 
64
                       None for no limit.
329 by Jelmer Vernooij
Make broken_line_length setting from higher up.
65
        :param broken_line_length: After how much lines to break 
66
                                   branches.
322 by Jelmer Vernooij
Add docstrings.
67
        """
301 by Daniel Schierbeck
Initial work on extracting the TreeView from the branch window.
68
        gtk.ScrolledWindow.__init__(self)
69
303 by Daniel Schierbeck
Made basic signaling work.
70
        self.set_policy(gtk.POLICY_NEVER, gtk.POLICY_AUTOMATIC)
301 by Daniel Schierbeck
Initial work on extracting the TreeView from the branch window.
71
        self.set_shadow_type(gtk.SHADOW_IN)
72
303 by Daniel Schierbeck
Made basic signaling work.
73
        self.construct_treeview()
74
316 by Daniel Schierbeck
Removed viz.TreeView.set_branch()
75
        self.branch = branch
76
        self.branch.lock_read()
77
329 by Jelmer Vernooij
Make broken_line_length setting from higher up.
78
        gobject.idle_add(self.populate, start, maxnum, 
79
                         broken_line_length)
316 by Daniel Schierbeck
Removed viz.TreeView.set_branch()
80
303 by Daniel Schierbeck
Made basic signaling work.
81
        self.revision = None
82
        self.children = None
83
        self.parents  = None
84
314 by Daniel Schierbeck
Moved branch locking into treeview.
85
        self.connect('destroy', lambda w: self.branch.unlock())
86
347 by Daniel Schierbeck
Added property getter and setter method to the treeview.
87
    def do_get_property(self, property):
88
        if property.name == 'revno-column-visible':
352 by Daniel Schierbeck
Added branch property to treeview.
89
            return self.revno_column.get_visible()
357 by Daniel Schierbeck
Added support for showing the date column in the viz.
90
        elif property.name == 'date-column-visible':
91
            return self.date_column.get_visible()
352 by Daniel Schierbeck
Added branch property to treeview.
92
        elif property.name == 'branch':
93
            return self.branch
356 by Daniel Schierbeck
Made revision a property on TreeView.
94
        elif property.name == 'revision':
95
            return self.revision
347 by Daniel Schierbeck
Added property getter and setter method to the treeview.
96
        else:
97
            raise AttributeError, 'unknown property %s' % property.name
98
99
    def do_set_property(self, property, value):
100
        if property.name == 'revno-column-visible':
101
            self.revno_column.set_visible(value)
357 by Daniel Schierbeck
Added support for showing the date column in the viz.
102
        elif property.name == 'date-column-visible':
103
            self.date_column.set_visible(value)
352 by Daniel Schierbeck
Added branch property to treeview.
104
        elif property.name == 'branch':
105
            self.branch = value
356 by Daniel Schierbeck
Made revision a property on TreeView.
106
        elif property.name == 'revision':
107
            self.set_revision_id(value.revision_id)
347 by Daniel Schierbeck
Added property getter and setter method to the treeview.
108
        else:
109
            raise AttributeError, 'unknown property %s' % property.name
110
303 by Daniel Schierbeck
Made basic signaling work.
111
    def get_revision(self):
322 by Jelmer Vernooij
Add docstrings.
112
        """Return revision id of currently selected revision, or None."""
303 by Daniel Schierbeck
Made basic signaling work.
113
        return self.revision
114
356 by Daniel Schierbeck
Made revision a property on TreeView.
115
    def set_revision_id(self, revid):
322 by Jelmer Vernooij
Add docstrings.
116
        """Change the currently selected revision.
117
118
        :param revid: Revision id of revision to display.
119
        """
305 by Daniel Schierbeck
Moved revision selection to the new view.
120
        self.treeview.set_cursor(self.index[revid])
121
        self.treeview.grab_focus()
122
303 by Daniel Schierbeck
Made basic signaling work.
123
    def get_children(self):
322 by Jelmer Vernooij
Add docstrings.
124
        """Return the children of the currently selected revision.
125
126
        :return: list of revision ids.
127
        """
303 by Daniel Schierbeck
Made basic signaling work.
128
        return self.children
129
130
    def get_parents(self):
322 by Jelmer Vernooij
Add docstrings.
131
        """Return the parents of the currently selected revision.
132
133
        :return: list of revision ids.
134
        """
303 by Daniel Schierbeck
Made basic signaling work.
135
        return self.parents
316 by Daniel Schierbeck
Removed viz.TreeView.set_branch()
136
        
304 by Daniel Schierbeck
Made forward/back buttons work again.
137
    def back(self):
322 by Jelmer Vernooij
Add docstrings.
138
        """Signal handler for the Back button."""
304 by Daniel Schierbeck
Made forward/back buttons work again.
139
        (path, col) = self.treeview.get_cursor()
140
        revision = self.model[path][treemodel.REVISION]
141
        parents = self.model[path][treemodel.PARENTS]
142
        if not len(parents):
143
            return
144
145
        for parent_id in parents:
146
            parent_index = self.index[parent_id]
147
            parent = self.model[parent_index][treemodel.REVISION]
148
            if same_branch(revision, parent):
149
                self.treeview.set_cursor(parent_index)
150
                break
151
        else:
152
            self.treeview.set_cursor(self.index[parents[0]])
153
        self.treeview.grab_focus()
154
155
    def forward(self):
322 by Jelmer Vernooij
Add docstrings.
156
        """Signal handler for the Forward button."""
304 by Daniel Schierbeck
Made forward/back buttons work again.
157
        (path, col) = self.treeview.get_cursor()
158
        revision = self.model[path][treemodel.REVISION]
159
        children = self.model[path][treemodel.CHILDREN]
160
        if not len(children):
161
            return
162
163
        for child_id in children:
164
            child_index = self.index[child_id]
165
            child = self.model[child_index][treemodel.REVISION]
166
            if same_branch(child, revision):
167
                self.treeview.set_cursor(child_index)
168
                break
169
        else:
170
            self.treeview.set_cursor(self.index[children[0]])
171
        self.treeview.grab_focus()
172
329 by Jelmer Vernooij
Make broken_line_length setting from higher up.
173
    def populate(self, start, maxnum, broken_line_length=None):
322 by Jelmer Vernooij
Add docstrings.
174
        """Fill the treeview with contents.
175
176
        :param start: Revision id of revision to start with.
177
        :param maxnum: Maximum number of revisions to display, or None 
178
                       for no limit.
329 by Jelmer Vernooij
Make broken_line_length setting from higher up.
179
        :param broken_line_length: After how much lines branches \
180
                       should be broken.
322 by Jelmer Vernooij
Add docstrings.
181
        """
328 by Jelmer Vernooij
Use repository instead of branch in more places, to make it easier to support multiple branches in viz.
182
        (linegraphdata, index, columns_len) = linegraph(self.branch.repository,
304 by Daniel Schierbeck
Made forward/back buttons work again.
183
                                                        start,
329 by Jelmer Vernooij
Make broken_line_length setting from higher up.
184
                                                        maxnum, 
185
                                                        broken_line_length)
304 by Daniel Schierbeck
Made forward/back buttons work again.
186
328 by Jelmer Vernooij
Use repository instead of branch in more places, to make it easier to support multiple branches in viz.
187
        self.model = TreeModel(self.branch.repository, linegraphdata)
304 by Daniel Schierbeck
Made forward/back buttons work again.
188
        self.graph_cell.columns_len = columns_len
189
        width = self.graph_cell.get_size(self.treeview)[2]
190
        self.graph_column.set_fixed_width(width)
191
        self.graph_column.set_max_width(width)
192
        self.index = index
193
        self.treeview.set_model(self.model)
194
        self.treeview.set_cursor(0)
307 by Daniel Schierbeck
Made load notification work again.
195
        self.emit('revisions-loaded')
304 by Daniel Schierbeck
Made forward/back buttons work again.
196
197
        return False
198
330.4.1 by Daniel Schierbeck
Made it possible to view the diff of an orphant revision.
199
    def show_diff(self, branch, revid, parentid=None):
306 by Daniel Schierbeck
Made clicking a row work again.
200
        """Open a new window to show a diff between the given revisions."""
201
        from bzrlib.plugins.gtk.diff import DiffWindow
202
        window = DiffWindow(parent=self)
330.4.1 by Daniel Schierbeck
Made it possible to view the diff of an orphant revision.
203
344 by Daniel Schierbeck
Minor code formatting fix.
204
        rev_tree = branch.repository.revision_tree(revid)
330.4.3 by Daniel Schierbeck
Switched to using NULL_REVISION instead of None.
205
206
        if parentid is None:
207
            parentid = NULL_REVISION
208
330.4.1 by Daniel Schierbeck
Made it possible to view the diff of an orphant revision.
209
        parent_tree = branch.repository.revision_tree(parentid)
210
306 by Daniel Schierbeck
Made clicking a row work again.
211
        description = revid + " - " + branch.nick
212
        window.set_diff(description, rev_tree, parent_tree)
213
        window.show()
214
301 by Daniel Schierbeck
Initial work on extracting the TreeView from the branch window.
215
    def construct_treeview(self):
216
        self.treeview = gtk.TreeView()
217
218
        self.treeview.set_rules_hint(True)
330.1.2 by Daniel Schierbeck
Replaced literal column index with equivalent symbol.
219
        self.treeview.set_search_column(treemodel.REVNO)
330.1.1 by Daniel Schierbeck
Added tooltip to the treeview.
220
        self.treeview.set_tooltip_column(treemodel.MESSAGE)
301 by Daniel Schierbeck
Initial work on extracting the TreeView from the branch window.
221
303 by Daniel Schierbeck
Made basic signaling work.
222
        self.treeview.get_selection().connect("changed",
301 by Daniel Schierbeck
Initial work on extracting the TreeView from the branch window.
223
                self._on_selection_changed)
224
225
        self.treeview.connect("row-activated", 
226
                self._on_revision_activated)
227
228
        self.treeview.connect("button-release-event", 
229
                self._on_revision_selected)
230
231
        self.treeview.set_property('fixed-height-mode', True)
232
233
        self.add(self.treeview)
234
        self.treeview.show()
235
236
        cell = gtk.CellRendererText()
237
        cell.set_property("width-chars", 15)
238
        cell.set_property("ellipsize", pango.ELLIPSIZE_END)
345 by Daniel Schierbeck
Made treeview columns instance variables.
239
        self.revno_column = gtk.TreeViewColumn("Revision No")
240
        self.revno_column.set_resizable(True)
241
        self.revno_column.set_sizing(gtk.TREE_VIEW_COLUMN_FIXED)
242
        self.revno_column.set_fixed_width(cell.get_size(self.treeview)[2])
243
        self.revno_column.pack_start(cell, expand=True)
244
        self.revno_column.add_attribute(cell, "text", treemodel.REVNO)
245
        self.treeview.append_column(self.revno_column)
301 by Daniel Schierbeck
Initial work on extracting the TreeView from the branch window.
246
247
        self.graph_cell = CellRendererGraph()
248
        self.graph_column = gtk.TreeViewColumn()
249
        self.graph_column.set_resizable(True)
250
        self.graph_column.set_sizing(gtk.TREE_VIEW_COLUMN_FIXED)
251
        self.graph_column.pack_start(self.graph_cell, expand=False)
252
        self.graph_column.add_attribute(self.graph_cell, "node", treemodel.NODE)
253
        self.graph_column.add_attribute(self.graph_cell, "in-lines", treemodel.LAST_LINES)
254
        self.graph_column.add_attribute(self.graph_cell, "out-lines", treemodel.LINES)
255
        self.treeview.append_column(self.graph_column)
256
257
        cell = gtk.CellRendererText()
258
        cell.set_property("width-chars", 65)
259
        cell.set_property("ellipsize", pango.ELLIPSIZE_END)
345 by Daniel Schierbeck
Made treeview columns instance variables.
260
        self.msg_column = gtk.TreeViewColumn("Message")
261
        self.msg_column.set_resizable(True)
262
        self.msg_column.set_sizing(gtk.TREE_VIEW_COLUMN_FIXED)
263
        self.msg_column.set_fixed_width(cell.get_size(self.treeview)[2])
264
        self.msg_column.pack_start(cell, expand=True)
265
        self.msg_column.add_attribute(cell, "text", treemodel.MESSAGE)
266
        self.treeview.append_column(self.msg_column)
301 by Daniel Schierbeck
Initial work on extracting the TreeView from the branch window.
267
268
        cell = gtk.CellRendererText()
269
        cell.set_property("width-chars", 15)
270
        cell.set_property("ellipsize", pango.ELLIPSIZE_END)
345 by Daniel Schierbeck
Made treeview columns instance variables.
271
        self.committer_column = gtk.TreeViewColumn("Committer")
272
        self.committer_column.set_resizable(True)
273
        self.committer_column.set_sizing(gtk.TREE_VIEW_COLUMN_FIXED)
274
        self.committer_column.set_fixed_width(cell.get_size(self.treeview)[2])
275
        self.committer_column.pack_start(cell, expand=True)
276
        self.committer_column.add_attribute(cell, "text", treemodel.COMMITER)
277
        self.treeview.append_column(self.committer_column)
301 by Daniel Schierbeck
Initial work on extracting the TreeView from the branch window.
278
357 by Daniel Schierbeck
Added support for showing the date column in the viz.
279
        cell = gtk.CellRendererText()
359 by Daniel Schierbeck
Simplified date format.
280
        cell.set_property("width-chars", 20)
357 by Daniel Schierbeck
Added support for showing the date column in the viz.
281
        cell.set_property("ellipsize", pango.ELLIPSIZE_END)
282
        self.date_column = gtk.TreeViewColumn("Date")
283
        self.date_column.set_visible(False)
284
        self.date_column.set_resizable(True)
285
        self.date_column.set_sizing(gtk.TREE_VIEW_COLUMN_FIXED)
286
        self.date_column.set_fixed_width(cell.get_size(self.treeview)[2])
287
        self.date_column.pack_start(cell, expand=True)
288
        self.date_column.add_attribute(cell, "text", treemodel.TIMESTAMP)
289
        self.treeview.append_column(self.date_column)
290
301 by Daniel Schierbeck
Initial work on extracting the TreeView from the branch window.
291
    def _on_selection_changed(self, selection, *args):
303 by Daniel Schierbeck
Made basic signaling work.
292
        """callback for when the treeview changes."""
301 by Daniel Schierbeck
Initial work on extracting the TreeView from the branch window.
293
        (model, selected_rows) = selection.get_selected_rows()
294
        if len(selected_rows) > 0:
295
            iter = self.model.get_iter(selected_rows[0])
303 by Daniel Schierbeck
Made basic signaling work.
296
            self.revision = self.model.get_value(iter, treemodel.REVISION)
297
            self.parents = self.model.get_value(iter, treemodel.PARENTS)
298
            self.children = self.model.get_value(iter, treemodel.CHILDREN)
301 by Daniel Schierbeck
Initial work on extracting the TreeView from the branch window.
299
310 by Daniel Schierbeck
Moved to using custom signal for handling revision selections.
300
            self.emit('revision-selected')
301
301 by Daniel Schierbeck
Initial work on extracting the TreeView from the branch window.
302
    def _on_revision_selected(self, widget, event):
303
        from bzrlib.plugins.gtk.revisionmenu import RevisionPopupMenu
304
        if event.button == 3:
305
            menu = RevisionPopupMenu(self.branch.repository, 
312 by Daniel Schierbeck
Made right-clicking work again.
306
                [self.get_revision().revision_id],
301 by Daniel Schierbeck
Initial work on extracting the TreeView from the branch window.
307
                self.branch)
308
            menu.popup(None, None, None, event.button, event.get_time())
309
310
    def _on_revision_activated(self, widget, path, col):
311
        # TODO: more than one parent
312
        """Callback for when a treeview row gets activated."""
313
        revision_id = self.model[path][treemodel.REVID]
314
        parents = self.model[path][treemodel.PARENTS]
330.4.1 by Daniel Schierbeck
Made it possible to view the diff of an orphant revision.
315
301 by Daniel Schierbeck
Initial work on extracting the TreeView from the branch window.
316
        if len(parents) == 0:
330.4.1 by Daniel Schierbeck
Made it possible to view the diff of an orphant revision.
317
            parent_id = None
318
        else:
319
            parent_id = parents[0]
320
301 by Daniel Schierbeck
Initial work on extracting the TreeView from the branch window.
321
        self.show_diff(self.branch, revision_id, parent_id)
322
        self.treeview.grab_focus()