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