/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: Vincent Ladeuil
  • Date: 2008-05-05 18:16:46 UTC
  • mto: (487.1.1 gtk)
  • mto: This revision was merged to the branch mainline in revision 490.
  • Revision ID: v.ladeuil+lp@free.fr-20080505181646-n95l8ltw2u6jtr26
Fix bug #187283 fix replacing _() by _i18n().

* genpot.sh 
Remove duplication. Add the ability to specify the genrated pot
file on command-line for debugging purposes.

* po/olive-gtk.pot:
Regenerated.

* __init__.py, branch.py, branchview/treeview.py, checkout.py,
commit.py, conflicts.py, diff.py, errors.py, initialize.py,
merge.py, nautilus-bzr.py, olive/__init__.py, olive/add.py,
olive/bookmark.py, olive/guifiles.py, olive/info.py,
olive/menu.py, olive/mkdir.py, olive/move.py, olive/remove.py,
olive/rename.py, push.py, revbrowser.py, status.py, tags.py:
Replace all calls to _() by calls to _i18n(), the latter being
defined in __init__.py and imported in the other modules from
there. This fix the problem encountered countless times when
running bzr selftest and getting silly error messages about
boolean not being callables.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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
 
 
9
import sys
 
10
import string
 
11
import gtk
 
12
import gobject
 
13
import pango
 
14
import re
 
15
import treemodel
 
16
 
 
17
from bzrlib.plugins.gtk import _i18n
 
18
from linegraph import linegraph, same_branch
 
19
from graphcell import CellRendererGraph
 
20
from treemodel import TreeModel
 
21
from bzrlib.revision import NULL_REVISION
 
22
 
 
23
class TreeView(gtk.VBox):
 
24
 
 
25
    __gproperties__ = {
 
26
        'branch': (gobject.TYPE_PYOBJECT,
 
27
                   'Branch',
 
28
                   'The Bazaar branch being visualized',
 
29
                   gobject.PARAM_CONSTRUCT_ONLY | gobject.PARAM_WRITABLE),
 
30
 
 
31
        'revision': (gobject.TYPE_PYOBJECT,
 
32
                     'Revision',
 
33
                     'The currently selected revision',
 
34
                     gobject.PARAM_READWRITE),
 
35
 
 
36
        'revision-number': (gobject.TYPE_STRING,
 
37
                            'Revision number',
 
38
                            'The number of the selected revision',
 
39
                            '',
 
40
                            gobject.PARAM_READABLE),
 
41
 
 
42
        'children': (gobject.TYPE_PYOBJECT,
 
43
                     'Child revisions',
 
44
                     'Children of the currently selected revision',
 
45
                     gobject.PARAM_READABLE),
 
46
 
 
47
        'parents': (gobject.TYPE_PYOBJECT,
 
48
                    'Parent revisions',
 
49
                    'Parents to the currently selected revision',
 
50
                    gobject.PARAM_READABLE),
 
51
 
 
52
        'revno-column-visible': (gobject.TYPE_BOOLEAN,
 
53
                                 'Revision number column',
 
54
                                 'Show revision number column',
 
55
                                 True,
 
56
                                 gobject.PARAM_READWRITE),
 
57
 
 
58
        'graph-column-visible': (gobject.TYPE_BOOLEAN,
 
59
                                 'Graph column',
 
60
                                 'Show graph column',
 
61
                                 True,
 
62
                                 gobject.PARAM_READWRITE),
 
63
 
 
64
        'date-column-visible': (gobject.TYPE_BOOLEAN,
 
65
                                 'Date',
 
66
                                 'Show date column',
 
67
                                 False,
 
68
                                 gobject.PARAM_READWRITE),
 
69
 
 
70
        'compact': (gobject.TYPE_BOOLEAN,
 
71
                    'Compact view',
 
72
                    'Break ancestry lines to save space',
 
73
                    True,
 
74
                    gobject.PARAM_CONSTRUCT | gobject.PARAM_READWRITE),
 
75
 
 
76
        'mainline-only': (gobject.TYPE_BOOLEAN,
 
77
                    'Mainline only',
 
78
                    'Only show the mainline history.',
 
79
                    False,
 
80
                    gobject.PARAM_CONSTRUCT | gobject.PARAM_READWRITE),
 
81
 
 
82
    }
 
