/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:
14
14
import re
15
15
import treemodel
16
16
 
 
17
from bzrlib.plugins.gtk import _i18n
17
18
from linegraph import linegraph, same_branch
18
19
from graphcell import CellRendererGraph
19
20
from treemodel import TreeModel
20
 
 
21
 
class TreeView(gtk.ScrolledWindow):
 
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
    }
22
83
 
23
84
    __gsignals__ = {
24
 
            'revisions-loaded': (gobject.SIGNAL_RUN_FIRST, 
25
 
                                 gobject.TYPE_NONE,
26
 
                                 ()),
27
 
            'revision-selected': (gobject.SIGNAL_RUN_FIRST,
28
 
                                  gobject.TYPE_NONE,
29
 
                                  ())
 
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))
30
97
    }
31
98
 
32
 
    def __init__(self, branch, start, maxnum):
33
 
        gtk.ScrolledWindow.__init__(self)
34
 
 
35
 
        self.set_policy(gtk.POLICY_NEVER, gtk.POLICY_AUTOMATIC)
36
 
        self.set_shadow_type(gtk.SHADOW_IN)
37
 
 
38
 
        self.construct_treeview()
39
 
 
 
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
40
126
        self.branch = branch
41
 
        self.branch.lock_read()
42
 
 
43
 
        gobject.idle_add(self.populate, start, maxnum)
44
 
 
45
127
        self.revision = None
46
 
        self.children = None
47
 
        self.parents  = None
48
 
 
49
 
        self.connect('destroy', lambda w: self.branch.unlock())
 
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
50
178
 
51
179
    def get_revision(self):
52
 
        return self.revision
53
 
 
54
 
    def set_revision(self, revid):
 
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
        """
55
191
        self.treeview.set_cursor(self.index[revid])
56
192
        self.treeview.grab_focus()
57
193
 
58
194
    def get_children(self):
59
 
        return self.children
 
195
        """Return the children of the currently selected revision.
 
196
 
 
197
        :return: list of revision ids.
 
