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