83
 
 
84
    __gsignals__ = {
 
85
        'revisions-loaded': (gobject.SIGNAL_RUN_FIRST, 
 
86
                             gobject.TYPE_NONE,
 
87
                             ()),
 
88
        'revision-selected': (gobject.SIGNAL_RUN_FIRST,
 
89
                              gobject.TYPE_NONE,
 
90
                              ()),
 
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
    }
 
98
 
 
99
    def __init__(self, branch, start, maxnum, compact=True):
 
100
        """Create a new TreeView.
 
101
 
 
102
        :param branch: Branch object for branch to show.
 
103
        :param start: Revision id of top revision.
 
104
        :param maxnum: Maximum number of revisions to display, 
 
105
                       None for no limit.
 
106
        :param broken_line_length: After how much lines to break 
 
107
                                   branches.
 
108
        """
 
109
        gtk.VBox.__init__(self, spacing=0)
 
110
 
 
111
        self.pack_start(self.construct_loading_msg(), expand=False, fill=True)
 
112
        self.connect('revisions-loaded', 
 
113
                lambda x: self.loading_msg_box.hide())
 
114
 
 
115
        self.scrolled_window = gtk.ScrolledWindow()
 
116
        self.scrolled_window.set_policy(gtk.POLICY_AUTOMATIC,
 
117
                                        gtk.POLICY_AUTOMATIC)
 
118
        self.scrolled_window.set_shadow_type(gtk.SHADOW_IN)
 
119
        self.scrolled_window.show()
 
120
        self.pack_start(self.scrolled_window, expand=True, fill=True)
 
121
 
 
122
        self.scrolled_window.add(self.construct_treeview())
 
123
        
 
124
 
 
125
        self.iter = None
 
126
        self.branch = branch
 
127
        self.revision = None
 
128
 
 
129
        self.start = start
 
130
        self.maxnum = maxnum
 
131
        self.compact = compact
 
132
 
 
133
        gobject.idle_add(self.populate)
 
134
 
 
135
        self.connect("destroy", lambda x: self.branch.unlock())
 
136
 
 
137
    def do_get_property(self, property):
 
138
        if property.name == 'revno-column-visible':
 
139
            return self.revno_column.get_visible()
 
140
        elif property.name == 'graph-column-visible':
 
141
            return self.graph_column.get_visible()
 
142
        elif property.name == 'date-column-visible':
 
143
            return self.date_column.get_visible()
 
144
        elif property.name == 'compact':
 
145
            return self.compact
 
146
        elif property.name == 'mainline-only':
 
147
            return self.mainline_only
 
148
        elif property.name == 'branch':
 
149
            return self.branch
 
150
        elif property.name == 'revision':
 
151
            return self.model.get_value(self.iter, treemodel.REVISION)
 
152
        elif property.name == 'revision-number':
 
153
            return self.model.get_value(self.iter, treemodel.REVNO)
 
154
        elif property.name == 'children':
 
155
            return self.model.get_value(self.iter, treemodel.CHILDREN)
 
156
        elif property.name == 'parents':
 
157
            return self.model.get_value(self.iter, treemodel.PARENTS)
 
158
        else:
 
159
            raise AttributeError, 'unknown property %s' % property.name
 
160
 
 
161
    def do_set_property(self, property, value):
 
162
        if property.name == 'revno-column-visible':
 
163
            self.revno_column.set_visible(value)
 
164
        elif property.name == 'graph-column-visible':
 
165
            self.graph_column.set_visible(value)
 
166
        elif property.name == 'date-column-visible':
 
167
            self.date_column.set_visible(value)
 
168
        elif property.name == 'compact':
 
