6
6
__copyright__ = "Copyright © 2005 Canonical Ltd."
7
7
__author__ = "Daniel Schierbeck <daniel.schierbeck@gmail.com>"
9
from gi.repository import Gtk
10
from gi.repository import GObject
11
from gi.repository import Pango
13
13
from bzrlib import ui
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
20
16
from bzrlib.plugins.gtk import lock
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
23
class TreeView(Gtk.VBox):
25
25
__gproperties__ = {
26
'branch': (gobject.TYPE_PYOBJECT,
26
'branch': (GObject.TYPE_PYOBJECT,
28
28
'The Bazaar branch being visualized',
29
gobject.PARAM_CONSTRUCT_ONLY | gobject.PARAM_WRITABLE),
29
GObject.PARAM_CONSTRUCT_ONLY | GObject.PARAM_WRITABLE),
31
'revision': (gobject.TYPE_PYOBJECT,
31
'revision': (GObject.TYPE_PYOBJECT,
33
33
'The currently selected revision',
34
gobject.PARAM_READWRITE),
34
GObject.PARAM_READWRITE),
36
'revision-number': (gobject.TYPE_STRING,
36
'revision-number': (GObject.TYPE_STRING,
38
38
'The number of the selected revision',
40
gobject.PARAM_READABLE),
40
GObject.PARAM_READABLE),
42
'children': (gobject.TYPE_PYOBJECT,
42
'children': (GObject.TYPE_PYOBJECT,
44
44
'Children of the currently selected revision',
45
gobject.PARAM_READABLE),
45
GObject.PARAM_READABLE),
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),
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',
56
gobject.PARAM_READWRITE),
56
GObject.PARAM_READWRITE),
58
'graph-column-visible': (gobject.TYPE_BOOLEAN,
58
'graph-column-visible': (GObject.TYPE_BOOLEAN,
60
60
'Show graph column',
62
gobject.PARAM_READWRITE),
62
GObject.PARAM_READWRITE),
64
'date-column-visible': (gobject.TYPE_BOOLEAN,
64
'date-column-visible': (GObject.TYPE_BOOLEAN,
66
66
'Show date column',
68
gobject.PARAM_READWRITE),
68
GObject.PARAM_READWRITE),
70
'compact': (gobject.TYPE_BOOLEAN,
70
'compact': (GObject.TYPE_BOOLEAN,
72
72
'Break ancestry lines to save space',
74
gobject.PARAM_CONSTRUCT | gobject.PARAM_READWRITE),
74
GObject.PARAM_CONSTRUCT | GObject.PARAM_READWRITE),
76
'mainline-only': (gobject.TYPE_BOOLEAN,
76
'mainline-only': (GObject.TYPE_BOOLEAN,
78
78
'Only show the mainline history.',
80
gobject.PARAM_CONSTRUCT | gobject.PARAM_READWRITE),
80
GObject.PARAM_CONSTRUCT | GObject.PARAM_READWRITE),
85
'revision-selected': (gobject.SIGNAL_RUN_FIRST,
85
'revision-selected': (GObject.SignalFlags.RUN_FIRST,
88
'revision-activated': (gobject.SIGNAL_RUN_FIRST,
90
(gobject.TYPE_PYOBJECT, gobject.TYPE_PYOBJECT)),
91
'tag-added': (gobject.SIGNAL_RUN_FIRST,
93
(gobject.TYPE_STRING, gobject.TYPE_STRING)),
94
'refreshed': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
88
'revision-activated': (GObject.SignalFlags.RUN_FIRST,
90
(GObject.TYPE_PYOBJECT, GObject.TYPE_PYOBJECT)),
91
'tag-added': (GObject.SignalFlags.RUN_FIRST,
93
(GObject.TYPE_STRING, GObject.TYPE_STRING)),
94
'refreshed': (GObject.SignalFlags.RUN_FIRST, None,
105
105
:param broken_line_length: After how much lines to break
108
gtk.VBox.__init__(self, spacing=0)
108
Gtk.VBox.__init__(self, homogeneous=False, spacing=0)
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)
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)
123
123
self.scrolled_window.add(self.construct_treeview())
331
341
self.progress_bar.finished()
333
343
def construct_treeview(self):
334
self.treeview = gtk.TreeView()
344
self.treeview = Gtk.TreeView()
336
346
self.treeview.set_rules_hint(True)
337
self.treeview.set_search_column(treemodel.REVNO)
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)
347
# combined revno/summary interactive search
349
# the row in a treemodel is considered "matched" if a REVNO *starts*
350
# from the key (that is the key is found in a REVNO at the offset 0)
351
# or if a MESSAGE *contains* the key anywhere (that is, the key is
352
# found case insensitively in a MESSAGE at any offset)
353
def search_equal_func(model, column, key, iter):
354
return (model.get_value(iter, treemodel.REVNO).find(key) != 0
355
and model.get_value(iter, treemodel.MESSAGE).lower().find(key.lower()) == -1)
357
self.treeview.set_search_equal_func(search_equal_func, None)
358
self.treeview.set_enable_search(True)
360
self.treeview.set_tooltip_column(treemodel.MESSAGE)
344
362
self._prev_cursor_path = None
345
363
self.treeview.connect("cursor-changed",
356
374
self.treeview.show()
358
cell = gtk.CellRendererText()
376
cell = Gtk.CellRendererText()
359
377
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)
378
cell.set_property("ellipsize", Pango.EllipsizeMode.END)
379
self.revno_column = Gtk.TreeViewColumn("Revision No")
380
self.revno_column.set_resizable(True)
381
self.revno_column.set_sizing(Gtk.TreeViewColumnSizing.FIXED)
382
self.revno_column.set_fixed_width(
383
cell.get_preferred_width(self.treeview)[1])
384
self.revno_column.pack_start(cell, True)
366
385
self.revno_column.add_attribute(cell, "text", treemodel.REVNO)
367
386
self.treeview.append_column(self.revno_column)
369
388
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)
389
self.graph_column = Gtk.TreeViewColumn()
390
self.graph_column.set_resizable(True)
391
self.graph_column.set_sizing(Gtk.TreeViewColumnSizing.FIXED)
392
self.graph_column.pack_start(self.graph_cell, True)
374
393
self.graph_column.add_attribute(self.graph_cell, "node", treemodel.NODE)
375
394
self.graph_column.add_attribute(self.graph_cell, "tags", treemodel.TAGS)
376
395
self.graph_column.add_attribute(self.graph_cell, "in-lines", treemodel.LAST_LINES)
377
396
self.graph_column.add_attribute(self.graph_cell, "out-lines", treemodel.LINES)
378
397
self.treeview.append_column(self.graph_column)
380
cell = gtk.CellRendererText()
399
cell = Gtk.CellRendererText()
381
400
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)
401
cell.set_property("ellipsize", Pango.EllipsizeMode.END)
402
self.summary_column = Gtk.TreeViewColumn("Summary")
403
self.summary_column.set_resizable(True)
385
404
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)
405
self.summary_column.set_sizing(Gtk.TreeViewColumnSizing.FIXED)
406
self.summary_column.set_fixed_width(
407
cell.get_preferred_width(self.treeview)[1])
408
self.summary_column.pack_start(cell, True)
389
409
self.summary_column.add_attribute(cell, "markup", treemodel.SUMMARY)
390
410
self.treeview.append_column(self.summary_column)
392
cell = gtk.CellRendererText()
412
cell = Gtk.CellRendererText()
393
413
cell.set_property("width-chars", 15)
394
cell.set_property("ellipsize", pango.ELLIPSIZE_END)
395
self.authors_column = gtk.TreeViewColumn("Author(s)")
414
cell.set_property("ellipsize", Pango.EllipsizeMode.END)
415
self.authors_column = Gtk.TreeViewColumn("Author(s)")
396
416
self.authors_column.set_resizable(False)
397
self.authors_column.set_sizing(gtk.TREE_VIEW_COLUMN_FIXED)
417
self.authors_column.set_sizing(Gtk.TreeViewColumnSizing.FIXED)
398
418
self.authors_column.set_fixed_width(200)
399
self.authors_column.pack_start(cell, expand=True)
419
self.authors_column.pack_start(cell, True)
400
420
self.authors_column.add_attribute(cell, "text", treemodel.AUTHORS)
401
421
self.treeview.append_column(self.authors_column)
403
cell = gtk.CellRendererText()
423
cell = Gtk.CellRendererText()
404
424
cell.set_property("width-chars", 20)
405
cell.set_property("ellipsize", pango.ELLIPSIZE_END)
406
self.date_column = gtk.TreeViewColumn("Date")
425
cell.set_property("ellipsize", Pango.EllipsizeMode.END)
426
self.date_column = Gtk.TreeViewColumn("Date")
407
427
self.date_column.set_visible(False)
408
self.date_column.set_resizable(False)
409
self.date_column.set_sizing(gtk.TREE_VIEW_COLUMN_FIXED)
428
self.date_column.set_resizable(True)
429
self.date_column.set_sizing(Gtk.TreeViewColumnSizing.FIXED)
410
430
self.date_column.set_fixed_width(130)
411
self.date_column.pack_start(cell, expand=True)
431
self.date_column.pack_start(cell, True)
412
432
self.date_column.add_attribute(cell, "text", treemodel.TIMESTAMP)
413
433
self.treeview.append_column(self.date_column)
415
435
return self.treeview
417
437
def _on_selection_changed(self, treeview):
418
438
"""callback for when the treeview changes."""
419
439
(path, focus) = treeview.get_cursor()