/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: Daniel Schierbeck
  • Date: 2008-04-07 20:34:51 UTC
  • mfrom: (450.6.13 bugs)
  • mto: (463.2.1 bug.78765)
  • mto: This revision was merged to the branch mainline in revision 462.
  • Revision ID: daniel.schierbeck@gmail.com-20080407203451-2i6el7jf9t0k9y64
Merged bug page improvements.

Show diffs side-by-side

added added

removed removed

Lines of Context:
15
15
# along with this program; if not, write to the Free Software
16
16
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
17
17
 
18
 
from gi.repository import Gtk
19
 
from gi.repository import Pango
20
 
from gi.repository import GObject
21
 
import webbrowser
 
18
import pygtk
 
19
pygtk.require("2.0")
 
20
import gtk
 
21
import pango
 
22
import gobject
 
23
import subprocess
22
24
 
23
 
from bzrlib import trace
 
25
from bzrlib.plugins.gtk import icon_path
24
26
from bzrlib.osutils import format_date
25
 
from bzrlib.bencode import bdecode
26
 
from bzrlib.testament import Testament
27
 
 
28
 
from bzrlib.plugins.gtk import icon_path
29
 
 
30
 
from bzrlib.plugins.gtk.avatarsbox import AvatarsBox
 
27
from bzrlib.util.bencode import bdecode
31
28
 
32
29
try:
33
30
    from bzrlib.plugins.gtk import seahorse
36
33
else:
37
34
    has_seahorse = True
38
35
 
39
 
PAGE_GENERAL = 0
40
 
PAGE_RELATIONS = 1
41
 
PAGE_SIGNATURE = 2
42
 
PAGE_BUGS = 3
43
 
 
44
 
 
45
36
def _open_link(widget, uri):
46
 
    for cmd in ['sensible-browser', 'xdg-open']:
47
 
        if webbrowser._iscommand(cmd):
48
 
            webbrowser._tryorder.insert(0, '%s "%%s"' % cmd)
49
 
    webbrowser.open(uri)
50
 
 
51
 
 
52
 
class BugsTab(Gtk.VBox):
 
37
    subprocess.Popen(['sensible-browser', uri], close_fds=True)
 
38
 
 
39
gtk.link_button_set_uri_hook(_open_link)
 
40
 
 
41
class BugsTab(gtk.VBox):
53
42
 
54
43
    def __init__(self):
55
 
        super(BugsTab, self).__init__(homogeneous=False, spacing=6)
56
 
 
57
 
        table = Gtk.Table(rows=2, columns=2)
 
44
        super(BugsTab, self).__init__(False, 6)
 
45
    
 
46
        table = gtk.Table(rows=2, columns=2)
58
47
 
59
48
        table.set_row_spacings(6)
60
49
        table.set_col_spacing(0, 16)
61
50
 
62
 
        image = Gtk.Image()
 
51
        image = gtk.Image()
63
52
        image.set_from_file(icon_path("bug.png"))
64
 
        table.attach(image, 0, 1, 0, 1, Gtk.AttachOptions.FILL)
 
53
        table.attach(image, 0, 1, 0, 1, gtk.FILL)
65
54
 
66
 
        align = Gtk.Alignment.new(0.0, 0.1, 0, 0)
67
 
        self.label = Gtk.Label()
 
55
        align = gtk.Alignment(0.0, 0.1)
 
56
        self.label = gtk.Label()
68
57
        align.add(self.label)
69
 
        table.attach(align, 1, 2, 0, 1, Gtk.AttachOptions.FILL)
 
58
        table.attach(align, 1, 2, 0, 1, gtk.FILL)
70
59
 
71
60
        treeview = self.construct_treeview()
72
 
        table.attach(treeview, 1, 2, 1, 2, Gtk.AttachOptions.FILL | Gtk.AttachOptions.EXPAND)
 
61
        table.attach(treeview, 1, 2, 1, 2, gtk.FILL | gtk.EXPAND)
73
62
 
74
63
        self.set_border_width(6)
75
 
        self.pack_start(table, False, True, 0)
 
64
        self.pack_start(table, expand=False)
76
65
 
77
66
        self.clear()
78
67
        self.show_all()
87
76
                (url, status) = bugline.split(" ")
88
77
                if status == "fixed":
89
78
                    self.add_bug(url, status)
90
 
 
 
79
        
91
80
        if self.num_bugs == 0:
92
81
            return
93
82
        elif self.num_bugs == 1:
100
89
                              "%d %s." % (self.num_bugs, label))
101
90
 
102
91
    def construct_treeview(self):
103
 
        self.bugs = Gtk.ListStore(GObject.TYPE_STRING, GObject.TYPE_STRING)
104
 
        self.treeview = Gtk.TreeView(model=self.bugs)
 
92
        self.bugs = gtk.ListStore(gobject.TYPE_STRING, gobject.TYPE_STRING)
 