198
        """
 
199
        return self.get_property('children')
60
200
 
61
201
    def get_parents(self):
62
 
        return self.parents
 
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)
63
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
 
64
240
    def back(self):
65
 
        (path, col) = self.treeview.get_cursor()
66
 
        revision = self.model[path][treemodel.REVISION]
67
 
        parents = self.model[path][treemodel.PARENTS]
 
241
        """Signal handler for the Back button."""
 
242
        parents = self.get_parents()
68
243
        if not len(parents):
69
244
            return
70
245
 
71
246
        for parent_id in parents:
72
247
            parent_index = self.index[parent_id]
73
248
            parent = self.model[parent_index][treemodel.REVISION]
74
 
            if same_branch(revision, parent):
75
 
                self.treeview.set_cursor(parent_index)
 
249
            if same_branch(self.get_revision(), parent):
 
250
                self.set_revision(parent)
76
251
                break
77
252
        else:
78
 
            self.treeview.set_cursor(self.index[parents[0]])
79
 
        self.treeview.grab_focus()
 
253
            self.set_revision_id(parents[0])
80
254
 
81
255
    def forward(self):
82
 
        (path, col) = self.treeview.get_cursor()
83
 
        revision = self.model[path][treemodel.REVISION]
84
 
        children = self.model[path][treemodel.CHILDREN]
 
256
        """Signal handler for the Forward button."""
 
257
        children = self.get_children()
85
258
        if not len(children):
86
259
            return
87
260
 
88
261
        for child_id in children:
89
262
            child_index = self.index[child_id]
90
263
            child = self.model[child_index][treemodel.REVISION]
91
 
            if same_branch(child, revision):
92
 
                self.treeview.set_cursor(child_index)
 
264
            if same_branch(child, self.get_revision()):
 
265
                self.set_revision(child)
93
266
                break
94
267
        else:
95
 
            self.treeview.set_cursor(self.index[children[0]])
96
 
        self.treeview.grab_focus()
97
 
 
98
 
    def populate(self, start, maxnum):
99
 
        (linegraphdata, index, columns_len) = linegraph(self.branch,
100
 
                                                        start,
101
 
                                                        maxnum)
 
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)
102
294
 
103
295
        self.model = TreeModel(self.branch, linegraphdata)
104
296
        self.graph_cell.columns_len = columns_len
105
297
        width = self.graph_cell.get_size(self.treeview)[2]
 
298
        if width > 500:
 
299
            width = 500
106
300
        self.graph_column.set_fixed_width(width)
107
301
        self.graph_column.set_max_width(width)
108
302
        self.index = index
109
303
        self.treeview.set_model(self.model)
110
 
        self.treeview.set_cursor(0)
 
304
 
 
305
        if not revision or revision == NULL_REVISION:
 
306
            self.treeview.set_cursor(0)
 
307
        else:
 
308
            self.set_revision(revision)
 
309
 
111
310
        self.emit('revisions-loaded')
112
311
 
113
312
        return False
114
313
 
115
 
    def show_diff(self, branch, revid, parentid):
116
 
        """Open a new window to show a diff between the given revisions."""
117
 
        from bzrlib.plugins.gtk.diff import DiffWindow
118
 
        window = DiffWindow(parent=self)
119
 
        (parent_tree, rev_tree) = branch.repository.revision_trees([parentid, 
120
 
                                                                   revid])
121
 
        description = revid + " - " + branch.nick
122
 
        window.set_diff(description, rev_tree, parent_tree)
123
 
        window.show()
124
 
 
125
314
    def construct_treeview(self):
126
315
        self.treeview = gtk.TreeView()
127
316
 
128
317
        self.treeview.set_rules_hint(True)
129
 
        self.treeview.set_search_column(4)
 
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)
130
324
 
131
 
        self.treeview.get_selection().connect("changed",
 
325
        self.treeview.connect("cursor-changed",
132
326
                self._on_selection_changed)
133
327
 
134
328
        self.treeview.connect("row-activated", 
139
333
 
140
334
        self.treeview.set_property('fixed-height-mode', True)
141
335
 
142
 
        self.add(self.treeview)
143
336
        self.treeview.show()
144
337
 
145
338
        cell = gtk.CellRendererText()
146
339
        cell.set_property("width-chars", 15)
147
340
        cell.set_property("ellipsize", pango.ELLIPSIZE_END)
148
 
        column = gtk.TreeViewColumn("Revision No")
149
 
        column.set_resizable(True)
150
 
        column.set_sizing(gtk.TREE_VIEW_COLUMN_FIXED)
151
 
        column.set_fixed_width(cell.get_size(self.treeview)[2])
152
 
        column.pack_start(cell, expand=True)
153
 
        column.add_attribute(cell, "text", treemodel.REVNO)
154
 
        self.treeview.append_column(column)
 
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)
155
348
 
156
349
        self.graph_cell = CellRendererGraph()
157
350
        self.graph_column = gtk.TreeViewColumn()
159
352
        self.graph_column.set_sizing(gtk.TREE_VIEW_COLUMN_FIXED)
160
353
        self.graph_column.pack_start(self.graph_cell, expand=False)
161
354
        self.graph_column.add_attribute(self.graph_cell, "node", treemodel.NODE)
 
355
        self.graph_column.add_attribute(self.graph_cell, "tags", treemodel.TAGS)
162
356
        self.graph_column.add_attribute(self.graph_cell, "in-lines", treemodel.LAST_LINES)
163
357
        self.graph_column.add_attribute(self.graph_cell, "out-lines", treemodel.LINES)
164
358
        self.treeview.append_column(self.graph_column)
166
360
        cell = gtk.CellRendererText()
167
361
        cell.set_property("width-chars", 65)
168
362
        cell.set_property("ellipsize", pango.ELLIPSIZE_END)
169
 
        column = gtk.TreeViewColumn("Message")
170
 
        column.set_resizable(True)
171
 
        column.set_sizing(gtk.TREE_VIEW_COLUMN_FIXED)
172
 
        column.set_fixed_width(cell.get_size(self.treeview)[2])
173
 
        column.pack_start(cell, expand=True)
174
 
        column.add_attribute(cell, "text", treemodel.MESSAGE)
175
 
        self.treeview.append_column(column)
 
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)
176
370
 
177
371
        cell = gtk.CellRendererText()
178
372
        cell.set_property("width-chars", 15)
179
373
        cell.set_property("ellipsize", pango.ELLIPSIZE_END)
180
 
        column = gtk.TreeViewColumn("Committer")
181
 
        column.set_resizable(True)
182
 
        column.set_sizing(gtk.TREE_VIEW_COLUMN_FIXED)
183
 
        column.set_fixed_width(cell.get_size(self.treeview)[2])
184
 
        column.pack_start(cell, expand=True)
185
 
        column.add_attribute(cell, "text", treemodel.COMMITER)
186
 
        self.treeview.append_column(column)
187
 
 
188
 
    def _on_selection_changed(self, selection, *args):
 
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):
189
416
        """callback for when the treeview changes."""
190
 
        (model, selected_rows) = selection.get_selected_rows()
191
 
        if len(selected_rows) > 0:
192
 
            iter = self.model.get_iter(selected_rows[0])
193
 
            self.revision = self.model.get_value(iter, treemodel.REVISION)
194
 
            self.parents = self.model.get_value(iter, treemodel.PARENTS)
195
 
            self.children = self.model.get_value(iter, treemodel.CHILDREN)
196
 
 
 
417
        (path, focus) = treeview.get_cursor()
 
418
        if path is not None:
 
419
            self.iter = self.model.get_iter(path)
197
420
            self.emit('revision-selected')
198
421
 
199
422
    def _on_revision_selected(self, widget, event):
202
425
            menu = RevisionPopupMenu(self.branch.repository, 
203
426
                [self.get_revision().revision_id],
204
427
                self.branch)
 
428
            menu.connect('tag-added', lambda w, t, r: self.add_tag(t, r))
205
429
            menu.popup(None, None, None, event.button, event.get_time())
206
430
 
207
431
    def _on_revision_activated(self, widget, path, col):
208
 
        # TODO: more than one parent
209
 
        """Callback for when a treeview row gets activated."""
210
 
        revision_id = self.model[path][treemodel.REVID]
211
 
        parents = self.model[path][treemodel.PARENTS]
212
 
        if len(parents) == 0:
213
 
            # Ignore revisions without parent
214
 
            return
215
 
        parent_id = parents[0]
216
 
        self.show_diff(self.branch, revision_id, parent_id)
217
 
        self.treeview.grab_focus()
 
432
        self.emit('revision-activated', path, col)