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