93
        self.treeview = gtk.TreeView(self.bugs)
105
94
        self.treeview.set_headers_visible(False)
106
95
 
107
 
        uri_column = Gtk.TreeViewColumn('Bug URI', Gtk.CellRendererText(), text=0)
 
96
        uri_column = gtk.TreeViewColumn('Bug URI', gtk.CellRendererText(), text=0)
108
97
        self.treeview.append_column(uri_column)
109
98
 
110
99
        self.treeview.connect('row-activated', self.on_row_activated)
111
100
 
112
 
        win = Gtk.ScrolledWindow()
113
 
        win.set_policy(Gtk.PolicyType.AUTOMATIC, Gtk.PolicyType.AUTOMATIC)
114
 
        win.set_shadow_type(Gtk.ShadowType.IN)
 
101
        win = gtk.ScrolledWindow()
 
102
        win.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
 
103
        win.set_shadow_type(gtk.SHADOW_IN)
115
104
        win.add(self.treeview)
116
105
 
117
106
        return win
136
125
        _open_link(self, uri)
137
126
 
138
127
 
139
 
class SignatureTab(Gtk.VBox):
 
128
class SignatureTab(gtk.VBox):
140
129
 
141
130
    def __init__(self, repository):
142
131
        self.key = None
143
132
        self.revision = None
144
133
        self.repository = repository
145
134
 
146
 
        super(SignatureTab, self).__init__(homogeneous=False, spacing=6)
147
 
        signature_box = Gtk.Table(rows=3, columns=3)
 
135
        super(SignatureTab, self).__init__(False, 6)
 
136
        signature_box = gtk.Table(rows=3, columns=3)
148
137
        signature_box.set_col_spacing(0, 16)
149
138
        signature_box.set_col_spacing(1, 12)
150
139
        signature_box.set_row_spacings(6)
151
140
 
152
 
        self.signature_image = Gtk.Image()
153
 
        signature_box.attach(self.signature_image, 0, 1, 0, 1, Gtk.AttachOptions.FILL)
 
141
        self.signature_image = gtk.Image()
 
142
        signature_box.attach(self.signature_image, 0, 1, 0, 1, gtk.FILL)
154
143
 
155
 
        align = Gtk.Alignment.new(0.0, 0.1, 0.0, 0.0)
156
 
        self.signature_label = Gtk.Label()
 
144
        align = gtk.Alignment(0.0, 0.1)
 
145
        self.signature_label = gtk.Label()
157
146
        align.add(self.signature_label)
158
 
        signature_box.attach(align, 1, 3, 0, 1, Gtk.AttachOptions.FILL)
 
147
        signature_box.attach(align, 1, 3, 0, 1, gtk.FILL)
159
148
 
160
 
        align = Gtk.Alignment.new(0.0, 0.5, 0.0, 0.0)
161
 
        self.signature_key_id_label = Gtk.Label()
 
149
        align = gtk.Alignment(0.0, 0.5)
 
150
        self.signature_key_id_label = gtk.Label()
162
151
        self.signature_key_id_label.set_markup("<b>Key Id:</b>")
163
152
        align.add(self.signature_key_id_label)
164
 
        signature_box.attach(align, 1, 2, 1, 2, Gtk.AttachOptions.FILL, Gtk.AttachOptions.FILL)
 
153
        signature_box.attach(align, 1, 2, 1, 2, gtk.FILL, gtk.FILL)
165
154
 
166
 
        align = Gtk.Alignment.new(0.0, 0.5, 0.0, 0.0)
167
 
        self.signature_key_id = Gtk.Label()
 
155
        align = gtk.Alignment(0.0, 0.5)
 
156
        self.signature_key_id = gtk.Label()
168
157
        self.signature_key_id.set_selectable(True)
169
158
        align.add(self.signature_key_id)
170
 
        signature_box.attach(align, 2, 3, 1, 2, Gtk.AttachOptions.EXPAND | Gtk.AttachOptions.FILL, Gtk.AttachOptions.FILL)
 
159
        signature_box.attach(align, 2, 3, 1, 2, gtk.EXPAND | gtk.FILL, gtk.FILL)
171
160
 
172
 
        align = Gtk.Alignment.new(0.0, 0.5, 0.0, 0.0)
173
 
        self.signature_fingerprint_label = Gtk.Label()
 
161
        align = gtk.Alignment(0.0, 0.5)
 
162
        self.signature_fingerprint_label = gtk.Label()
174
163
        self.signature_fingerprint_label.set_markup("<b>Fingerprint:</b>")
175
164
        align.add(self.signature_fingerprint_label)
176
 
        signature_box.attach(align, 1, 2, 2, 3, Gtk.AttachOptions.FILL, Gtk.AttachOptions.FILL)
 
165
        signature_box.attach(align, 1, 2, 2, 3, gtk.FILL, gtk.FILL)
177
166
 
