/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 revisionview.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:
19
19
pygtk.require("2.0")
20
20
import gtk
21
21
import pango
 
22
import gobject
 
23
import subprocess
22
24
 
 
25
from bzrlib.plugins.gtk import icon_path
23
26
from bzrlib.osutils import format_date
24
 
 
25
 
 
26
 
class LogView(gtk.ScrolledWindow):
 
27
from bzrlib.util.bencode import bdecode
 
28
 
 
29
try:
 
30
    from bzrlib.plugins.gtk import seahorse
 
31
except ImportError:
 
32
    has_seahorse = False
 
33
else:
 
34
    has_seahorse = True
 
35
 
 
36
PAGE_GENERAL = 0
 
37
PAGE_RELATIONS = 1
 
38
PAGE_SIGNATURE = 2
 
39
PAGE_BUGS = 3
 
40
 
 
41
def _open_link(widget, uri):
 
42
    subprocess.Popen(['sensible-browser', uri], close_fds=True)
 
43
 
 
44
gtk.link_button_set_uri_hook(_open_link)
 
45
 
 
46
class BugsTab(gtk.VBox):
 
47
 
 
48
    def __init__(self):
 
49
        super(BugsTab, self).__init__(False, 6)
 
50
    
 
51
        table = gtk.Table(rows=2, columns=2)
 
52
 
 
53
        table.set_row_spacings(6)
 
54
        table.set_col_spacing(0, 16)
 
55
 
 
56
        image = gtk.Image()
 
57
        image.set_from_file(icon_path("bug.png"))
 
58
        table.attach(image, 0, 1, 0, 1, gtk.FILL)
 
59
 
 
60
        align = gtk.Alignment(0.0, 0.1)
 
61
        self.label = gtk.Label()
 
62
        align.add(self.label)
 
63
        table.attach(align, 1, 2, 0, 1, gtk.FILL)
 
64
 
 
65
        treeview = self.construct_treeview()
 
66
        table.attach(treeview, 1, 2, 1, 2, gtk.FILL | gtk.EXPAND)
 
67
 
 
68
        self.set_border_width(6)
 
69
        self.pack_start(table, expand=False)
 
70
 
 
71
        self.clear()
 
72
        self.show_all()
 
73
 
 
74
    def set_revision(self, revision):
 
75
        if revision is None:
 
76
            return
 
77
 
 
78
        self.clear()
 
79
        bugs_text = revision.properties.get('bugs', '')
 
80
        for bugline in bugs_text.splitlines():
 
81
                (url, status) = bugline.split(" ")
 
82
                if status == "fixed":
 
83
                    self.add_bug(url, status)
 
84
        
 
85
        if self.num_bugs == 0:
 
86
            return
 
87
        elif self.num_bugs == 1:
 
88
            label = "bug"
 
89
        else:
 
90
            label = "bugs"
 
91
 
 
92
        self.label.set_markup("<b>Bugs fixed</b>\n" +
 
93
                              "This revision claims to fix " +
 
94
                              "%d %s." % (self.num_bugs, label))
 
95
 
 
96
    def construct_treeview(self):
 
97
        self.bugs = gtk.ListStore(gobject.TYPE_STRING, gobject.TYPE_STRING)
 
98
        self.treeview = gtk.TreeView(self.bugs)
 
99
        self.treeview.set_headers_visible(False)
 
100
 
 
101
        uri_column = gtk.TreeViewColumn('Bug URI', gtk.CellRendererText(), text=0)
 
102
        self.treeview.append_column(uri_column)
 
103
 
 
104
        self.treeview.connect('row-activated', self.on_row_activated)
 
105
 
 
106
        win = gtk.ScrolledWindow()
 
107
        win.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
 
108
        win.set_shadow_type(gtk.SHADOW_IN)
 
109
        win.add(self.treeview)
 
110
 
 
111
        return win
 
112
 
 
113
    def clear(self):
 
114
        self.num_bugs = 0
 
115
        self.bugs.clear()
 
116
        self.set_sensitive(False)
 
117
        self.label.set_markup("<b>No bugs fixed</b>\n" +
 
118
                              "This revision does not claim to fix any bugs.")
 
119
 
 
120
    def add_bug(self, url, status):
 
121
        self.num_bugs += 1
 
122
        self.bugs.append([url, status])
 