169
            self.compact = value
 
170
        elif property.name == 'mainline-only':
 
171
            self.mainline_only = value
 
172
        elif property.name == 'branch':
 
173
            self.branch = value
 
174
        elif property.name == 'revision':
 
175
            self.set_revision_id(value.revision_id)
 
176
        else:
 
177
            raise AttributeError, 'unknown property %s' % property.name
 
178
 
 
179
    def get_revision(self):
 
180
        """Return revision id of currently selected revision, or None."""
 
181
        return self.get_property('revision')
 
182
 
 
183
    def set_revision(self, revision):
 
184
        self.set_property('revision', revision)
 
185
 
 
186
    def set_revision_id(self, revid):
 
187
        """Change the currently selected revision.
 
188
 
 
189
        :param revid: Revision id of revision to display.
 
190
        """
 
191
        self.treeview.set_cursor(self.index[revid])
 
192
        self.treeview.grab_focus()
 
193
 
 
194
    def get_children(self):
 
195
        """Return the children of the currently selected revision.
 
196
 
 
197
        :return: list of revision ids.
 
198
        """
 
199
        return self.get_property('children')
 
200
 
 
201
    def get_parents(self):
 
202
        """Return the parents of the currently selected revision.
 
203
 
 
204
        :return: list of revision ids.
 
205
        """
 
206
        return self.get_property('parents')
 
207
 
 
208
    def add_tag(self, tag, revid=None):
 
209
        if revid is None: revid = self.revision.revision_id
 
210
 
 
211
        try:
 
212
            self.branch.unlock()
 
213
 
 
214
            try:
 
215
                self.branch.lock_write()
 
216
                self.model.add_tag(tag, revid)
 
217
            finally:
 
218
                self.branch.unlock()
 
219
 
 
220
        finally:
 
221
            self.branch.lock_read()
 
222
 
 
223
        self.emit('tag-added', tag, revid)
 
224
        
 
225
    def refresh(self):
 
226
        self.loading_msg_box.show()
 
227
        gobject.idle_add(self.populate, self.get_revision())
 
228
 
 
229
    def update(self):
 
230
        try:
 
231
            self.branch.unlock()
 
232
            try:
 
233
                self.branch.lock_write()
 
234
                self.branch.update()
 
235
            finally:
 
236
                self.branch.unlock()
 
237
        finally:
 
238
            self.branch.lock_read()
 
239
 
 
240
    def back(self):
 
241
        """Signal handler for the Back button."""
 
242
        parents = self.get_parents()
 
243
        if not len(parents):
 
244
            return
 
245
 
 
246
        for parent_id in parents:
 
247
            parent_index = self.index[parent_id]
 
248
            parent = self.model[parent_index][treemodel.REVISION]
 
249
            if same_branch(self.get_revision(), parent):
 
250
                self.set_revision(parent)
 
251
                break
 
252
        else:
 
253
            self.set_revision_id(parents[0])
 
254
 
 
255
    def forward(self):
 
256
        """Signal handler for the Forward button."""
 
257
        children = self.get_children()
 
258
        if not len(children):
 
259
            return
 
260
 
 
261
        for child_id in children:
 
262
            child_index = self.index[child_id]
 
263
            child = self.model[child_index][treemodel.REVISION]
 
264
            if same_branch(child, self.get_revision()):
 
265
                self.set_revision(child)
 
266
                break
 
267
        else:
 
268
            self.set_revision_id(children[0])
 
269
 
 
270
    def populate(self, revision=None):
 
271
        """Fill the treeview with contents.
 
272
 
 
273
        :param start: Revision id of revision to start with.
 
274
        :param maxnum: Maximum number of revisions to display, or None 
 
275
                       for no limit.
 
276
        :param broken_line_length: After how much lines branches \
 
277
                       should be broken.
 
278
        """
 
279
 
 
280
        if self.compact:
 
281
            broken_line_length = 32
 
282
        else:
 
283
            broken_line_length = None
 
