/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-02 23:21:11 UTC
  • mto: This revision was merged to the branch mainline in revision 481.
  • Revision ID: daniel.schierbeck@gmail.com-20080402232111-a2psy91ng4m9pvnb
Fixed bug where the broken lines markers were not drawn correctly.

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