123
        self.set_sensitive(True)
 
124
 
 
125
    def get_num_bugs(self):
 
126
        return self.num_bugs
 
127
 
 
128
    def on_row_activated(self, treeview, path, column):
 
129
        uri = self.bugs.get_value(self.bugs.get_iter(path), 0)
 
130
        _open_link(self, uri)
 
131
 
 
132
 
 
133
class SignatureTab(gtk.VBox):
 
134
 
 
135
    def __init__(self, repository):
 
136
        self.key = None
 
137
        self.revision = None
 
138
        self.repository = repository
 
139
 
 
140
        super(SignatureTab, self).__init__(False, 6)
 
141
        signature_box = gtk.Table(rows=3, columns=3)
 
142
        signature_box.set_col_spacing(0, 16)
 
143
        signature_box.set_col_spacing(1, 12)
 
144
        signature_box.set_row_spacings(6)
 
145
 
 
146
        self.signature_image = gtk.Image()
 
147
        signature_box.attach(self.signature_image, 0, 1, 0, 1, gtk.FILL)
 
148
 
 
149
        align = gtk.Alignment(0.0, 0.1)
 
150
        self.signature_label = gtk.Label()
 
151
        align.add(self.signature_label)
 
152
        signature_box.attach(align, 1, 3, 0, 1, gtk.FILL)
 
153
 
 
154
        align = gtk.Alignment(0.0, 0.5)
 
155
        self.signature_key_id_label = gtk.Label()
 
156
        self.signature_key_id_label.set_markup("<b>Key Id:</b>")
 
157
        align.add(self.signature_key_id_label)
 
158
        signature_box.attach(align, 1, 2, 1, 2, gtk.FILL, gtk.FILL)
 
159
 
 
160
        align = gtk.Alignment(0.0, 0.5)
 
161
        self.signature_key_id = gtk.Label()
 
162
        self.signature_key_id.set_selectable(True)
 
163
        align.add(self.signature_key_id)
 
164
        signature_box.attach(align, 2, 3, 1, 2, gtk.EXPAND | gtk.FILL, gtk.FILL)
 
165
 
 
166
        align = gtk.Alignment(0.0, 0.5)
 
167
        self.signature_fingerprint_label = gtk.Label()
 
168
        self.signature_fingerprint_label.set_markup("<b>Fingerprint:</b>")
 
169
        align.add(self.signature_fingerprint_label)
 
170
        signature_box.attach(align, 1, 2, 2, 3, gtk.FILL, gtk.FILL)
 
171
 
 
172
        align = gtk.Alignment(0.0, 0.5)
 
173
        self.signature_fingerprint = gtk.Label()
 
174
        self.signature_fingerprint.set_selectable(True)
 
175
        align.add(self.signature_fingerprint)
 
176
        signature_box.attach(align, 2, 3, 2, 3, gtk.EXPAND | gtk.FILL, gtk.FILL)
 
177
 
 
178
        align = gtk.Alignment(0.0, 0.5)
 
179
        self.signature_trust_label = gtk.Label()
 
180
        self.signature_trust_label.set_markup("<b>Trust:</b>")
 
181
        align.add(self.signature_trust_label)
 
182
        signature_box.attach(align, 1, 2, 3, 4, gtk.FILL, gtk.FILL)
 
183
 
 
184
        align = gtk.Alignment(0.0, 0.5)
 
185
        self.signature_trust = gtk.Label()
 
186
        self.signature_trust.set_selectable(True)
 
187
        align.add(self.signature_trust)
 
188
        signature_box.attach(align, 2, 3, 3, 4, gtk.EXPAND | gtk.FILL, gtk.FILL)
 
189
 
 
190
        self.set_border_width(6)
 
191
        self.pack_start(signature_box, expand=False)
 
192
        self.show_all()
 
193
 
 
194
    def set_revision(self, revision):
 
195
        self.revision = revision
 
196
        revid = revision.revision_id
 
197
 
 
198
        if self.repository.has_signature_for_revision_id(revid):
 
199
            crypttext = self.repository.get_signature_text(revid)
 
200
            self.show_signature(crypttext)
 
201
        else:
 
202
            self.show_no_signature()
 
203
 
 
204
    def show_no_signature(self):
 
205
        self.signature_key_id_label.hide()
 
206
        self.signature_key_id.set_text("")
 