178
 
        align = Gtk.Alignment.new(0.0, 0.5, 0.0, 0.0)
179
 
        self.signature_fingerprint = Gtk.Label()
 
167
        align = gtk.Alignment(0.0, 0.5)
 
168
        self.signature_fingerprint = gtk.Label()
180
169
        self.signature_fingerprint.set_selectable(True)
181
170
        align.add(self.signature_fingerprint)
182
 
        signature_box.attach(align, 2, 3, 2, 3, Gtk.AttachOptions.EXPAND | Gtk.AttachOptions.FILL, Gtk.AttachOptions.FILL)
 
171
        signature_box.attach(align, 2, 3, 2, 3, gtk.EXPAND | gtk.FILL, gtk.FILL)
183
172
 
184
 
        align = Gtk.Alignment.new(0.0, 0.5, 0.0, 0.0)
185
 
        self.signature_trust_label = Gtk.Label()
 
173
        align = gtk.Alignment(0.0, 0.5)
 
174
        self.signature_trust_label = gtk.Label()
186
175
        self.signature_trust_label.set_markup("<b>Trust:</b>")
187
176
        align.add(self.signature_trust_label)
188
 
        signature_box.attach(align, 1, 2, 3, 4, Gtk.AttachOptions.FILL, Gtk.AttachOptions.FILL)
 
177
        signature_box.attach(align, 1, 2, 3, 4, gtk.FILL, gtk.FILL)
189
178
 
190
 
        align = Gtk.Alignment.new(0.0, 0.5, 0.0, 0.0)
191
 
        self.signature_trust = Gtk.Label()
 
179
        align = gtk.Alignment(0.0, 0.5)
 
180
        self.signature_trust = gtk.Label()
192
181
        self.signature_trust.set_selectable(True)
193
182
        align.add(self.signature_trust)
194
 
        signature_box.attach(align, 2, 3, 3, 4, Gtk.AttachOptions.EXPAND | Gtk.AttachOptions.FILL, Gtk.AttachOptions.FILL)
 
183
        signature_box.attach(align, 2, 3, 3, 4, gtk.EXPAND | gtk.FILL, gtk.FILL)
195
184
 
196
185
        self.set_border_width(6)
197
 
        self.pack_start(signature_box, False, True, 0)
 
186
        self.pack_start(signature_box, expand=False)
198
187
        self.show_all()
199
188
 
200
189
    def set_revision(self, revision):
222
211
                                        "This revision has not been signed.")
223
212
 
224
213
    def show_signature(self, crypttext):
225
 
        (cleartext, key) = seahorse.verify(crypttext)
226
 
 
227
 
        assert cleartext is not None
228
 
 
229
 
        inv = self.repository.get_inventory(self.revision.revision_id)
230
 
        expected_testament = Testament(self.revision, inv).as_short_text()
231
 
        if expected_testament != cleartext:
232
 
            self.signature_image.set_from_file(icon_path("sign-bad.png"))
233
 
            self.signature_label.set_markup("<b>Signature does not match repository data</b>\n" +
234
 
                        "The signature plaintext is different from the expected testament plaintext.")
235
 
            return
 
214
        key = seahorse.verify(crypttext)
236
215
 
237
216
        if key and key.is_available():
238
217
            if key.is_trusted():
284
263
        self.signature_trust.set_text('This key is ' + trust_text)
285
264
 
286
265
 
287
 
class RevisionView(Gtk.Notebook):
 
