/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: Jelmer Vernooij
  • Date: 2010-05-25 17:09:02 UTC
  • mto: This revision was merged to the branch mainline in revision 691.
  • Revision ID: jelmer@samba.org-20100525170902-3to8g5iw7ovw79kh
Split out olive into a separate directory.

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
 
from gi.repository import Gtk
10
 
from gi.repository import GObject
11
 
from gi.repository import Pango
12
 
 
 
9
import sys
 
10
import string
 
11
import gtk
 
12
import gobject
 
13
import pango
 
14
import re
 
15
import treemodel
13
16
from bzrlib import ui
 
17
 
 
18
from bzrlib.plugins.gtk import _i18n
 
19
from bzrlib.plugins.gtk.ui import GtkProgressBar, ProgressPanel
 
20
from linegraph import linegraph, same_branch
 
21
from graphcell import CellRendererGraph
 
22
from treemodel import TreeModel
14
23
from bzrlib.revision import NULL_REVISION
15
24
 
16
 
from bzrlib.plugins.gtk import lock
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):
 
25
 
 
26
class TreeView(gtk.VBox):
24
27
 
25
28
    __gproperties__ = {
26
 
        'branch': (GObject.TYPE_PYOBJECT,
 
29
        'branch': (gobject.TYPE_PYOBJECT,
27
30
                   'Branch',
28
31
                   'The Bazaar branch being visualized',
29
 
                   GObject.PARAM_CONSTRUCT_ONLY | GObject.PARAM_WRITABLE),
 
32
                   gobject.PARAM_CONSTRUCT_ONLY | gobject.PARAM_WRITABLE),
30
33
 
31
 
        'revision': (GObject.TYPE_PYOBJECT,
 
34
        'revision': (gobject.TYPE_PYOBJECT,
32
35
                     'Revision',
33
36
                     'The currently selected revision',
34
 
                     GObject.PARAM_READWRITE),
 
37
                     gobject.PARAM_READWRITE),
35
38
 
36
 
        'revision-number': (GObject.TYPE_STRING,
 
39
        'revision-number': (gobject.TYPE_STRING,
37
40
                            'Revision number',
38
41
                            'The number of the selected revision',
39
42
                            '',
40
 
                            GObject.PARAM_READABLE),
 
43
                            gobject.PARAM_READABLE),
41
44
 
42
 
        'children': (GObject.TYPE_PYOBJECT,
 
45
        'children': (gobject.TYPE_PYOBJECT,
43
46
                     'Child revisions',
44
47
                     'Children of the currently selected revision',
45
 
                     GObject.PARAM_READABLE),
 
48
                     gobject.PARAM_READABLE),
46
49
 
47
 
        'parents': (GObject.TYPE_PYOBJECT,
 
50
        'parents': (gobject.TYPE_PYOBJECT,
48
51
                    'Parent revisions',
49
52
                    'Parents to the currently selected revision',
50
 
                    GObject.PARAM_READABLE),
 
53
                    gobject.PARAM_READABLE),
51
54
 
52
 
        'revno-column-visible': (GObject.TYPE_BOOLEAN,
 
55
        'revno-column-visible': (gobject.TYPE_BOOLEAN,
53
56
                                 'Revision number column',
54
57
                                 'Show revision number column',
55
58
                                 True,
56
 
                                 GObject.PARAM_READWRITE),
 
59
                                 gobject.PARAM_READWRITE),
57
60
 
58
 
        'graph-column-visible': (GObject.TYPE_BOOLEAN,
 
61
        'graph-column-visible': (gobject.TYPE_BOOLEAN,
59
62
                                 'Graph column',
60
63
                                 'Show graph column',
61
64
                                 True,
62
 
                                 GObject.PARAM_READWRITE),
 
65
                                 gobject.PARAM_READWRITE),
63
66
 
64
 
        'date-column-visible': (GObject.TYPE_BOOLEAN,
 
67
        'date-column-visible': (gobject.TYPE_BOOLEAN,
65
68
                                 'Date',
66
69
                                 'Show date column',
67
70
                                 False,
68
 
                                 GObject.PARAM_READWRITE),
 
71
                                 gobject.PARAM_READWRITE),
69
72
 
70
 
        'compact': (GObject.TYPE_BOOLEAN,
 
73
        'compact': (gobject.TYPE_BOOLEAN,
71
74
                    'Compact view',
72
75
                    'Break ancestry lines to save space',
73
76
                    True,
74
 
                    GObject.PARAM_CONSTRUCT | GObject.PARAM_READWRITE),
 
77
                    gobject.PARAM_CONSTRUCT | gobject.PARAM_READWRITE),
75
78
 
76
 
        'mainline-only': (GObject.TYPE_BOOLEAN,
 
79
        'mainline-only': (gobject.TYPE_BOOLEAN,
77
80
                    'Mainline only',
78
81
                    'Only show the mainline history.',
79
82
                    False,
80
 
                    GObject.PARAM_CONSTRUCT | GObject.PARAM_READWRITE),
 
83
                    gobject.PARAM_CONSTRUCT | gobject.PARAM_READWRITE),
81
84
 
82
85
    }