207
 
 
208
        self.signature_fingerprint_label.hide()
 
209
        self.signature_fingerprint.set_text("")
 
210
 
 
211
        self.signature_trust_label.hide()
 
212
        self.signature_trust.set_text("")
 
213
 
 
214
        self.signature_image.set_from_file(icon_path("sign-unknown.png"))
 
215
        self.signature_label.set_markup("<b>Authenticity unknown</b>\n" +
 
216
                                        "This revision has not been signed.")
 
217
 
 
218
    def show_signature(self, crypttext):
 
219
        key = seahorse.verify(crypttext)
 
220
 
 
221
        if key and key.is_available():
 
222
            if key.is_trusted():
 
223
                if key.get_display_name() == self.revision.committer:
 
224
                    self.signature_image.set_from_file(icon_path("sign-ok.png"))
 
225
                    self.signature_label.set_markup("<b>Authenticity confirmed</b>\n" +
 
226
                                                    "This revision has been signed with " +
 
227
                                                    "a trusted key.")
 
228
                else:
 
229
                    self.signature_image.set_from_file(icon_path("sign-bad.png"))
 
230
                    self.signature_label.set_markup("<b>Authenticity cannot be confirmed</b>\n" +
 
231
                                                    "Revision committer is not the same as signer.")
 
232
            else:
 
233
                self.signature_image.set_from_file(icon_path("sign-bad.png"))
 
234
                self.signature_label.set_markup("<b>Authenticity cannot be confirmed</b>\n" +
 
235
                                                "This revision has been signed, but the " +
 
236
                                                "key is not trusted.")
 
237
        else:
 
238
            self.show_no_signature()
 
239
            self.signature_image.set_from_file(icon_path("sign-bad.png"))
 
240
            self.signature_label.set_markup("<b>Authenticity cannot be confirmed</b>\n" +
 
241
                                            "Signature key not available.")
 
242
            return
 
243
 
 
244
        trust = key.get_trust()
 
245
 
 
246
        if trust <= seahorse.TRUST_NEVER:
 
247
            trust_text = 'never trusted'
 
248
        elif trust == seahorse.TRUST_UNKNOWN:
 
249
            trust_text = 'not trusted'
 
250
        elif trust == seahorse.TRUST_MARGINAL:
 
251
            trust_text = 'marginally trusted'
 
252
        elif trust == seahorse.TRUST_FULL:
 
253
            trust_text = 'fully trusted'
 
254
        elif trust == seahorse.TRUST_ULTIMATE:
 
255
            trust_text = 'ultimately trusted'
 
256
 
 
257
        self.signature_key_id_label.show()
 
258
        self.signature_key_id.set_text(key.get_id())
 
259
 
 
260
        fingerprint = key.get_fingerprint()
 
261
        if fingerprint == "":
 
262
            fingerprint = '<span foreground="dim grey">N/A</span>'
 
263
 
 
264
        self.signature_fingerprint_label.show()
 
265
        self.signature_fingerprint.set_markup(fingerprint)
 
266
 
 
267
        self.signature_trust_label.show()
 
268
        self.signature_trust.set_text('This key is ' + trust_text)
 
269
 
 
270
 
 
271
class RevisionView(gtk.Notebook):
27
272
    """ Custom widget for commit log details.
28
273
 
29
274
    A variety of bzr tools may need to implement such a thing. This is a
30
275
    start.
31
276
    """
32
277
 
33
 
    def __init__(self, revision=None, scroll=True, tags=None):
34
 
        super(LogView, self).__init__()
35
 
        if scroll:
36
 
            self.set_policy(gtk.POLICY_NEVER, gtk.POLICY_AUTOMATIC)
 
278
    __gproperties__ = {
 
279
        'branch': (
 
280
            gobject.TYPE_PYOBJECT,
 
281
            'Branch',
 
282
            'The branch holding the revision being displayed',
 
283
            gobject.PARAM_CONSTRUCT_ONLY | gobject.PARAM_WRITABLE
 
284
        ),
 
285
 
 
286
        'revision': (
 
287
            gobject.TYPE_PYOBJECT,
 
288
            'Revision',
 
289
            'The revision being displayed',
 
290
            gobject.PARAM_READWRITE
 
291
        ),
 
292
 
 
293
        'children': (
 
294
            gobject.TYPE_PYOBJECT,
 
295
            'Children',
 
296
            'Child revisions',
 
297
            gobject.PARAM_READWRITE
 
298
        ),
 
299
 
 
300
        'file-id': (
 
301
            gobject.TYPE_PYOBJECT,
 
302
            'File Id',
 
303
            'The file id',
 
304
            gobject.PARAM_READWRITE
 
305
        )
 
306
    }
 