266
class RevisionView(gtk.Notebook):
288
267
    """ Custom widget for commit log details.
289
268
 
290
269
    A variety of bzr tools may need to implement such a thing. This is a
293
272
 
294
273
    __gproperties__ = {
295
274
        'branch': (
296
 
            GObject.TYPE_PYOBJECT,
 
275
            gobject.TYPE_PYOBJECT,
297
276
            'Branch',
298
277
            'The branch holding the revision being displayed',
299
 
            GObject.PARAM_CONSTRUCT_ONLY | GObject.PARAM_WRITABLE
 
278
            gobject.PARAM_CONSTRUCT_ONLY | gobject.PARAM_WRITABLE
300
279
        ),
301
280
 
302
281
        'revision': (
303
 
            GObject.TYPE_PYOBJECT,
 
282
            gobject.TYPE_PYOBJECT,
304
283
            'Revision',
305
284
            'The revision being displayed',
306
 
            GObject.PARAM_READWRITE
 
285
            gobject.PARAM_READWRITE
307
286
        ),
308
287
 
309
288
        'children': (
310
 
            GObject.TYPE_PYOBJECT,
 
289
            gobject.TYPE_PYOBJECT,
311
290
            'Children',
312
291
            'Child revisions',
313
 
            GObject.PARAM_READWRITE
 
292
            gobject.PARAM_READWRITE
314
293
        ),
315
294
 
316
295
        'file-id': (
317
 
            GObject.TYPE_PYOBJECT,
 
296
            gobject.TYPE_PYOBJECT,
318
297
            'File Id',
319
298
            'The file id',
320
 
            GObject.PARAM_READWRITE
 
299
            gobject.PARAM_READWRITE
321
300
        )
322
301
    }
323
302
 
324
 
    def __init__(self, branch=None, repository=None):
325
 
        super(RevisionView, self).__init__()
 
303
 
 
304
    def __init__(self, branch=None):
 
305
        gtk.Notebook.__init__(self)
326
306
 
327
307
        self._revision = None
328
308
        self._branch = branch
329
 
        if branch is not None:
330
 
            self._repository = branch.repository
331
 
        else:
332
 
            self._repository = repository
333
 
        self.signature_table = None
334
309
 
335
310
        self._create_general()
336
311
        self._create_relations()
337
 
        # Disabled because testaments aren't verified yet:
338
312
        if has_seahorse:
339
313
            self._create_signature()
340
314
        self._create_file_info_view()
341
315
        self._create_bugs()
342
316
 
343
 
        self.set_current_page(PAGE_GENERAL)
344
 
        self.connect_after('switch-page', self._switch_page_cb)
 
317
        self.set_current_page(0)
345
318
        
346
319
        self._show_callback = None
347
320
        self._clicked_callback = None
397
370
 
398
371
    def _set_revision(self, revision):
399
372
        if revision is None: return
400
 
        
401
 
        self.avatarsbox.reset()
402
 
        
 
373
 
403
374
        self._revision = revision
404
375
        if revision.committer is not None:
405
376
            self.committer.set_text(revision.committer)
406
 
            self.avatarsbox.add(revision.committer, "committer")
407
377
        else:
408
378
            self.committer.set_text("")
409
 
            self.avatarsbox.hide()
410
379
        author = revision.properties.get('author', '')
411
 
        self.avatarsbox.merge(revision.get_apparent_authors(), "author")
412
380
        if author != '':
413
381
            self.author.set_text(author)
414
382
            self.author.show()
421
389
            self.timestamp.set_text(format_date(revision.timestamp,
422
390
                                                revision.timezone))
423
391
        try:
424
 
            self.branchnick.show()
425
 
            self.branchnick_label.show()
426
 
            self.branchnick.set_text(revision.properties['branch-nick'])
 
392
            self.branchnick_label.set_text(revision.properties['branch-nick'])
427
393
        except KeyError:
428
 
            self.branchnick.hide()
429
 
            self.branchnick_label.hide()
 
394
            self.branchnick_label.set_text("")
430
395
 
431
396
        self._add_parents_or_children(revision.parent_ids,
432
397
                                      self.parents_widgets,
433
398
                                      self.parents_table)
434
 
 
 
399
        
435
400
        file_info = revision.properties.get('file-info', None)
436
401
        if file_info is not None:
437
 
            try:
438
 
                file_info = bdecode(file_info.encode('UTF-8'))
439
 
            except ValueError:
440
 
                trace.note('Invalid per-file info for revision:%s, value: %r',
441
 
                           revision.revision_id, file_info)
442
 
                file_info = None
 
402
            file_info = bdecode(file_info.encode('UTF-8'))
443
403
 
444
404
        if file_info:
445
405
            if self._file_id is None:
470
430
        self._add_tags()
471
431
 
472
432
    def _update_signature(self, widget, param):
473
 
        if not has_seahorse:
474
 
            return
475
 
        if self.get_current_page() == PAGE_SIGNATURE:
476
 
            self.signature_table.set_revision(self._revision)
 
433
        self.signature_table.set_revision(self._revision)
477
434
 
478
435
    def _update_bugs(self, widget, param):
479
436
        self.bugs_page.set_revision(self._revision)
485
442
                                      self.children_widgets,
486
443
                                      self.children_table)
487
444
 
488
 
    def _switch_page_cb(self, notebook, page, page_num):
489
 
        if not has_seahorse:
490
 
            return
491
 
        if page_num == PAGE_SIGNATURE:
492
 
            self.signature_table.set_revision(self._revision)
493
 
 
494
 
 
495
 
 
496
445
    def _show_clicked_cb(self, widget, revid, parentid):
497
446
        """Callback for when the show button for a parent is clicked."""
498
447
        self._show_callback(revid, parentid)
527
476
        table.resize(max(len(revids), 1), 2)
528
477
 
529
478
        for idx, revid in enumerate(revids):
530
 
            align = Gtk.Alignment.new(0.0, 0.0, 1, 1)
 
479
            align = gtk.Alignment(0.0, 0.0)
531
480
            widgets.append(align)
532
481
            table.attach(align, 1, 2, idx, idx + 1,
533
 
                                      Gtk.AttachOptions.EXPAND | Gtk.AttachOptions.FILL, Gtk.AttachOptions.FILL)
 
482
                                      gtk.EXPAND | gtk.FILL, gtk.FILL)
534
483
            align.show()
535
484
 
536
 
            hbox = Gtk.HBox(homogeneous=False, spacing=6)
 
485
            hbox = gtk.HBox(False, spacing=6)
537
486
            align.add(hbox)
538
487
            hbox.show()
539
488
 
540
 
            image = Gtk.Image()
 
489
            image = gtk.Image()
541
490
            image.set_from_stock(
542
 
                Gtk.STOCK_FIND, Gtk.IconSize.SMALL_TOOLBAR)
 
491
                gtk.STOCK_FIND, gtk.ICON_SIZE_SMALL_TOOLBAR)
543
492
            image.show()
544
493
 
545
494
            if self._show_callback is not None:
546
 
                button = Gtk.Button()
 
495
                button = gtk.Button()
547
496
                button.add(image)
548
497
                button.connect("clicked", self._show_clicked_cb,
549
498
                               self._revision.revision_id, revid)
550
 
                hbox.pack_start(button, False, True, 0)
 
499
                hbox.pack_start(button, expand=False, fill=True)
551
500
                button.show()
552
501
 
553
 
            button = Gtk.Button()
554
 
            revid_label = Gtk.Label(label=str(revid))
555
 
            revid_label.set_ellipsize(Pango.EllipsizeMode.MIDDLE)
556
 
            revid_label.set_alignment(0.0, 0.5)
557
 
            button.add(revid_label)
 
502
            button = gtk.Button(revid)
558
503
            button.connect("clicked",
559
 
                    lambda w, r: self.set_revision(
560
 
                        self._repository.get_revision(r)), revid)
 
504
                    lambda w, r: self.set_revision(self._branch.repository.get_revision(r)), revid)
561
505
            button.set_use_underline(False)
562
 
            hbox.pack_start(button, True, True, 0)
563
 
            button.show_all()
 
506
            hbox.pack_start(button, expand=False, fill=True)
 
507
            button.show()
564
508
 
565
509
    def _create_general(self):
566
 
        vbox = Gtk.VBox(homogeneous=False, spacing=6)
 
510
        vbox = gtk.VBox(False, 6)
567
511
        vbox.set_border_width(6)
568
 
        vbox.pack_start(self._create_headers(), False, True, 0)
569
 
        vbox.pack_start(self._create_message_view(), True, True, 0)
570
 
        self.append_page(vbox, Gtk.Label(label="General"))
 
512
        vbox.pack_start(self._create_headers(), expand=False, fill=True)
 
513
        vbox.pack_start(self._create_message_view())
 
514
        self.append_page(vbox, tab_label=gtk.Label("General"))
571
515
        vbox.show()
572
516
 
573
517
    def _create_relations(self):
574
 
        vbox = Gtk.VBox(homogeneous=False, spacing=6)
 
518
        vbox = gtk.VBox(False, 6)
575
519
        vbox.set_border_width(6)
576
 
        vbox.pack_start(self._create_parents(), False, True, 0)
577
 
        vbox.pack_start(self._create_children(), False, True, 0)
578
 
        self.append_page(vbox, Gtk.Label(label="Relations"))
 
520
        vbox.pack_start(self._create_parents(), expand=False, fill=True)
 
521
        vbox.pack_start(self._create_children(), expand=False, fill=True)
 
522
        self.append_page(vbox, tab_label=gtk.Label("Relations"))
579
523
        vbox.show()
580
524
 
581
525
    def _create_signature(self):
582
 
        self.signature_table = SignatureTab(self._repository)
583
 
        self.append_page(
584
 
            self.signature_table, Gtk.Label(label='Signature'))
 
526
        self.signature_table = SignatureTab(self._branch.repository)
 
527
        self.append_page(self.signature_table, tab_label=gtk.Label('Signature'))
585
528
        self.connect_after('notify::revision', self._update_signature)
586
529
 
587
530
    def _create_headers(self):
588
 
        self.avatarsbox = AvatarsBox()
589
 
        
590
 
        self.table = Gtk.Table(rows=5, columns=2)
 
531
        self.table = gtk.Table(rows=5, columns=2)
591
532
        self.table.set_row_spacings(6)
592
533
        self.table.set_col_spacings(6)
593
534
        self.table.show()
594
 
        
595
 
        self.avatarsbox.pack_start(self.table, True, True, 0)
596
 
        self.avatarsbox.show()
597
 
 
598
 
        row = 0
599
 
 
600
 
        label = Gtk.Label()
601
 
        label.set_alignment(1.0, 0.5)
 
535
 
 
536
        align = gtk.Alignment(1.0, 0.5)
 
537
        label = gtk.Label()
602
538
        label.set_markup("<b>Revision Id:</b>")
603
 
        self.table.attach(label, 0, 1, row, row+1, Gtk.AttachOptions.FILL, Gtk.AttachOptions.FILL)
 
539
        align.add(label)
 
540
        self.table.attach(align, 0, 1, 0, 1, gtk.FILL, gtk.FILL)
 
541
        align.show()
604
542
        label.show()
605
543
 
606
 
        revision_id = Gtk.Label()
607
 
        revision_id.set_ellipsize(Pango.EllipsizeMode.MIDDLE)
608
 
        revision_id.set_alignment(0.0, 0.5)
 
544
        align = gtk.Alignment(0.0, 0.5)
 
545
        revision_id = gtk.Label()
609
546
        revision_id.set_selectable(True)
610
547
        self.connect('notify::revision', 
611
548
                lambda w, p: revision_id.set_text(self._revision.revision_id))
612
 
        self.table.attach(revision_id, 1, 2, row, row+1, Gtk.AttachOptions.EXPAND | Gtk.AttachOptions.FILL, Gtk.AttachOptions.FILL)
 
549
        align.add(revision_id)
 
550
        self.table.attach(align, 1, 2, 0, 1, gtk.EXPAND | gtk.FILL, gtk.FILL)
 
551
        align.show()
613
552
        revision_id.show()
614
553
 
615
 
        row += 1
616
 
        self.author_label = Gtk.Label()
617
 
        self.author_label.set_alignment(1.0, 0.5)
 
554
        align = gtk.Alignment(1.0, 0.5)
 
555
        self.author_label = gtk.Label()
618
556
        self.author_label.set_markup("<b>Author:</b>")
619
 
        self.table.attach(self.author_label, 0, 1, row, row+1, Gtk.AttachOptions.FILL, Gtk.AttachOptions.FILL)
 
557
        align.add(self.author_label)
 
558
        self.table.attach(align, 0, 1, 1, 2, gtk.FILL, gtk.FILL)
 
559
        align.show()
620
560
        self.author_label.show()
621
561
 
622
 
        self.author = Gtk.Label()
623
 
        self.author.set_ellipsize(Pango.EllipsizeMode.END)
624
 
        self.author.set_alignment(0.0, 0.5)
 
562
        align = gtk.Alignment(0.0, 0.5)
 
563
        self.author = gtk.Label()
625
564
        self.author.set_selectable(True)
626
 
        self.table.attach(self.author, 1, 2, row, row+1, Gtk.AttachOptions.EXPAND | Gtk.AttachOptions.FILL, Gtk.AttachOptions.FILL)
 
565
        align.add(self.author)
 
566
        self.table.attach(align, 1, 2, 1, 2, gtk.EXPAND | gtk.FILL, gtk.FILL)
 
567
        align.show()
627
568
        self.author.show()
628
569
        self.author.hide()
629
570
 
630
 
        row += 1
631
 
        label = Gtk.Label()
632
 
        label.set_alignment(1.0, 0.5)
 
571
        align = gtk.Alignment(1.0, 0.5)
 
572
        label = gtk.Label()
633
573
        label.set_markup("<b>Committer:</b>")
634
 
        self.table.attach(label, 0, 1, row, row+1, Gtk.AttachOptions.FILL, Gtk.AttachOptions.FILL)
 
574
        align.add(label)
 
575
        self.table.attach(align, 0, 1, 2, 3, gtk.FILL, gtk.FILL)
 
576
        align.show()
635
577
        label.show()
636
578
 
637
 
        self.committer = Gtk.Label()
638
 
        self.committer.set_ellipsize(Pango.EllipsizeMode.END)
639
 
        self.committer.set_alignment(0.0, 0.5)
 
579
        align = gtk.Alignment(0.0, 0.5)
 
580
        self.committer = gtk.Label()
640
581
        self.committer.set_selectable(True)
641
 
        self.table.attach(self.committer, 1, 2, row, row+1, Gtk.AttachOptions.EXPAND | Gtk.AttachOptions.FILL, Gtk.AttachOptions.FILL)
 
582
        align.add(self.committer)
 
583
        self.table.attach(align, 1, 2, 2, 3, gtk.EXPAND | gtk.FILL, gtk.FILL)
 
584
        align.show()
642
585
        self.committer.show()
643
586
 
644
 
        row += 1
645
 
        self.branchnick_label = Gtk.Label()
646
 
        self.branchnick_label.set_alignment(1.0, 0.5)
647
 
        self.branchnick_label.set_markup("<b>Branch nick:</b>")
648
 
        self.table.attach(self.branchnick_label, 0, 1, row, row+1, Gtk.AttachOptions.FILL, Gtk.AttachOptions.FILL)
 
587
        align = gtk.Alignment(0.0, 0.5)
 
588
        label = gtk.Label()
 
589
        label.set_markup("<b>Branch nick:</b>")
 
590
        align.add(label)
 
591
        self.table.attach(align, 0, 1, 3, 4, gtk.FILL, gtk.FILL)
 
592
        label.show()
 
593
        align.show()
 
594
 
 
595
        align = gtk.Alignment(0.0, 0.5)
 
596
        self.branchnick_label = gtk.Label()
 
597
        self.branchnick_label.set_selectable(True)
 
598
        align.add(self.branchnick_label)
 
599
        self.table.attach(align, 1, 2, 3, 4, gtk.EXPAND | gtk.FILL, gtk.FILL)
649
600
        self.branchnick_label.show()
650
 
 
651
 
        self.branchnick = Gtk.Label()
652
 
        self.branchnick.set_ellipsize(Pango.EllipsizeMode.MIDDLE)
653
 
        self.branchnick.set_alignment(0.0, 0.5)
654
 
        self.branchnick.set_selectable(True)
655
 
        self.table.attach(self.branchnick, 1, 2, row, row+1, Gtk.AttachOptions.EXPAND | Gtk.AttachOptions.FILL, Gtk.AttachOptions.FILL)
656
 
        self.branchnick.show()
657
 
 
658
 
        row += 1
659
 
        label = Gtk.Label()
660
 
        label.set_alignment(1.0, 0.5)
 
601
        align.show()
 
602
 
 
603
        align = gtk.Alignment(1.0, 0.5)
 
604
        label = gtk.Label()
661
605
        label.set_markup("<b>Timestamp:</b>")
662
 
        self.table.attach(label, 0, 1, row, row+1, Gtk.AttachOptions.FILL, Gtk.AttachOptions.FILL)
 
606
        align.add(label)
 
607
        self.table.attach(align, 0, 1, 4, 5, gtk.FILL, gtk.FILL)
 
608
        align.show()
663
609
        label.show()
664
610
 
665
 
        self.timestamp = Gtk.Label()
666
 
        self.timestamp.set_ellipsize(Pango.EllipsizeMode.END)
667
 
        self.timestamp.set_alignment(0.0, 0.5)
 
611
        align = gtk.Alignment(0.0, 0.5)
 
612
        self.timestamp = gtk.Label()
668
613
        self.timestamp.set_selectable(True)
669
 
        self.table.attach(self.timestamp, 1, 2, row, row+1, Gtk.AttachOptions.EXPAND | Gtk.AttachOptions.FILL, Gtk.AttachOptions.FILL)
 
614
        align.add(self.timestamp)
 
615
        self.table.attach(align, 1, 2, 4, 5, gtk.EXPAND | gtk.FILL, gtk.FILL)
 
616
        align.show()
670
617
        self.timestamp.show()
671
618
 
672
 
        row += 1
673
 
        self.tags_label = Gtk.Label()
674
 
        self.tags_label.set_alignment(1.0, 0.5)
 
619
        align = gtk.Alignment(1.0, 0.5)
 
620
        self.tags_label = gtk.Label()
675
621
        self.tags_label.set_markup("<b>Tags:</b>")
676
 
        self.table.attach(self.tags_label, 0, 1, row, row+1, Gtk.AttachOptions.FILL, Gtk.AttachOptions.FILL)
 
622
        align.add(self.tags_label)
 
623
        align.show()
 
624
        self.table.attach(align, 0, 1, 5, 6, gtk.FILL, gtk.FILL)
677
625
        self.tags_label.show()
678
626
 
679
 
        self.tags_list = Gtk.Label()
680
 
        self.tags_list.set_ellipsize(Pango.EllipsizeMode.MIDDLE)
681
 
        self.tags_list.set_alignment(0.0, 0.5)
682
 
        self.table.attach(self.tags_list, 1, 2, row, row+1, Gtk.AttachOptions.EXPAND | Gtk.AttachOptions.FILL, Gtk.AttachOptions.FILL)
 
627
        align = gtk.Alignment(0.0, 0.5)
 
628
        self.tags_list = gtk.Label()
 
629
        align.add(self.tags_list)
 
630
        self.table.attach(align, 1, 2, 5, 6, gtk.EXPAND | gtk.FILL, gtk.FILL)
 
631
        align.show()
683
632
        self.tags_list.show()
684
633
 
685
634
        self.connect('notify::revision', self._add_tags)
686
635
 
687
 
        return self.avatarsbox
 
636
        return self.table
688
637
    
689
638
    def _create_parents(self):
690
 
        hbox = Gtk.HBox(homogeneous=True, spacing=3)
 
639
        hbox = gtk.HBox(True, 3)
691
640
        
692
641
        self.parents_table = self._create_parents_or_children_table(
693
642
            "<b>Parents:</b>")
694
643
        self.parents_widgets = []
695
 
        hbox.pack_start(self.parents_table, True, True, 0)
 
644
        hbox.pack_start(self.parents_table)
696
645
 
697
646
        hbox.show()
698
647
        return hbox
699
648
 
700
649
    def _create_children(self):
701
 
        hbox = Gtk.HBox(homogeneous=True, spacing=3)
 
650
        hbox = gtk.HBox(True, 3)
702
651
        self.children_table = self._create_parents_or_children_table(
703
652
            "<b>Children:</b>")
704
653
        self.children_widgets = []
705
 
        hbox.pack_start(self.children_table, True, True, 0)
 
654
        hbox.pack_start(self.children_table)
706
655
        hbox.show()
707
656
        return hbox
708
657
        
709
658
    def _create_parents_or_children_table(self, text):
710
 
        table = Gtk.Table(rows=1, columns=2)
 
659
        table = gtk.Table(rows=1, columns=2)
711
660
        table.set_row_spacings(3)
712
661
        table.set_col_spacings(6)
713
662
        table.show()
714
663
 
715
 
        label = Gtk.Label()
 
664
        label = gtk.Label()
716
665
        label.set_markup(text)
717
 
        align = Gtk.Alignment.new(0.0, 0.5, 0, 0)
 
666
        align = gtk.Alignment(0.0, 0.5)
718
667
        align.add(label)
719
 
        table.attach(align, 0, 1, 0, 1, Gtk.AttachOptions.FILL, Gtk.AttachOptions.FILL)
 
668
        table.attach(align, 0, 1, 0, 1, gtk.FILL, gtk.FILL)
720
669
        label.show()
721
670
        align.show()
722
671
 
723
672
        return table
724
673
 
725
674
    def _create_message_view(self):
726
 
        msg_buffer = Gtk.TextBuffer()
 
675
        msg_buffer = gtk.TextBuffer()
727
676
        self.connect('notify::revision',
728
677
                lambda w, p: msg_buffer.set_text(self._revision.message))
729
 
        window = Gtk.ScrolledWindow()
730
 
        window.set_policy(Gtk.PolicyType.NEVER, Gtk.PolicyType.AUTOMATIC)
731
 
        window.set_shadow_type(Gtk.ShadowType.IN)
732
 
        tv = Gtk.TextView(buffer=msg_buffer)
 
678
        window = gtk.ScrolledWindow()
 
679
        window.set_policy(gtk.POLICY_NEVER, gtk.POLICY_AUTOMATIC)
 
680
        window.set_shadow_type(gtk.SHADOW_IN)
 
681
        tv = gtk.TextView(msg_buffer)
733
682
        tv.set_editable(False)
734
 
        tv.set_wrap_mode(Gtk.WrapMode.WORD)
 
683
        tv.set_wrap_mode(gtk.WRAP_WORD)
735
684
 
736
 
        tv.modify_font(Pango.FontDescription("Monospace"))
 
685
        tv.modify_font(pango.FontDescription("Monospace"))
737
686
        tv.show()
738
687
        window.add(tv)
739
688
        window.show()
742
691
    def _create_bugs(self):
743
692
        self.bugs_page = BugsTab()
744
693
        self.connect_after('notify::revision', self._update_bugs) 
745
 
        self.append_page(self.bugs_page, Gtk.Label(label='Bugs'))
 
694
        self.append_page(self.bugs_page, tab_label=gtk.Label('Bugs'))
746
695
 
747
696
    def _create_file_info_view(self):
748
 
        self.file_info_box = Gtk.VBox(homogeneous=False, spacing=6)
 
697
        self.file_info_box = gtk.VBox(False, 6)
749
698
        self.file_info_box.set_border_width(6)
750
 
        self.file_info_buffer = Gtk.TextBuffer()
751
 
        window = Gtk.ScrolledWindow()
752
 
        window.set_policy(Gtk.PolicyType.NEVER, Gtk.PolicyType.AUTOMATIC)
753
 
        window.set_shadow_type(Gtk.ShadowType.IN)
754
 
        tv = Gtk.TextView(buffer=self.file_info_buffer)
 
699
        self.file_info_buffer = gtk.TextBuffer()
 
700
        window = gtk.ScrolledWindow()
 
701
        window.set_policy(gtk.POLICY_NEVER, gtk.POLICY_AUTOMATIC)
 
702
        window.set_shadow_type(gtk.SHADOW_IN)
 
703
        tv = gtk.TextView(self.file_info_buffer)
755
704
        tv.set_editable(False)
756
 
        tv.set_wrap_mode(Gtk.WrapMode.WORD)
757
 
        tv.modify_font(Pango.FontDescription("Monospace"))
 
705
        tv.set_wrap_mode(gtk.WRAP_WORD)
 
706
        tv.modify_font(pango.FontDescription("Monospace"))
758
707
        tv.show()
759
708
        window.add(tv)
760
709
        window.show()
761
 
        self.file_info_box.pack_start(window, True, True, 0)
 
710
        self.file_info_box.pack_start(window)
762
711
        self.file_info_box.hide() # Only shown when there are per-file messages
763
 
        self.append_page(self.file_info_box, Gtk.Label(label='Per-file'))
 
712
        self.append_page(self.file_info_box, tab_label=gtk.Label('Per-file'))
764
713