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