307
 
 
308
    def __init__(self, branch=None, repository=None):
 
309
        gtk.Notebook.__init__(self)
 
310
 
 
311
        self._revision = None
 
312
        self._branch = branch
 
313
        if branch is not None:
 
314
            self._repository = branch.repository
37
315
        else:
38
 
            self.set_policy(gtk.POLICY_NEVER, gtk.POLICY_NEVER)
39
 
        self.set_shadow_type(gtk.SHADOW_NONE)
40
 
        self._create()
 
316
            self._repository = repository
 
317
 
 
318
        self._create_general()
 
319
        self._create_relations()
 
320
        if has_seahorse:
 
321
            self._create_signature()
 
322
        self._create_file_info_view()
 
323
        self._create_bugs()
 
324
 
 
325
        self.set_current_page(PAGE_GENERAL)
 
326
        self.connect_after('switch-page', self._switch_page_cb)
 
327
        
41
328
        self._show_callback = None
42
 
        self._go_callback = None
43
329
        self._clicked_callback = None
44
330
 
45
 
        if revision is not None:
46
 
            self.set_revision(revision, tags=tags)
 
331
        self._revision = None
 
332
        self._branch = branch
 
333
 
 
334
        self.update_tags()
 
335
 
 
336
        self.set_file_id(None)
 
337
 
 
338
    def do_get_property(self, property):
 
339
        if property.name == 'branch':
 
340
            return self._branch
 
341
        elif property.name == 'revision':
 
342
            return self._revision
 
343
        elif property.name == 'children':
 
344
            return self._children
 
345
        elif property.name == 'file-id':
 
346
            return self._file_id
 
347
        else:
 
348
            raise AttributeError, 'unknown property %s' % property.name
 
349
 
 
350
    def do_set_property(self, property, value):
 
351
        if property.name == 'branch':
 
352
            self._branch = value
 
353
        elif property.name == 'revision':
 
354
            self._set_revision(value)
 
355
        elif property.name == 'children':
 
356
            self.set_children(value)
 
357
        elif property.name == 'file-id':
 
358
            self._file_id = value
 
359
        else:
 
360
            raise AttributeError, 'unknown property %s' % property.name
47
361
 
48
362
    def set_show_callback(self, callback):
49
363
        self._show_callback = callback
50
364
 
51
 
    def set_go_callback(self, callback):
52
 
        self._go_callback = callback
53
 
 
54
 
    def set_revision(self, revision, tags=None):
 
365
    def set_file_id(self, file_id):
 
366
        """Set a specific file id that we want to track.
 
367
 
 
368
        This just effects the display of a per-file commit message.
 
369
        If it is set to None, then all commit messages will be shown.
 
370
        """
 
371
        self.set_property('file-id', file_id)
 
372
 
 
373
    def set_revision(self, revision):
 
374
        if revision != self._revision:
 
375
            self.set_property('revision', revision)
 
376
 
 
377
    def get_revision(self):
 
378
        return self.get_property('revision')
 
379
 
 
380
    def _set_revision(self, revision):
 
381
        if revision is None: return
 
382
 
55
383
        self._revision = revision
56
 
        self.revision_id.set_text(revision.revision_id)
57
384
        if revision.committer is not None:
58
385
            self.committer.set_text(revision.committer)
59
386
        else:
60
387
            self.committer.set_text("")
 
388
        author = revision.properties.get('author', '')
 
389
        if author != '':
 
390
            self.author.set_text(author)
 
391
            self.author.show()
 
392
            self.author_label.show()
 
393
        else:
 
394
            self.author.hide()
 
395
            self.author_label.hide()
 
396
 
61
397
        if revision.timestamp is not None:
62
398
            self.timestamp.set_text(format_date(revision.timestamp,
63
399
                                                revision.timezone))
64
 
        self.message_buffer.set_text(revision.message)
65
400
        try:
66
401
            self.branchnick_label.set_text(revision.properties['branch-nick'])