83
86
 
84
87
    __gsignals__ = {
85
 
        'revision-selected': (GObject.SignalFlags.RUN_FIRST,
86
 
                              None,
 
88
        'revision-selected': (gobject.SIGNAL_RUN_FIRST,
 
89
                              gobject.TYPE_NONE,
87
90
                              ()),
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,
 
91
        'revision-activated': (gobject.SIGNAL_RUN_FIRST,
 
92
                              gobject.TYPE_NONE,
 
93
                              (gobject.TYPE_PYOBJECT, gobject.TYPE_PYOBJECT)),
 
94
        'tag-added': (gobject.SIGNAL_RUN_FIRST,
 
95
                              gobject.TYPE_NONE,
 
96
                              (gobject.TYPE_STRING, gobject.TYPE_STRING)),
 
97
        'refreshed': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
95
98
                              ())
96
99
    }
97
100
 
105
108
        :param broken_line_length: After how much lines to break 
106
109
                                   branches.
107
110
        """
108
 
        GObject.GObject.__init__(self, spacing=0)
 
111
        gtk.VBox.__init__(self, spacing=0)
109
112
 
110
113
        self.progress_widget = ProgressPanel()
111
114
        self.pack_start(self.progress_widget, expand=False, fill=True)
113
116
            # We'are using our own ui, let's tell it to use our widget.
114
117
            ui.ui_factory.set_progress_bar_widget(self.progress_widget)
115
118
 
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)
 
119
        self.scrolled_window = gtk.ScrolledWindow()
 
120
        self.scrolled_window.set_policy(gtk.POLICY_AUTOMATIC,
 
121
                                        gtk.POLICY_AUTOMATIC)
 
122
        self.scrolled_window.set_shadow_type(gtk.SHADOW_IN)
120
123
        self.scrolled_window.show()
121
124
        self.pack_start(self.scrolled_window, expand=True, fill=True)
122
125
 
131
134
        self.maxnum = maxnum
132
135
        self.compact = compact
133
136
 
134
 
        self.model = treemodel.TreeModel(self.branch, [])
135
 
        GObject.idle_add(self.populate)
 
137
        gobject.idle_add(self.populate)
136
138
 
137
139
        self.connect("destroy", self._on_destroy)
138
140
 
156
158
        elif property.name == 'branch':
157
159
            return self.branch
158
160
        elif property.name == 'revision':
159
 
            if self.path is None:
160
 
                return None
161
161
            return self.model.get_value(self.model.get_iter(self.path),
162
162
                                        treemodel.REVISION)
163
163
        elif property.name == 'revision-number':
164
 
            if self.path is None:
165
 
                return None
166
164
            return self.model.get_value(self.model.get_iter(self.path),
167
165
                                        treemodel.REVNO)
168
166
        elif property.name == 'children':
169
 
            if self.path is None:
170
 
                return None
171
167
            return self.model.get_value(self.model.get_iter(self.path),
172
168
                                        treemodel.CHILDREN)
173
169
        elif property.name == 'parents':
174
 
            if self.path is None:
175
 
                return None
176
170
            return self.model.get_value(self.model.get_iter(self.path),
177
171
                                        treemodel.PARENTS)
178
172
        else:
231
225
    def add_tag(self, tag, revid=None):
232
226
        if revid is None: revid = self.revision.revision_id
233
227
 
234
 
        if lock.release(self.branch):
 
228
        try:
 
229
            self.branch.unlock()
 
230
 
235
231
            try:
236
 
                lock.acquire(self.branch, lock.WRITE)
 
232
                self.branch.lock_write()
237
233
                self.model.add_tag(tag, revid)
238
234
            finally:
239
 
                lock.release(self.branch)
240
 
 
241
 
            lock.acquire(self.branch, lock.READ)
242
 
 
243
 
            self.emit('tag-added', tag, revid)
244
 
 
 
235
                self.branch.unlock()
 
236
 
 
237
        finally:
 
238
            self.branch.lock_read()
 
239
 
 
240
        self.emit('tag-added', tag, revid)
 
241
        
245
242
    def refresh(self):
246
 
        GObject.idle_add(self.populate, self.get_revision())
 
243
        gobject.idle_add(self.populate, self.get_revision())
247
244
 
248
245
    def update(self):
249
246
        try:
307
304
                broken_line_length = 32
308
305
            else:
309
306
                broken_line_length = None
310
 
 
 
307
            
311
308
            show_graph = self.graph_column.get_visible()
312
309
 
313
310
            self.branch.lock_read()
319
316
                                                            self.mainline_only,
320
317
                                                            self.progress_bar)
321
318
 
322
 
            self.model.line_graph_data = linegraphdata
 
319
            self.model = TreeModel(self.branch, linegraphdata)
323
320
            self.graph_cell.columns_len = columns_len
324
321
            width = self.graph_cell.get_size(self.treeview)[2]
325
322
            if width > 500:
340
337
            self.progress_bar.finished()
341
338
 
342
339
    def construct_treeview(self):
343
 
        self.treeview = Gtk.TreeView()
 
340
        self.treeview = gtk.TreeView()
344
341
 
345
342
        self.treeview.set_rules_hint(True)
346
 
        # combined revno/summary interactive search
347
 
        #
348
 
        # the row in a treemodel is considered "matched" if a REVNO *starts*
349
 
        # from the key (that is the key is found in a REVNO at the offset 0)
350
 
        # or if a MESSAGE *contains* the key anywhere (that is, the key is
351
 
        # found case insensitively in a MESSAGE at any offset)
352
 
        def search_equal_func(model, column, key, iter):
353
 
            return (model.get_value(iter, treemodel.REVNO).find(key) != 0
354
 
                and model.get_value(iter, treemodel.MESSAGE).lower().find(key.lower()) == -1)
355
 
 
356
 
        self.treeview.set_search_equal_func(search_equal_func)
357
 
        self.treeview.set_enable_search(True)
358
 
 
359
 
        set_tooltip(treemodel.MESSAGE)
 
343
        self.treeview.set_search_column(treemodel.REVNO)
 
344
        
 
345
        # Fix old PyGTK bug - by JAM
 
346
        set_tooltip = getattr(self.treeview, 'set_tooltip_column', None)
 
347
        if set_tooltip is not None:
 
348
            set_tooltip(treemodel.MESSAGE)
360
349
 
361
350
        self._prev_cursor_path = None
362
351
        self.treeview.connect("cursor-changed",
372
361
 
373
362
        self.treeview.show()
374
363
 
375
 
        cell = Gtk.CellRendererText()
 
364
        cell = gtk.CellRendererText()
376
365
        cell.set_property("width-chars", 15)
377
 
        cell.set_property("ellipsize", Pango.EllipsizeMode.END)
378
 
        self.revno_column = Gtk.TreeViewColumn("Revision No")
379
 
        self.revno_column.set_resizable(True)
380
 
        self.revno_column.set_sizing(Gtk.TreeViewColumnSizing.FIXED)
 
366
        cell.set_property("ellipsize", pango.ELLIPSIZE_END)
 
367
        self.revno_column = gtk.TreeViewColumn("Revision No")
 
368
        self.revno_column.set_resizable(False)
 
369
        self.revno_column.set_sizing(gtk.TREE_VIEW_COLUMN_FIXED)
381
370
        self.revno_column.set_fixed_width(cell.get_size(self.treeview)[2])
382
 
        self.revno_column.pack_start(cell, True, True, 0)
 
371
        self.revno_column.pack_start(cell, expand=True)
383
372
        self.revno_column.add_attribute(cell, "text", treemodel.REVNO)
384
373
        self.treeview.append_column(self.revno_column)
385
374
 
386
375
        self.graph_cell = CellRendererGraph()
387
 
        self.graph_column = Gtk.TreeViewColumn()
388
 
        self.graph_column.set_resizable(True)
389
 
        self.graph_column.set_sizing(Gtk.TreeViewColumnSizing.FIXED)
390
 
        self.graph_column.pack_start(self.graph_cell, True, True, 0)
 
376
        self.graph_column = gtk.TreeViewColumn()
 
377
        self.graph_column.set_resizable(False)
 
378
        self.graph_column.set_sizing(gtk.TREE_VIEW_COLUMN_FIXED)
 
379
        self.graph_column.pack_start(self.graph_cell, expand=True)
391
380
        self.graph_column.add_attribute(self.graph_cell, "node", treemodel.NODE)
392
381
        self.graph_column.add_attribute(self.graph_cell, "tags", treemodel.TAGS)
393
382
        self.graph_column.add_attribute(self.graph_cell, "in-lines", treemodel.LAST_LINES)
394
383
        self.graph_column.add_attribute(self.graph_cell, "out-lines", treemodel.LINES)
395
384
        self.treeview.append_column(self.graph_column)
396
385
 
397
 
        cell = Gtk.CellRendererText()
 
386
        cell = gtk.CellRendererText()
398
387
        cell.set_property("width-chars", 65)
399
 
        cell.set_property("ellipsize", Pango.EllipsizeMode.END)
400
 
        self.summary_column = Gtk.TreeViewColumn("Summary")
401
 
        self.summary_column.set_resizable(True)
 
388
        cell.set_property("ellipsize", pango.ELLIPSIZE_END)
 
389
        self.summary_column = gtk.TreeViewColumn("Summary")
 
390
        self.summary_column.set_resizable(False)
402
391
        self.summary_column.set_expand(True)
403
 
        self.summary_column.set_sizing(Gtk.TreeViewColumnSizing.FIXED)
 
392
        self.summary_column.set_sizing(gtk.TREE_VIEW_COLUMN_FIXED)
404
393
        self.summary_column.set_fixed_width(cell.get_size(self.treeview)[2])
405
 
        self.summary_column.pack_start(cell, True, True, 0)
 
394
        self.summary_column.pack_start(cell, expand=True)
406
395
        self.summary_column.add_attribute(cell, "markup", treemodel.SUMMARY)
407
396
        self.treeview.append_column(self.summary_column)
408
397
 
409
 
        cell = Gtk.CellRendererText()
 
398
        cell = gtk.CellRendererText()
410
399
        cell.set_property("width-chars", 15)
411
 
        cell.set_property("ellipsize", Pango.EllipsizeMode.END)
412
 
        self.authors_column = Gtk.TreeViewColumn("Author(s)")
413
 
        self.authors_column.set_resizable(False)
414
 
        self.authors_column.set_sizing(Gtk.TreeViewColumnSizing.FIXED)
415
 
        self.authors_column.set_fixed_width(200)
416
 
        self.authors_column.pack_start(cell, True, True, 0)
417
 
        self.authors_column.add_attribute(cell, "text", treemodel.AUTHORS)
418
 
        self.treeview.append_column(self.authors_column)
 
400
        cell.set_property("ellipsize", pango.ELLIPSIZE_END)
 
401
        self.committer_column = gtk.TreeViewColumn("Committer")
 
402
        self.committer_column.set_resizable(False)
 
403
        self.committer_column.set_sizing(gtk.TREE_VIEW_COLUMN_FIXED)
 
404
        self.committer_column.set_fixed_width(200)
 
405
        self.committer_column.pack_start(cell, expand=True)
 
406
        self.committer_column.add_attribute(cell, "text", treemodel.COMMITTER)
 
407
        self.treeview.append_column(self.committer_column)
419
408
 
420
 
        cell = Gtk.CellRendererText()
 
409
        cell = gtk.CellRendererText()
421
410
        cell.set_property("width-chars", 20)
422
 
        cell.set_property("ellipsize", Pango.EllipsizeMode.END)
423
 
        self.date_column = Gtk.TreeViewColumn("Date")
 
411
        cell.set_property("ellipsize", pango.ELLIPSIZE_END)
 
412
        self.date_column = gtk.TreeViewColumn("Date")
424
413
        self.date_column.set_visible(False)
425
 
        self.date_column.set_resizable(True)
426
 
        self.date_column.set_sizing(Gtk.TreeViewColumnSizing.FIXED)
 
414
        self.date_column.set_resizable(False)
 
415
        self.date_column.set_sizing(gtk.TREE_VIEW_COLUMN_FIXED)
427
416
        self.date_column.set_fixed_width(130)
428
 
        self.date_column.pack_start(cell, True, True, 0)
 
417
        self.date_column.pack_start(cell, expand=True)
429
418
        self.date_column.add_attribute(cell, "text", treemodel.TIMESTAMP)
430
419
        self.treeview.append_column(self.date_column)
431
 
 
 
420
        
432
421
        return self.treeview
433
 
 
 
422
    
434
423
    def _on_selection_changed(self, treeview):
435
424
        """callback for when the treeview changes."""
436
425
        (path, focus) = treeview.get_cursor()