284
        
 
285
        show_graph = self.graph_column.get_visible()
 
286
 
 
287
        self.branch.lock_read()
 
288
        (linegraphdata, index, columns_len) = linegraph(self.branch.repository,
 
289
                                                        self.start,
 
290
                                                        self.maxnum, 
 
291
                                                        broken_line_length,
 
292
                                                        show_graph,
 
293
                                                        self.mainline_only)
 
294
 
 
295
        self.model = TreeModel(self.branch, linegraphdata)
 
296
        self.graph_cell.columns_len = columns_len
 
297
        width = self.graph_cell.get_size(self.treeview)[2]
 
298
        if width > 500:
 
299
            width = 500
 
300
        self.graph_column.set_fixed_width(width)
 
301
        self.graph_column.set_max_width(width)
 
302
        self.index = index
 
303
        self.treeview.set_model(self.model)
 
304
 
 
305
        if not revision or revision == NULL_REVISION:
 
306
            self.treeview.set_cursor(0)
 
307
        else:
 
308
            self.set_revision(revision)
 
309
 
 
310
        self.emit('revisions-loaded')
 
311
 
 
312
        return False
 
313
 
 
314
    def construct_treeview(self):
 
315
        self.treeview = gtk.TreeView()
 
316
 
 
317
        self.treeview.set_rules_hint(True)
 
318
        self.treeview.set_search_column(treemodel.REVNO)
 
319
        
 
320
        # Fix old PyGTK bug - by JAM
 
321
        set_tooltip = getattr(self.treeview, 'set_tooltip_column', None)
 
322
        if set_tooltip is not None:
 
323
            set_tooltip(treemodel.MESSAGE)
 
324
 
 
325
        self.treeview.connect("cursor-changed",
 
326
                self._on_selection_changed)
 
327
 
 
328
        self.treeview.connect("row-activated", 
 
329
                self._on_revision_activated)
 
330
 
 
331
        self.treeview.connect("button-release-event", 
 
332
                self._on_revision_selected)
 
333
 
 
334
        self.treeview.set_property('fixed-height-mode', True)
 
335
 
 
336
        self.treeview.show()
 
337
 
 
338
        cell = gtk.CellRendererText()
 
339
        cell.set_property("width-chars", 15)
 
340
        cell.set_property("ellipsize", pango.ELLIPSIZE_END)
 
341
        self.revno_column = gtk.TreeViewColumn("Revision No")
 
342
        self.revno_column.set_resizable(True)
 
343
        self.revno_column.set_sizing(gtk.TREE_VIEW_COLUMN_FIXED)
 
344
        self.revno_column.set_fixed_width(cell.get_size(self.treeview)[2])
 
345
        self.revno_column.pack_start(cell, expand=True)
 
346
        self.revno_column.add_attribute(cell, "text", treemodel.REVNO)
 
347
        self.treeview.append_column(self.revno_column)
 
348
 
 
349
        self.graph_cell = CellRendererGraph()
 
350
        self.graph_column = gtk.TreeViewColumn()
 
351
        self.graph_column.set_resizable(True)
 
352
        self.graph_column.set_sizing(gtk.TREE_VIEW_COLUMN_FIXED)
 
353
        self.graph_column.pack_start(self.graph_cell, expand=False)
 
354
        self.graph_column.add_attribute(self.graph_cell, "node", treemodel.NODE)
 
355
        self.graph_column.add_attribute(self.graph_cell, "tags", treemodel.TAGS)
 
356
        self.graph_column.add_attribute(self.graph_cell, "in-lines", treemodel.LAST_LINES)
 
357
        self.graph_column.add_attribute(self.graph_cell, "out-lines", treemodel.LINES)
 
358
        self.treeview.append_column(self.graph_column)
 
359
 
 
360
        cell = gtk.CellRendererText()
 
361
        cell.set_property("width-chars", 65)
 
362
        cell.set_property("ellipsize", pango.ELLIPSIZE_END)
 
363
        self.summary_column = gtk.TreeViewColumn("Summary")
 