67
402
        except KeyError:
68
403
            self.branchnick_label.set_text("")
69
404
 
70
 
        self._add_parents(revision.parent_ids)
71
 
        self._add_tags(tags)
 
405
        self._add_parents_or_children(revision.parent_ids,
 
406
                                      self.parents_widgets,
 
407
                                      self.parents_table)
 
408
        
 
409
        file_info = revision.properties.get('file-info', None)
 
410
        if file_info is not None:
 
411
            file_info = bdecode(file_info.encode('UTF-8'))
 
412
 
 
413
        if file_info:
 
414
            if self._file_id is None:
 
415
                text = []
 
416
                for fi in file_info:
 
417
                    text.append('%(path)s\n%(message)s' % fi)
 
418
                self.file_info_buffer.set_text('\n'.join(text))
 
419
                self.file_info_box.show()
 
420
            else:
 
421
                text = []
 
422
                for fi in file_info:
 
423
                    if fi['file_id'] == self._file_id:
 
424
                        text.append(fi['message'])
 
425
                if text:
 
426
                    self.file_info_buffer.set_text('\n'.join(text))
 
427
                    self.file_info_box.show()
 
428
                else:
 
429
                    self.file_info_box.hide()
 
430
        else:
 
431
            self.file_info_box.hide()
 
432
 
 
433
    def update_tags(self):
 
434
        if self._branch is not None and self._branch.supports_tags():
 
435
            self._tagdict = self._branch.tags.get_reverse_tag_dict()
 
436
        else:
 
437
            self._tagdict = {}
 
438
 
 
439
        self._add_tags()
 
440
 
 
441
    def _update_signature(self, widget, param):
 
442
        if self.get_current_page() == PAGE_SIGNATURE:
 
443
            self.signature_table.set_revision(self._revision)
 
444
 
 
445
    def _update_bugs(self, widget, param):
 
446
        self.bugs_page.set_revision(self._revision)
 
447
        label = self.get_tab_label(self.bugs_page)
 
448
        label.set_sensitive(self.bugs_page.get_num_bugs() != 0)
 
449
 
 
450
    def set_children(self, children):
 
451
        self._add_parents_or_children(children,
 
452
                                      self.children_widgets,
 
453
                                      self.children_table)
 
454
 
 
455
    def _switch_page_cb(self, notebook, page, page_num):
 
456
        if page_num == PAGE_SIGNATURE:
 
457
            self.signature_table.set_revision(self._revision)
 
458
 
 
459
 
72
460
 
73
461
    def _show_clicked_cb(self, widget, revid, parentid):
74
462
        """Callback for when the show button for a parent is clicked."""
76
464
 
77
465
    def _go_clicked_cb(self, widget, revid):
78
466
        """Callback for when the go button for a parent is clicked."""
79
 
        self._go_callback(revid)
80
 
 
81
 
    def _add_tags(self, tags):
 
467
 
 
468
    def _add_tags(self, *args):
 
469
        if self._revision is None:
 
470
            return
 
471
 
 
472
        if self._tagdict.has_key(self._revision.revision_id):
 
473
            tags = self._tagdict[self._revision.revision_id]
 
474
        else:
 
475
            tags = []
 
476
            
82
477
        if tags == []:
83
478
            self.tags_list.hide()
84
479
            self.tags_label.hide()
85
480
            return
86
481
 
87
 
        for widget in self.tags_widgets:
88
 
            self.tags_list.remove(widget)
89
 
 
90
 
        self.tags_widgets = []
91
 
 
92
 
        for tag in tags:
93
 
            widget = gtk.Label(tag)
94
 
            widget.set_selectable(True)
95
 
            self.tags_widgets.append(widget)
96
 
            self.tags_list.add(widget)
 
482
        self.tags_list.set_text(", ".join(tags))
 
483
 
97
484
        self.tags_list.show_all()
98
485
        self.tags_label.show_all()
99
486
        
100
 
 
101
 
    def _add_parents(self, parent_ids):
102
 
        for widget in self.parents_widgets:
103
 
            self.parents_table.remove(widget)
104
 
            
105
 
        self.parents_widgets = []
106
 
        self.parents_table.resize(max(len(parent_ids), 1), 2)
107
 
 
108
 
        for idx, parent_id in enumerate(parent_ids):
 
487
    def _add_parents_or_children(self, revids, widgets, table):
 
