/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: 2007-02-01 15:50:40 UTC
  • Revision ID: jelmer@samba.org-20070201155040-3hq4mfbxs99kzazy
add framework for tests.

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