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