488
        while len(widgets) > 0:
 
489
            widget = widgets.pop()
 
490
            table.remove(widget)
 
491
        
 
492
        table.resize(max(len(revids), 1), 2)
 
493
 
 
494
        for idx, revid in enumerate(revids):
109
495
            align = gtk.Alignment(0.0, 0.0)
110
 
            self.parents_widgets.append(align)
111
 
            self.parents_table.attach(align, 1, 2, idx, idx + 1,
 
496
            widgets.append(align)
 
497
            table.attach(align, 1, 2, idx, idx + 1,
112
498
                                      gtk.EXPAND | gtk.FILL, gtk.FILL)
113
499
            align.show()
114
500
 
125
511
                button = gtk.Button()
126
512
                button.add(image)
127
513
                button.connect("clicked", self._show_clicked_cb,
128
 
                               self._revision.revision_id, parent_id)
 
514
                               self._revision.revision_id, revid)
129
515
                hbox.pack_start(button, expand=False, fill=True)
130
516
                button.show()
131
517
 
132
 
            if self._go_callback is not None:
133
 
                button = gtk.Button(parent_id)
134
 
                button.connect("clicked", self._go_clicked_cb, parent_id)
135
 
            else:
136
 
                button = gtk.Label(parent_id)
 
518
            button = gtk.Button(revid)
 
519
            button.connect("clicked",
 
520
                    lambda w, r: self.set_revision(self._repository.get_revision(r)), revid)
137
521
            button.set_use_underline(False)
138
522
            hbox.pack_start(button, expand=False, fill=True)
139
523
            button.show()
140
524
 
141
 
    def _create(self):
 
525
    def _create_general(self):
142
526
        vbox = gtk.VBox(False, 6)
143
527
        vbox.set_border_width(6)
144
528
        vbox.pack_start(self._create_headers(), expand=False, fill=True)
145
 
        vbox.pack_start(self._create_parents_table(), expand=False, fill=True)
146
529
        vbox.pack_start(self._create_message_view())
147
 
        self.add_with_viewport(vbox)
148
 
        vbox.show()
 
530
        self.append_page(vbox, tab_label=gtk.Label("General"))
 
531
        vbox.show()
 
532
 
 
533
    def _create_relations(self):
 
534
        vbox = gtk.VBox(False, 6)
 
535
        vbox.set_border_width(6)
 
536
        vbox.pack_start(self._create_parents(), expand=False, fill=True)
 
537
        vbox.pack_start(self._create_children(), expand=False, fill=True)
 
538
        self.append_page(vbox, tab_label=gtk.Label("Relations"))
 
539
        vbox.show()
 
540
 
 
541
    def _create_signature(self):
 
542
        self.signature_table = SignatureTab(self._repository)
 
543
        self.append_page(self.signature_table, tab_label=gtk.Label('Signature'))
 
544
        self.connect_after('notify::revision', self._update_signature)
149
545
 
150
546
    def _create_headers(self):
151
547
        self.table = gtk.Table(rows=5, columns=2)
162
558
        label.show()
163
559
 
164
560
        align = gtk.Alignment(0.0, 0.5)
165
 
        self.revision_id = gtk.Label()
166
 
        self.revision_id.set_selectable(True)
167
 
        align.add(self.revision_id)
 
561
        revision_id = gtk.Label()
 
562
        revision_id.set_selectable(True)
 
563
        self.connect('notify::revision', 
 
564
                lambda w, p: revision_id.set_text(self._revision.revision_id))
 
565
        align.add(revision_id)
168
566
        self.table.attach(align, 1, 2, 0, 1, gtk.EXPAND | gtk.FILL, gtk.FILL)
169
567
        align.show()
170
 
        self.revision_id.show()
 
568
        revision_id.show()
 
569
 
 
570
        align = gtk.Alignment(1.0, 0.5)
 
571
        self.author_label = gtk.Label()
 
572
        self.author_label.set_markup("<b>Author:</b>")
 
573
        align.add(self.author_label)
 
574
        self.table.attach(align, 0, 1, 1, 2, gtk.FILL, gtk.FILL)
 
575
        align.show()
 
576
        self.author_label.show()
 
577
 
 
578
        align = gtk.Alignment(0.0, 0.5)
 
579
        self.author = gtk.Label()
 
