/b-gtk/fix-viz

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/b-gtk/fix-viz

« back to all changes in this revision

Viewing changes to branchview/treeview.py

  • Committer: Curtis Hovey
  • Date: 2012-02-05 05:14:11 UTC
  • mto: This revision was merged to the branch mainline in revision 775.
  • Revision ID: sinzui.is@verizon.net-20120205051411-y9ra08wae1wsfv52
Remove unneeded gtksourceview1 support.

Show diffs side-by-side

added added

removed removed

Lines of Context:
6
6
__copyright__ = "Copyright © 2005 Canonical Ltd."
7
7
__author__    = "Daniel Schierbeck <daniel.schierbeck@gmail.com>"
8
8
 
9
 
import gtk
10
 
import gobject
11
 
import pango
12
 
import treemodel
 
9
from gi.repository import Gtk
 
10
from gi.repository import GObject
 
11
from gi.repository import Pango
 
12
 
13
13
from bzrlib import ui
14
 
 
15
 
from bzrlib.plugins.gtk.ui import ProgressPanel
16
 
from linegraph import linegraph, same_branch
17
 
from graphcell import CellRendererGraph
18
 
from treemodel import TreeModel
19
14
from bzrlib.revision import NULL_REVISION
 
15
 
20
16
from bzrlib.plugins.gtk import lock
21
 
 
22
 
 
23
 
class TreeView(gtk.VBox):
 
17
from bzrlib.plugins.gtk.ui import ProgressPanel
 
18
from bzrlib.plugins.gtk.branchview import treemodel
 
19
from bzrlib.plugins.gtk.branchview.linegraph import linegraph, same_branch
 
20
from bzrlib.plugins.gtk.branchview.graphcell import CellRendererGraph
 
21
 
 
22
 
 
23
class TreeView(Gtk.VBox):
24
24
 
25
25
    __gproperties__ = {
26
 
        'branch': (gobject.TYPE_PYOBJECT,
 
26
        'branch': (GObject.TYPE_PYOBJECT,
27
27
                   'Branch',
28
28
                   'The Bazaar branch being visualized',
29
 
                   gobject.PARAM_CONSTRUCT_ONLY | gobject.PARAM_WRITABLE),
 
29
                   GObject.PARAM_CONSTRUCT_ONLY | GObject.PARAM_WRITABLE),
30
30
 
31
 
        'revision': (gobject.TYPE_PYOBJECT,
 
31
        'revision': (GObject.TYPE_PYOBJECT,
32
32
                     'Revision',
33
33
                     'The currently selected revision',
34
 
                     gobject.PARAM_READWRITE),
 
34
                     GObject.PARAM_READWRITE),
35
35
 
36
 
        'revision-number': (gobject.TYPE_STRING,
 
36
        'revision-number': (GObject.TYPE_STRING,
37
37
                            'Revision number',
38
38
                            'The number of the selected revision',
39
39
                            '',
40
 
                            gobject.PARAM_READABLE),
 
40
                            GObject.PARAM_READABLE),
41
41
 
42
 
        'children': (gobject.TYPE_PYOBJECT,
 
42
        'children': (GObject.TYPE_PYOBJECT,
43
43
                     'Child revisions',
44
44
                     'Children of the currently selected revision',
45
 
                     gobject.PARAM_READABLE),
 
45
                     GObject.PARAM_READABLE),
46
46
 
47
 
        'parents': (gobject.TYPE_PYOBJECT,
 
47
        'parents': (GObject.TYPE_PYOBJECT,
48
48
                    'Parent revisions',
49
49
                    'Parents to the currently selected revision',
50
 
                    gobject.PARAM_READABLE),
 
50
                    GObject.PARAM_READABLE),
51
51
 
52
 
        'revno-column-visible': (gobject.TYPE_BOOLEAN,
 
52
        'revno-column-visible': (GObject.TYPE_BOOLEAN,
53
53
                                 'Revision number column',
54
54
                                 'Show revision number column',
55
55
                                 True,
56
 
                                 gobject.PARAM_READWRITE),
 
56
                                 GObject.PARAM_READWRITE),
57
57
 
58
 
        'graph-column-visible': (gobject.TYPE_BOOLEAN,
 
58
        'graph-column-visible': (GObject.TYPE_BOOLEAN,
59
59
                                 'Graph column',
60
60
                                 'Show graph column',
61
61
                                 True,
62
 
                                 gobject.PARAM_READWRITE),
 
62
                                 GObject.PARAM_READWRITE),
63
63
 
64
 
        'date-column-visible': (gobject.TYPE_BOOLEAN,
 
64
        'date-column-visible': (GObject.TYPE_BOOLEAN,
65
65
                                 'Date',
66
66
                                 'Show date column',
67
67
                                 False,
68
 
                                 gobject.PARAM_READWRITE),
 
68
                                 GObject.PARAM_READWRITE),
69
69
 
70
 
        'compact': (gobject.TYPE_BOOLEAN,
 
70
        'compact': (GObject.TYPE_BOOLEAN,
71
71
                    'Compact view',
72
72
                    'Break ancestry lines to save space',
73
73
                    True,
74
 
                    gobject.PARAM_CONSTRUCT | gobject.PARAM_READWRITE),
 
74
                    GObject.PARAM_CONSTRUCT | GObject.PARAM_READWRITE),
75
75
 
76
 
        'mainline-only': (gobject.TYPE_BOOLEAN,
 
76
        'mainline-only': (GObject.TYPE_BOOLEAN,
77
77
                    'Mainline only',
78
78
                    'Only show the mainline history.',
79
79
                    False,
80
 
                    gobject.PARAM_CONSTRUCT | gobject.PARAM_READWRITE),
 
80
                    GObject.PARAM_CONSTRUCT | GObject.PARAM_READWRITE),
81
81
 
82
82
    }
