/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 annotate/logview.py

  • Committer: Jelmer Vernooij
  • Date: 2006-08-16 00:22:24 UTC
  • Revision ID: jelmer@samba.org-20060816002224-52a986ce5032b1de
Release 0.9, list myself as maintainer.

Show diffs side-by-side

added added

removed removed

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