580
        self.author.set_selectable(True)
 
581
        align.add(self.author)
 
582
        self.table.attach(align, 1, 2, 1, 2, gtk.EXPAND | gtk.FILL, gtk.FILL)
 
583
        align.show()
 
584
        self.author.show()
 
585
        self.author.hide()
171
586
 
172
587
        align = gtk.Alignment(1.0, 0.5)
173
588
        label = gtk.Label()
174
589
        label.set_markup("<b>Committer:</b>")
175
590
        align.add(label)
176
 
        self.table.attach(align, 0, 1, 1, 2, gtk.FILL, gtk.FILL)
 
591
        self.table.attach(align, 0, 1, 2, 3, gtk.FILL, gtk.FILL)
177
592
        align.show()
178
593
        label.show()
179
594
 
181
596
        self.committer = gtk.Label()
182
597
        self.committer.set_selectable(True)
183
598
        align.add(self.committer)
184
 
        self.table.attach(align, 1, 2, 1, 2, gtk.EXPAND | gtk.FILL, gtk.FILL)
 
599
        self.table.attach(align, 1, 2, 2, 3, gtk.EXPAND | gtk.FILL, gtk.FILL)
185
600
        align.show()
186
601
        self.committer.show()
187
602
 
189
604
        label = gtk.Label()
190
605
        label.set_markup("<b>Branch nick:</b>")
191
606
        align.add(label)
192
 
        self.table.attach(align, 0, 1, 2, 3, gtk.FILL, gtk.FILL)
 
607
        self.table.attach(align, 0, 1, 3, 4, gtk.FILL, gtk.FILL)
193
608
        label.show()
194
609
        align.show()
195
610
 
197
612
        self.branchnick_label = gtk.Label()
198
613
        self.branchnick_label.set_selectable(True)
199
614
        align.add(self.branchnick_label)
200
 
        self.table.attach(align, 1, 2, 2, 3, gtk.EXPAND | gtk.FILL, gtk.FILL)
 
615
        self.table.attach(align, 1, 2, 3, 4, gtk.EXPAND | gtk.FILL, gtk.FILL)
201
616
        self.branchnick_label.show()
202
617
        align.show()
203
618
 
205
620
        label = gtk.Label()
206
621
        label.set_markup("<b>Timestamp:</b>")
207
622
        align.add(label)
208
 
        self.table.attach(align, 0, 1, 3, 4, gtk.FILL, gtk.FILL)
 
623
        self.table.attach(align, 0, 1, 4, 5, gtk.FILL, gtk.FILL)
209
624
        align.show()
210
625
        label.show()
211
626
 
213
628
        self.timestamp = gtk.Label()
214
629
        self.timestamp.set_selectable(True)
215
630
        align.add(self.timestamp)
216
 
        self.table.attach(align, 1, 2, 3, 4, gtk.EXPAND | gtk.FILL, gtk.FILL)
 
631
        self.table.attach(align, 1, 2, 4, 5, gtk.EXPAND | gtk.FILL, gtk.FILL)
217
632
        align.show()
218
633
        self.timestamp.show()
219
634
 
222
637
        self.tags_label.set_markup("<b>Tags:</b>")
223
638
        align.add(self.tags_label)
224
639
        align.show()
225
 
        self.table.attach(align, 0, 1, 4, 5, gtk.FILL, gtk.FILL)
 
640
        self.table.attach(align, 0, 1, 5, 6, gtk.FILL, gtk.FILL)
226
641
        self.tags_label.show()
227
642
 
228
643
        align = gtk.Alignment(0.0, 0.5)
229
 
        self.tags_list = gtk.VBox()
 
644
        self.tags_list = gtk.Label()
230
645
        align.add(self.tags_list)
231
 
        self.table.attach(align, 1, 2, 4, 5, gtk.EXPAND | gtk.FILL, gtk.FILL)
 
646
        self.table.attach(align, 1, 2, 5, 6, gtk.EXPAND | gtk.FILL, gtk.FILL)
232
647
        align.show()
233
648
        self.tags_list.show()
234
 
        self.tags_widgets = []
 
649
 
 
650
        self.connect('notify::revision', self._add_tags)
235
651
 
236
652
        return self.table
237
 
 
238
 
    def _create_parents_table(self):
239
 
        self.parents_table = gtk.Table(rows=1, columns=2)