83
83
 
84
84
    __gsignals__ = {
85
 
        'revision-selected': (gobject.SIGNAL_RUN_FIRST,
86
 
                              gobject.TYPE_NONE,
 
85
        'revision-selected': (GObject.SignalFlags.RUN_FIRST,
 
86
                              None,
87
87
                              ()),
88
 
        'revision-activated': (gobject.SIGNAL_RUN_FIRST,
89
 
                              gobject.TYPE_NONE,
90
 
                              (gobject.TYPE_PYOBJECT, gobject.TYPE_PYOBJECT)),
91
 
        'tag-added': (gobject.SIGNAL_RUN_FIRST,
92
 
                              gobject.TYPE_NONE,
93
 
                              (gobject.TYPE_STRING, gobject.TYPE_STRING)),
94
 
        'refreshed': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
 
88
        'revision-activated': (GObject.SignalFlags.RUN_FIRST,
 
89
                              None,
 
90
                              (GObject.TYPE_PYOBJECT, GObject.TYPE_PYOBJECT)),
 
91
        'tag-added': (GObject.SignalFlags.RUN_FIRST,
 
92
                              None,
 
93
                              (GObject.TYPE_STRING, GObject.TYPE_STRING)),
 
94
        'refreshed': (GObject.SignalFlags.RUN_FIRST, None,
95
95
                              ())
96
96
    }
97
97
 
105
105
        :param broken_line_length: After how much lines to break 
106
106
                                   branches.
107
107
        """
108
 
        gtk.VBox.__init__(self, spacing=0)
 
108
        super(TreeView, self).__init__(homogeneous=False, spacing=0)
109
109
 
110
110
        self.progress_widget = ProgressPanel()
111
 
        self.pack_start(self.progress_widget, expand=False, fill=True)
 
111
        self.pack_start(self.progress_widget, False, True, 0)
112
112
        if getattr(ui.ui_factory, "set_progress_bar_widget", None) is not None:
113
113
            # We'are using our own ui, let's tell it to use our widget.
114
114
            ui.ui_factory.set_progress_bar_widget(self.progress_widget)
115
115
 
116
 
        self.scrolled_window = gtk.ScrolledWindow()
117
 
        self.scrolled_window.set_policy(gtk.POLICY_AUTOMATIC,
118
 
                                        gtk.POLICY_AUTOMATIC)
119
 
        self.scrolled_window.set_shadow_type(gtk.SHADOW_IN)
 
116
        self.scrolled_window = Gtk.ScrolledWindow()
 
117
        self.scrolled_window.set_policy(Gtk.PolicyType.AUTOMATIC,
 
118
                                        Gtk.PolicyType.AUTOMATIC)
 
119
        self.scrolled_window.set_shadow_type(Gtk.ShadowType.IN)
120
120
        self.scrolled_window.show()
121
 
        self.pack_start(self.scrolled_window, expand=True, fill=True)
 
121
        self.pack_start(self.scrolled_window, True, True, 0)
122
122
 
123
123
        self.scrolled_window.add(self.construct_treeview())
124
124
 
131
131
        self.maxnum = maxnum
132
132
        self.compact = compact
133
133
 
134
 
        gobject.idle_add(self.populate)
 
134
        self.model = treemodel.BranchTreeModel(self.branch, [])
 
135
        GObject.idle_add(self.populate)
135
136
 
136
137
        self.connect("destroy", self._on_destroy)
137
138
 
155
156
        elif property.name == 'branch':
156
157
            return self.branch
157
158
        elif property.name == 'revision':
 
159
            if self.path is None:
 
160
                return None
158
161
            return self.model.get_value(self.model.get_iter(self.path),
159
162
                                        treemodel.REVISION)
160
163
        elif property.name == 'revision-number':
 
164
            if self.path is None:
 
165
                return None
161
166
            return self.model.get_value(self.model.get_iter(self.path),
162
167
                                        treemodel.REVNO)
163
168
        elif property.name == 'children':
 
169
            if self.path is None:
 
170
                return None
164
171
            return self.model.get_value(self.model.get_iter(self.path),
165
172
                                        treemodel.CHILDREN)
166
173
        elif property.name == 'parents':
 
174
            if self.path is None:
 
175
                return None
167
176
            return self.model.get_value(self.model.get_iter(self.path),
168
177
                                        treemodel.PARENTS)
169
178
        else:
202
211
 
203
212
        :param revid: Revision id of revision to display.
204
213
        """
205
 
        self.treeview.set_cursor(self.index[revid])
 
214
        self.treeview.set_cursor(
 
215
            Gtk.TreePath(path=self.index[revid]), None, False)
206
216
        self.treeview.grab_focus()
207
217
 
208
218
    def get_children(self):
232
242
            lock.acquire(self.branch, lock.READ)
233
243
 
234
244
            self.emit('tag-added', tag, revid)
235
 
        
 
245
 
236
246
    def refresh(self):
237
 
        gobject.idle_add(self.populate, self.get_revision())
 
247
        GObject.idle_add(self.populate, self.get_revision())
238
248
 
239
249
    def update(self):
240
250
        try:
250
260
    def back(self):
251
261
        """Signal handler for the Back button."""
252
262
        parents = self.get_parents()
253
 
        if not len(parents):
 
263
        if not parents:
254
264
            return
255
265
 
256
266
        for parent_id in parents:
265
275
    def forward(self):
266
276
        """Signal handler for the Forward button."""
267
277
        children = self.get_children()
268
 
        if not len(children):
 
278
        if not children:
269
279
            return
270
280
 
271
281
        for child_id in children:
298
308
                broken_line_length = 32
299
309
            else:
300
310
                broken_line_length = None
301
 
            
 
311
 
302
312
            show_graph = self.graph_column.get_visible()
303
313
 
304
314
            self.branch.lock_read()
305
 
            (linegraphdata, index, columns_len) = linegraph(self.branch.repository.get_graph(),
306
 
                                                            self.start,
307
 
                                                            self.maxnum, 
308
 
                                                            broken_line_length,
309
 
                                                            show_graph,
310
 
                                                            self.mainline_only,
311
 
                                                            self.progress_bar)
 
315
            (linegraphdata, index, columns_len) = linegraph(
 
316
                self.branch.repository.get_graph(),
 
317
                self.start,
 
318
                self.maxnum, 
 
319
                broken_line_length,
 
320
                show_graph,
 
321
                self.mainline_only,
 
322
                self.progress_bar)
312
323
 
313
 
            self.model = TreeModel(self.branch, linegraphdata)
 
324
            self.model.set_line_graph_data(linegraphdata)
314
325
            self.graph_cell.columns_len = columns_len
315
 
            width = self.graph_cell.get_size(self.treeview)[2]
 
326
            width = self.graph_cell.get_preferred_width(self.treeview)[1]
316
327
            if width > 500:
317
328
                width = 500
 
329
            elif width == 0:
 
330
                # The get_preferred_width() call got an insane value.
 
331
                width = 200
318
332
            self.graph_column.set_fixed_width(width)
319
333
            self.graph_column.set_max_width(width)
320
334
            self.index = index
321
335
            self.treeview.set_model(self.model)
322
336
 
323
337
            if not revision or revision == NULL_REVISION:
324
 
                self.treeview.set_cursor(0)
 
338
                self.treeview.set_cursor(Gtk.TreePath(path=0), None, False)
325
339
            else:
326
340
                self.set_revision(revision)
327
341
 
331
345
            self.progress_bar.finished()
332
346
 
333
347
    def construct_treeview(self):
334
 
        self.treeview = gtk.TreeView()
 
348
        self.treeview = Gtk.TreeView()
335
349
 
336
350
        self.treeview.set_rules_hint(True)
337
 
        self.treeview.set_search_column(treemodel.REVNO)
338
 
        
339
 
        # Fix old PyGTK bug - by JAM
340
 
        set_tooltip = getattr(self.treeview, 'set_tooltip_column', None)
341
 
        if set_tooltip is not None:
342
 
            set_tooltip(treemodel.MESSAGE)
 
351
        # combined revno/summary interactive search
 
352
        #
 
353
        # the row in a treemodel is considered "matched" if a REVNO *starts*
 
354
        # from the key (that is the key is found in a REVNO at the offset 0)
 
355
        # or if a MESSAGE *contains* the key anywhere (that is, the key is
 
356
        # found case insensitively in a MESSAGE at any offset)
 
357
        def search_equal_func(model, column, key, iter):
 
358
            return (model.get_value(iter, treemodel.REVNO).find(key) != 0
 
359
                and model.get_value(iter, treemodel.MESSAGE).lower().find(key.lower()) == -1)
 
360
 
 
361
        self.treeview.set_search_equal_func(search_equal_func, None)
 
362
        self.treeview.set_enable_search(True)
 
363
 
 
364
        self.treeview.set_tooltip_column(treemodel.MESSAGE)
 
365
        self.treeview.set_headers_visible(True)
343
366
 
344
367
        self._prev_cursor_path = None
345
368
        self.treeview.connect("cursor-changed",
355
378
 
356
379
        self.treeview.show()
357
380
 
358
 
        cell = gtk.CellRendererText()
 
381
        cell = Gtk.CellRendererText()
359
382
        cell.set_property("width-chars", 15)
360
 
        cell.set_property("ellipsize", pango.ELLIPSIZE_END)
361
 
        self.revno_column = gtk.TreeViewColumn("Revision No")
362
 
        self.revno_column.set_resizable(False)
363
 
        self.revno_column.set_sizing(gtk.TREE_VIEW_COLUMN_FIXED)
364
 
        self.revno_column.set_fixed_width(cell.get_size(self.treeview)[2])
365
 
        self.revno_column.pack_start(cell, expand=True)
 
383
        cell.set_property("ellipsize", Pango.EllipsizeMode.END)
 
384
        self.revno_column = Gtk.TreeViewColumn("Revision No")
 
385
        self.revno_column.set_resizable(True)
 
386
        self.revno_column.set_sizing(Gtk.TreeViewColumnSizing.FIXED)
 
387
        self.revno_column.set_fixed_width(
 
388
            cell.get_preferred_width(self.treeview)[1])
 
389
        self.revno_column.pack_start(cell, True)
366
390
        self.revno_column.add_attribute(cell, "text", treemodel.REVNO)
367
391
        self.treeview.append_column(self.revno_column)
368
392
 
369
393
        self.graph_cell = CellRendererGraph()
370
 
        self.graph_column = gtk.TreeViewColumn()
371
 
        self.graph_column.set_resizable(False)
372
 
        self.graph_column.set_sizing(gtk.TREE_VIEW_COLUMN_FIXED)
373
 
        self.graph_column.pack_start(self.graph_cell, expand=True)
374
 
        self.graph_column.add_attribute(self.graph_cell, "node", treemodel.NODE)
375
 
        self.graph_column.add_attribute(self.graph_cell, "tags", treemodel.TAGS)
376
 
        self.graph_column.add_attribute(self.graph_cell, "in-lines", treemodel.LAST_LINES)
377
 
        self.graph_column.add_attribute(self.graph_cell, "out-lines", treemodel.LINES)
 
394
        self.graph_column = Gtk.TreeViewColumn()
 
395
        self.graph_column.set_resizable(True)
 
396
        self.graph_column.set_sizing(Gtk.TreeViewColumnSizing.FIXED)
 
397
        self.graph_column.pack_start(self.graph_cell, True)
 
398
        self.graph_column.add_attribute(
 
399
            self.graph_cell, "node", treemodel.NODE)
 
400
        self.graph_column.add_attribute(
 
401
            self.graph_cell, "tags", treemodel.TAGS)
 
402
        self.graph_column.add_attribute(
 
403
            self.graph_cell, "in-lines", treemodel.LAST_LINES)
 
404
        self.graph_column.add_attribute(
 
405
            self.graph_cell, "out-lines", treemodel.LINES)
378
406
        self.treeview.append_column(self.graph_column)
379
407
 
380
 
        cell = gtk.CellRendererText()
 
408
        cell = Gtk.CellRendererText()
381
409
        cell.set_property("width-chars", 65)
382
 
        cell.set_property("ellipsize", pango.ELLIPSIZE_END)
383
 
        self.summary_column = gtk.TreeViewColumn("Summary")
384
 
        self.summary_column.set_resizable(False)
 
410
        cell.set_property("ellipsize", Pango.EllipsizeMode.END)
 
411
        self.summary_column = Gtk.TreeViewColumn("Summary")
 
412
        self.summary_column.set_resizable(True)
385
413
        self.summary_column.set_expand(True)
386
 
        self.summary_column.set_sizing(gtk.TREE_VIEW_COLUMN_FIXED)
387
 
        self.summary_column.set_fixed_width(cell.get_size(self.treeview)[2])
388
 
        self.summary_column.pack_start(cell, expand=True)
 
414
        self.summary_column.set_sizing(Gtk.TreeViewColumnSizing.FIXED)
 
415
        self.summary_column.set_fixed_width(
 
416
            cell.get_preferred_width(self.treeview)[1])
 
417
        self.summary_column.pack_start(cell, True)
389
418
        self.summary_column.add_attribute(cell, "markup", treemodel.SUMMARY)
390
419
        self.treeview.append_column(self.summary_column)
391
420
 
392
 
        cell = gtk.CellRendererText()
 
421
        cell = Gtk.CellRendererText()
393
422
        cell.set_property("width-chars", 15)
394
 
        cell.set_property("ellipsize", pango.ELLIPSIZE_END)
395
 
        self.authors_column = gtk.TreeViewColumn("Author(s)")
 
423
        cell.set_property("ellipsize", Pango.EllipsizeMode.END)
 
424
        self.authors_column = Gtk.TreeViewColumn("Author(s)")
396
425
        self.authors_column.set_resizable(False)
397
 
        self.authors_column.set_sizing(gtk.TREE_VIEW_COLUMN_FIXED)
 
426
        self.authors_column.set_sizing(Gtk.TreeViewColumnSizing.FIXED)
398
427
        self.authors_column.set_fixed_width(200)
399
 
        self.authors_column.pack_start(cell, expand=True)
 
428
        self.authors_column.pack_start(cell, True)
400
429
        self.authors_column.add_attribute(cell, "text", treemodel.AUTHORS)
401
430
        self.treeview.append_column(self.authors_column)
402
431
 
403
 
        cell = gtk.CellRendererText()
 
432
        cell = Gtk.CellRendererText()
404
433
        cell.set_property("width-chars", 20)
405
 
        cell.set_property("ellipsize", pango.ELLIPSIZE_END)
406
 
        self.date_column = gtk.TreeViewColumn("Date")
 
434
        cell.set_property("ellipsize", Pango.EllipsizeMode.END)
 
435
        self.date_column = Gtk.TreeViewColumn("Date")
407
436
        self.date_column.set_visible(False)
408
 
        self.date_column.set_resizable(False)
409
 
        self.date_column.set_sizing(gtk.TREE_VIEW_COLUMN_FIXED)
 
437
        self.date_column.set_resizable(True)
 
438
        self.date_column.set_sizing(Gtk.TreeViewColumnSizing.FIXED)
410
439
        self.date_column.set_fixed_width(130)
411
 
        self.date_column.pack_start(cell, expand=True)
 
440
        self.date_column.pack_start(cell, True)
412
441
        self.date_column.add_attribute(cell, "text", treemodel.TIMESTAMP)
413
442
        self.treeview.append_column(self.date_column)
414
 
        
 
443
 
415
444
        return self.treeview
416
 
    
 
445
 
417
446
    def _on_selection_changed(self, treeview):
418
447
        """callback for when the treeview changes."""
419
448
        (path, focus) = treeview.get_cursor()
429
458
                [self.get_revision().revision_id],
430
459
                self.branch)
431
460
            menu.connect('tag-added', lambda w, t, r: self.add_tag(t, r))
432
 
            menu.popup(None, None, None, event.button, event.get_time())
 
461
            menu.popup(None, None, None, None, event.button, event.get_time())
433
462
 
434
463
    def _on_revision_activated(self, widget, path, col):
435
464
        self.emit('revision-activated', path, col)