364
        self.summary_column.set_resizable(True)
 
365
        self.summary_column.set_sizing(gtk.TREE_VIEW_COLUMN_FIXED)
 
366
        self.summary_column.set_fixed_width(cell.get_size(self.treeview)[2])
 
367
        self.summary_column.pack_start(cell, expand=True)
 
368
        self.summary_column.add_attribute(cell, "markup", treemodel.SUMMARY)
 
369
        self.treeview.append_column(self.summary_column)
 
370
 
 
371
        cell = gtk.CellRendererText()
 
372
        cell.set_property("width-chars", 15)
 
373
        cell.set_property("ellipsize", pango.ELLIPSIZE_END)
 
374
        self.committer_column = gtk.TreeViewColumn("Committer")
 
375
        self.committer_column.set_resizable(True)
 
376
        self.committer_column.set_sizing(gtk.TREE_VIEW_COLUMN_FIXED)
 
377
        self.committer_column.set_fixed_width(cell.get_size(self.treeview)[2])
 
378
        self.committer_column.pack_start(cell, expand=True)
 
379
        self.committer_column.add_attribute(cell, "text", treemodel.COMMITTER)
 
380
        self.treeview.append_column(self.committer_column)
 
381
 
 
382
        cell = gtk.CellRendererText()
 
383
        cell.set_property("width-chars", 20)
 
384
        cell.set_property("ellipsize", pango.ELLIPSIZE_END)
 
385
        self.date_column = gtk.TreeViewColumn("Date")
 
386
        self.date_column.set_visible(False)
 
387
        self.date_column.set_resizable(True)
 
388
        self.date_column.set_sizing(gtk.TREE_VIEW_COLUMN_FIXED)
 
389
        self.date_column.set_fixed_width(cell.get_size(self.treeview)[2])
 
390
        self.date_column.pack_start(cell, expand=True)
 
391
        self.date_column.add_attribute(cell, "text", treemodel.TIMESTAMP)
 
392
        self.treeview.append_column(self.date_column)
 
393
        
 
394
        return self.treeview
 
395
    
 
396
    def construct_loading_msg(self):
 
397
        image_loading = gtk.image_new_from_stock(gtk.STOCK_REFRESH,
 
398
                                                 gtk.ICON_SIZE_BUTTON)
 
399
        image_loading.show()
 
400
        
 
401
        label_loading = gtk.Label(
 
402
            _i18n("Please wait, loading ancestral graph..."))
 
403
        label_loading.set_alignment(0.0, 0.5)
 
404
        label_loading.show()
 
405
        
 
406
        self.loading_msg_box = gtk.HBox()
 
407
        self.loading_msg_box.set_spacing(5)
 
408
        self.loading_msg_box.set_border_width(5)        
 
409
        self.loading_msg_box.pack_start(image_loading, False, False)
 
410
        self.loading_msg_box.pack_start(label_loading, True, True)
 
411
        self.loading_msg_box.show()
 
412
        
 
413
        return self.loading_msg_box
 
414
 
 
415
    def _on_selection_changed(self, treeview):
 
416
        """callback for when the treeview changes."""
 
417
        (path, focus) = treeview.get_cursor()
 
418
        if path is not None:
 
419
            self.iter = self.model.get_iter(path)
 
420
            self.emit('revision-selected')
 
421
 
 
422
    def _on_revision_selected(self, widget, event):
 
423
        from bzrlib.plugins.gtk.revisionmenu import RevisionPopupMenu
 
424
        if event.button == 3:
 
425
            menu = RevisionPopupMenu(self.branch.repository, 
 
426
                [self.get_revision().revision_id],
 
427
                self.branch)
 
428
            menu.connect('tag-added', lambda w, t, r: self.add_tag(t, r))
 
429
            menu.popup(None, None, None, event.button, event.get_time())
 
430
 
 
431
    def _on_revision_activated(self, widget, path, col):
 
432
        self.emit('revision-activated', path, col)