240
 
        self.parents_table.set_row_spacings(3)
241
 
        self.parents_table.set_col_spacings(6)
242
 
        self.parents_table.show()
 
653
    
 
654
    def _create_parents(self):
 
655
        hbox = gtk.HBox(True, 3)
 
656
        
 
657
        self.parents_table = self._create_parents_or_children_table(
 
658
            "<b>Parents:</b>")
243
659
        self.parents_widgets = []
 
660
        hbox.pack_start(self.parents_table)
 
661
 
 
662
        hbox.show()
 
663
        return hbox
 
664
 
 
665
    def _create_children(self):
 
666
        hbox = gtk.HBox(True, 3)
 
667
        self.children_table = self._create_parents_or_children_table(
 
668
            "<b>Children:</b>")
 
669
        self.children_widgets = []
 
670
        hbox.pack_start(self.children_table)
 
671
        hbox.show()
 
672
        return hbox
 
673
        
 
674
    def _create_parents_or_children_table(self, text):
 
675
        table = gtk.Table(rows=1, columns=2)
 
676
        table.set_row_spacings(3)
 
677
        table.set_col_spacings(6)
 
678
        table.show()
244
679
 
245
680
        label = gtk.Label()
246
 
        label.set_markup("<b>Parents:</b>")
 
681
        label.set_markup(text)
247
682
        align = gtk.Alignment(0.0, 0.5)
248
683
        align.add(label)
249
 
        self.parents_table.attach(align, 0, 1, 0, 1, gtk.FILL, gtk.FILL)
 
684
        table.attach(align, 0, 1, 0, 1, gtk.FILL, gtk.FILL)
250
685
        label.show()
251
686
        align.show()
252
687
 
253
 
        return self.parents_table
 
688
        return table
254
689
 
255
690
    def _create_message_view(self):
256
 
        self.message_buffer = gtk.TextBuffer()
257
 
        tv = gtk.TextView(self.message_buffer)
258
 
        tv.set_editable(False)
259
 
        tv.set_wrap_mode(gtk.WRAP_WORD)
260
 
        tv.modify_font(pango.FontDescription("Monospace"))
261
 
        tv.show()
262
 
        return tv
 
691
        msg_buffer = gtk.TextBuffer()
 
692
        self.connect('notify::revision',
 
693
                lambda w, p: msg_buffer.set_text(self._revision.message))
 
694
        window = gtk.ScrolledWindow()
 
695
        window.set_policy(gtk.POLICY_NEVER, gtk.POLICY_AUTOMATIC)
 
696
        window.set_shadow_type(gtk.SHADOW_IN)
 
697
        tv = gtk.TextView(msg_buffer)
 
698
        tv.set_editable(False)
 
699
        tv.set_wrap_mode(gtk.WRAP_WORD)
 
700
 
 
701
        tv.modify_font(pango.FontDescription("Monospace"))
 
702
        tv.show()
 
703
        window.add(tv)
 
704
        window.show()
 
705
        return window
 
706
 
 
707
    def _create_bugs(self):
 
708
        self.bugs_page = BugsTab()
 
709
        self.connect_after('notify::revision', self._update_bugs) 
 
710
        self.append_page(self.bugs_page, tab_label=gtk.Label('Bugs'))
 
711
 
 
712
    def _create_file_info_view(self):
 
713
        self.file_info_box = gtk.VBox(False, 6)
 
714
        self.file_info_box.set_border_width(6)
 
715
        self.file_info_buffer = gtk.TextBuffer()
 
716
        window = gtk.ScrolledWindow()
 
717
        window.set_policy(gtk.POLICY_NEVER, gtk.POLICY_AUTOMATIC)
 
718
        window.set_shadow_type(gtk.SHADOW_IN)
 
719
        tv = gtk.TextView(self.file_info_buffer)
 
720
        tv.set_editable(False)
 
721
        tv.set_wrap_mode(gtk.WRAP_WORD)
 
722
        tv.modify_font(pango.FontDescription("Monospace"))
 
723
        tv.show()
 
724
        window.add(tv)
 
725
        window.show()
 
726
        self.file_info_box.pack_start(window)
 
727
        self.file_info_box.hide() # Only shown when there are per-file messages
 
728
        self.append_page(self.file_info_box, tab_label=gtk.Label('Per-file'))
263
729