/b-gtk/fix-viz

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/b-gtk/fix-viz
0.1.1 by Dan Loda
First working version of xannotate.
1
# Copyright (C) 2005 Dan Loda <danloda@gmail.com>
175 by Jelmer Vernooij
Add very simple gmissing command.
2
# Copyright (C) 2007 Jelmer Vernooij <jelmer@samba.org>
0.1.1 by Dan Loda
First working version of xannotate.
3
4
# This program is free software; you can redistribute it and/or modify
5
# it under the terms of the GNU General Public License as published by
6
# the Free Software Foundation; either version 2 of the License, or
7
# (at your option) any later version.
8
9
# This program is distributed in the hope that it will be useful,
10
# but WITHOUT ANY WARRANTY; without even the implied warranty of
11
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12
# GNU General Public License for more details.
13
14
# You should have received a copy of the GNU General Public License
15
# along with this program; if not, write to the Free Software
16
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
17
18
import pygtk
19
pygtk.require("2.0")
20
import gtk
21
import pango
399.1.9 by Daniel Schierbeck
Merged with trunk.
22
import gobject
423.14.1 by Jelmer Vernooij
Add bugs tab to display bug status change metadata.
23
import subprocess
0.1.1 by Dan Loda
First working version of xannotate.
24
399.1.19 by Jelmer Vernooij
Add utility function for finding icon paths.
25
from bzrlib.plugins.gtk import icon_path
0.1.1 by Dan Loda
First working version of xannotate.
26
from bzrlib.osutils import format_date
412.1.8 by Daniel Schierbeck
Only import the bdecode function from the bzrlib.util.bencode package.
27
from bzrlib.util.bencode import bdecode
0.1.1 by Dan Loda
First working version of xannotate.
28
399.3.27 by Daniel Schierbeck
Only show Signature tab if DBus and Seahorse are installed.
29
try:
399.3.29 by Daniel Schierbeck
Renamed the crypt module to seahorse.
30
    from bzrlib.plugins.gtk import seahorse
399.3.27 by Daniel Schierbeck
Only show Signature tab if DBus and Seahorse are installed.
31
except ImportError:
399.3.29 by Daniel Schierbeck
Renamed the crypt module to seahorse.
32
    has_seahorse = False
399.3.27 by Daniel Schierbeck
Only show Signature tab if DBus and Seahorse are installed.
33
else:
399.3.29 by Daniel Schierbeck
Renamed the crypt module to seahorse.
34
    has_seahorse = True
399.3.27 by Daniel Schierbeck
Only show Signature tab if DBus and Seahorse are installed.
35
423.14.2 by Jelmer Vernooij
Move bugs tab to separate widget.
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):
399.3.1 by Daniel Schierbeck
Made the key id label disappear when the revision is not signed.
42
423.14.2 by Jelmer Vernooij
Move bugs tab to separate widget.
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)
448 by Jelmer Vernooij
Add bugs tab in branch view.
47
        self.clear()
423.14.2 by Jelmer Vernooij
Move bugs tab to separate widget.
48
49
    def clear(self):
50
        for c in self.get_children():
51
            self.remove(c)
52
        self.count = 0
448 by Jelmer Vernooij
Add bugs tab in branch view.
53
        self.hide_all() # Only shown when there are bugs
423.14.2 by Jelmer Vernooij
Move bugs tab to separate widget.
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
448 by Jelmer Vernooij
Add bugs tab in branch view.
63
        self.show_all()
423.14.2 by Jelmer Vernooij
Move bugs tab to separate widget.
64
65
399.1.15 by Jelmer Vernooij
Move signature tab to a separate class.
66
class SignatureTab(gtk.VBox):
399.3.1 by Daniel Schierbeck
Made the key id label disappear when the revision is not signed.
67
399.3.17 by Daniel Schierbeck
Moved signature handling into signature widget.
68
    def __init__(self, repository):
399.3.8 by Daniel Schierbeck
Moved crypt code into a Key class.
69
        self.key = None
399.3.23 by Daniel Schierbeck
Added comparison with revision committer.
70
        self.revision = None
399.3.17 by Daniel Schierbeck
Moved signature handling into signature widget.
71
        self.repository = repository
399.3.8 by Daniel Schierbeck
Moved crypt code into a Key class.
72
399.1.15 by Jelmer Vernooij
Move signature tab to a separate class.
73
        super(SignatureTab, self).__init__(False, 6)
399.3.5 by Daniel Schierbeck
Added support for key fingerprints.
74
        signature_box = gtk.Table(rows=3, columns=3)
399.3.21 by Daniel Schierbeck
Played a bit with the spacings.
75
        signature_box.set_col_spacing(0, 16)
76
        signature_box.set_col_spacing(1, 12)
399.3.19 by Daniel Schierbeck
Increased row spacing in signature tab.
77
        signature_box.set_row_spacings(6)
399.1.15 by Jelmer Vernooij
Move signature tab to a separate class.
78
79
        self.signature_image = gtk.Image()
80
        signature_box.attach(self.signature_image, 0, 1, 0, 1, gtk.FILL)
81
399.3.21 by Daniel Schierbeck
Played a bit with the spacings.
82
        align = gtk.Alignment(0.0, 0.1)
399.1.15 by Jelmer Vernooij
Move signature tab to a separate class.
83
        self.signature_label = gtk.Label()
399.3.2 by Daniel Schierbeck
Moved key id label to the right.
84
        align.add(self.signature_label)
85
        signature_box.attach(align, 1, 3, 0, 1, gtk.FILL)
399.1.15 by Jelmer Vernooij
Move signature tab to a separate class.
86
399.3.21 by Daniel Schierbeck
Played a bit with the spacings.
87
        align = gtk.Alignment(0.0, 0.5)
399.3.1 by Daniel Schierbeck
Made the key id label disappear when the revision is not signed.
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)
399.3.2 by Daniel Schierbeck
Moved key id label to the right.
91
        signature_box.attach(align, 1, 2, 1, 2, gtk.FILL, gtk.FILL)
399.1.15 by Jelmer Vernooij
Move signature tab to a separate class.
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)
399.3.2 by Daniel Schierbeck
Moved key id label to the right.
97
        signature_box.attach(align, 2, 3, 1, 2, gtk.EXPAND | gtk.FILL, gtk.FILL)
399.1.15 by Jelmer Vernooij
Move signature tab to a separate class.
98
399.3.21 by Daniel Schierbeck
Played a bit with the spacings.
99
        align = gtk.Alignment(0.0, 0.5)
399.3.5 by Daniel Schierbeck
Added support for key fingerprints.
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
399.3.6 by Daniel Schierbeck
Added support for key trust.
111
        align = gtk.Alignment(0.0, 0.5)
399.3.21 by Daniel Schierbeck
Played a bit with the spacings.
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)
399.3.6 by Daniel Schierbeck
Added support for key trust.
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
399.1.15 by Jelmer Vernooij
Move signature tab to a separate class.
123
        self.set_border_width(6)
124
        self.pack_start(signature_box, expand=False)
125
        self.show_all()
126
399.3.17 by Daniel Schierbeck
Moved signature handling into signature widget.
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):
399.3.30 by Daniel Schierbeck
Fixed some naming issues.
132
            crypttext = self.repository.get_signature_text(revid)
133
            self.show_signature(crypttext)
399.3.17 by Daniel Schierbeck
Moved signature handling into signature widget.
134
        else:
135
            self.show_no_signature()
136
399.1.16 by Jelmer Vernooij
Move logic showing images to the SignatureTab widget.
137
    def show_no_signature(self):
399.3.1 by Daniel Schierbeck
Made the key id label disappear when the revision is not signed.
138
        self.signature_key_id_label.hide()
399.1.16 by Jelmer Vernooij
Move logic showing images to the SignatureTab widget.
139
        self.signature_key_id.set_text("")
399.3.6 by Daniel Schierbeck
Added support for key trust.
140
399.3.5 by Daniel Schierbeck
Added support for key fingerprints.
141
        self.signature_fingerprint_label.hide()
142
        self.signature_fingerprint.set_text("")
399.3.6 by Daniel Schierbeck
Added support for key trust.
143
144
        self.signature_trust_label.hide()
145
        self.signature_trust.set_text("")
146
399.1.19 by Jelmer Vernooij
Add utility function for finding icon paths.
147
        self.signature_image.set_from_file(icon_path("sign-unknown.png"))
399.3.9 by Daniel Schierbeck
Added headings.
148
        self.signature_label.set_markup("<b>Authenticity unknown</b>\n" +
149
                                        "This revision has not been signed.")
399.1.16 by Jelmer Vernooij
Move logic showing images to the SignatureTab widget.
150
399.3.30 by Daniel Schierbeck
Fixed some naming issues.
151
    def show_signature(self, crypttext):
152
        key = seahorse.verify(crypttext)
399.3.3 by Daniel Schierbeck
Made the signature code use the Seahorse D-Bus service.
153
450.5.3 by Daniel Schierbeck
Made the signature checking code not try to discover the signature key.
154
        if key and key.is_available():
399.3.23 by Daniel Schierbeck
Added comparison with revision committer.
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:
399.3.11 by Daniel Schierbeck
Fixed error with unavailable keys.
171
            self.show_no_signature()
172
            self.signature_image.set_from_file(icon_path("sign-bad.png"))
399.3.13 by Daniel Schierbeck
Changed wording of authenticity heading.
173
            self.signature_label.set_markup("<b>Authenticity cannot be confirmed</b>\n" +
399.3.12 by Daniel Schierbeck
Fixed typo.
174
                                            "Signature key not available.")
399.3.11 by Daniel Schierbeck
Fixed error with unavailable keys.
175
            return
176
399.3.8 by Daniel Schierbeck
Moved crypt code into a Key class.
177
        trust = key.get_trust()
399.3.6 by Daniel Schierbeck
Added support for key trust.
178
399.3.29 by Daniel Schierbeck
Renamed the crypt module to seahorse.
179
        if trust <= seahorse.TRUST_NEVER:
399.3.6 by Daniel Schierbeck
Added support for key trust.
180
            trust_text = 'never trusted'
399.3.29 by Daniel Schierbeck
Renamed the crypt module to seahorse.
181
        elif trust == seahorse.TRUST_UNKNOWN:
399.3.6 by Daniel Schierbeck
Added support for key trust.
182
            trust_text = 'not trusted'
399.3.29 by Daniel Schierbeck
Renamed the crypt module to seahorse.
183
        elif trust == seahorse.TRUST_MARGINAL:
399.3.6 by Daniel Schierbeck
Added support for key trust.
184
            trust_text = 'marginally trusted'
399.3.29 by Daniel Schierbeck
Renamed the crypt module to seahorse.
185
        elif trust == seahorse.TRUST_FULL:
399.3.6 by Daniel Schierbeck
Added support for key trust.
186
            trust_text = 'fully trusted'
399.3.29 by Daniel Schierbeck
Renamed the crypt module to seahorse.
187
        elif trust == seahorse.TRUST_ULTIMATE:
399.3.6 by Daniel Schierbeck
Added support for key trust.
188
            trust_text = 'ultimately trusted'
399.3.5 by Daniel Schierbeck
Added support for key fingerprints.
189
399.3.1 by Daniel Schierbeck
Made the key id label disappear when the revision is not signed.
190
        self.signature_key_id_label.show()
399.3.8 by Daniel Schierbeck
Moved crypt code into a Key class.
191
        self.signature_key_id.set_text(key.get_id())
399.3.5 by Daniel Schierbeck
Added support for key fingerprints.
192
399.3.15 by Daniel Schierbeck
Made the fingerprint label read N/A when no fingerprint is available.
193
        fingerprint = key.get_fingerprint()
194
        if fingerprint == "":
399.3.18 by Daniel Schierbeck
Made empty fingerprint text grey.
195
            fingerprint = '<span foreground="dim grey">N/A</span>'
399.3.15 by Daniel Schierbeck
Made the fingerprint label read N/A when no fingerprint is available.
196
399.3.5 by Daniel Schierbeck
Added support for key fingerprints.
197
        self.signature_fingerprint_label.show()
399.3.18 by Daniel Schierbeck
Made empty fingerprint text grey.
198
        self.signature_fingerprint.set_markup(fingerprint)
399.3.3 by Daniel Schierbeck
Made the signature code use the Seahorse D-Bus service.
199
399.3.6 by Daniel Schierbeck
Added support for key trust.
200
        self.signature_trust_label.show()
201
        self.signature_trust.set_text('This key is ' + trust_text)
399.3.17 by Daniel Schierbeck
Moved signature handling into signature widget.
202
399.1.15 by Jelmer Vernooij
Move signature tab to a separate class.
203
330.3.1 by Daniel Schierbeck
Renamed logview 'revisionview'.
204
class RevisionView(gtk.Notebook):
0.1.1 by Dan Loda
First working version of xannotate.
205
    """ Custom widget for commit log details.
206
207
    A variety of bzr tools may need to implement such a thing. This is a
208
    start.
209
    """
210
412.1.1 by Daniel Schierbeck
Added branch and revision properties to the revisionview widget.
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',
412.1.2 by Daniel Schierbeck
Moved retrieval of tags into the revisionview itself.
223
            gobject.PARAM_READWRITE
412.1.7 by Daniel Schierbeck
Added file-id property to the revisionview.
224
        ),
225
412.1.13 by Daniel Schierbeck
Re-added support for displaying the children of a revision.
226
        'children': (
227
            gobject.TYPE_PYOBJECT,
228
            'Children',
229
            'Child revisions',
230
            gobject.PARAM_READWRITE
231
        ),
232
412.1.7 by Daniel Schierbeck
Added file-id property to the revisionview.
233
        'file-id': (
234
            gobject.TYPE_PYOBJECT,
235
            'File Id',
236
            'The file id',
237
            gobject.PARAM_READWRITE
412.1.1 by Daniel Schierbeck
Added branch and revision properties to the revisionview widget.
238
        )
239
    }
240
241
412.1.2 by Daniel Schierbeck
Moved retrieval of tags into the revisionview itself.
242
    def __init__(self, branch=None):
324.2.1 by Daniel Schierbeck
Turned the logview into a notebook.
243
        gtk.Notebook.__init__(self)
324.2.4 by Daniel Schierbeck
Added 'Changes' page to logview.
244
399.3.17 by Daniel Schierbeck
Moved signature handling into signature widget.
245
        self._revision = None
246
        self._branch = branch
247
324.2.1 by Daniel Schierbeck
Turned the logview into a notebook.
248
        self._create_general()
249
        self._create_relations()
399.3.29 by Daniel Schierbeck
Renamed the crypt module to seahorse.
250
        if has_seahorse:
399.3.27 by Daniel Schierbeck
Only show Signature tab if DBus and Seahorse are installed.
251
            self._create_signature()
278.1.45 by John Arbash Meinel
Switch to a new tab for per-file messages.
252
        self._create_file_info_view()
423.14.1 by Jelmer Vernooij
Add bugs tab to display bug status change metadata.
253
        self._create_bugs()
324.2.9 by Daniel Schierbeck
Made 'General' the default page of the logview.
254
255
        self.set_current_page(0)
324.2.4 by Daniel Schierbeck
Added 'Changes' page to logview.
256
        
147 by Jelmer Vernooij
Remove a bunch of duplicate functionality.
257
        self._show_callback = None
258
        self._clicked_callback = None
0.1.1 by Dan Loda
First working version of xannotate.
259
412.1.9 by Daniel Schierbeck
Removed the use of RevisionView.set_go_callback().
260
        self._revision = None
324.2.4 by Daniel Schierbeck
Added 'Changes' page to logview.
261
        self._branch = branch
262
423.7.4 by Daniel Schierbeck
Made revisionview and branchview update when a tag is added.
263
        self.update_tags()
412.1.2 by Daniel Schierbeck
Moved retrieval of tags into the revisionview itself.
264
278.1.3 by John Arbash Meinel
Have the ability to tell the log view that we only care about a specific file_id.
265
        self.set_file_id(None)
0.1.1 by Dan Loda
First working version of xannotate.
266
412.1.1 by Daniel Schierbeck
Added branch and revision properties to the revisionview widget.
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
412.1.13 by Daniel Schierbeck
Re-added support for displaying the children of a revision.
272
        elif property.name == 'children':
273
            return self._children
412.1.7 by Daniel Schierbeck
Added file-id property to the revisionview.
274
        elif property.name == 'file-id':
275
            return self._file_id
412.1.1 by Daniel Schierbeck
Added branch and revision properties to the revisionview widget.
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)
412.1.13 by Daniel Schierbeck
Re-added support for displaying the children of a revision.
284
        elif property.name == 'children':
285
            self.set_children(value)
412.1.7 by Daniel Schierbeck
Added file-id property to the revisionview.
286
        elif property.name == 'file-id':
287
            self._file_id = value
412.1.1 by Daniel Schierbeck
Added branch and revision properties to the revisionview widget.
288
        else:
289
            raise AttributeError, 'unknown property %s' % property.name
290
147 by Jelmer Vernooij
Remove a bunch of duplicate functionality.
291
    def set_show_callback(self, callback):
292
        self._show_callback = callback
293
278.1.3 by John Arbash Meinel
Have the ability to tell the log view that we only care about a specific file_id.
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
        """
412.1.7 by Daniel Schierbeck
Added file-id property to the revisionview.
300
        self.set_property('file-id', file_id)
278.1.3 by John Arbash Meinel
Have the ability to tell the log view that we only care about a specific file_id.
301
412.1.13 by Daniel Schierbeck
Re-added support for displaying the children of a revision.
302
    def set_revision(self, revision):
412.1.9 by Daniel Schierbeck
Removed the use of RevisionView.set_go_callback().
303
        if revision != self._revision:
304
            self.set_property('revision', revision)
305
306
    def get_revision(self):
307
        return self.get_property('revision')
412.1.1 by Daniel Schierbeck
Added branch and revision properties to the revisionview widget.
308
412.1.15 by Daniel Schierbeck
Removed redundant method argument.
309
    def _set_revision(self, revision):
412.1.1 by Daniel Schierbeck
Added branch and revision properties to the revisionview widget.
310
        if revision is None: return
311
147 by Jelmer Vernooij
Remove a bunch of duplicate functionality.
312
        self._revision = revision
192 by Jelmer Vernooij
Allow committer to be None.
313
        if revision.committer is not None:
314
            self.committer.set_text(revision.committer)
315
        else:
316
            self.committer.set_text("")
259 by Aaron Bentley
Add author support to gannotate and log viewer
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
197 by Jelmer Vernooij
Fix some warnings when displaying ghost revisions. Reported by John.
326
        if revision.timestamp is not None:
327
            self.timestamp.set_text(format_date(revision.timestamp,
328
                                                revision.timezone))
147 by Jelmer Vernooij
Remove a bunch of duplicate functionality.
329
        try:
330
            self.branchnick_label.set_text(revision.properties['branch-nick'])
331
        except KeyError:
332
            self.branchnick_label.set_text("")
333
256.2.23 by Gary van der Merwe
Show Children
334
        self._add_parents_or_children(revision.parent_ids,
335
                                      self.parents_widgets,
336
                                      self.parents_table)
337
        
278.1.3 by John Arbash Meinel
Have the ability to tell the log view that we only care about a specific file_id.
338
        file_info = revision.properties.get('file-info', None)
278.1.2 by John Arbash Meinel
Add an extra box that pops up when we have per-file information.
339
        if file_info is not None:
412.1.8 by Daniel Schierbeck
Only import the bdecode function from the bzrlib.util.bencode package.
340
            file_info = bdecode(file_info.encode('UTF-8'))
278.1.2 by John Arbash Meinel
Add an extra box that pops up when we have per-file information.
341
342
        if file_info:
278.1.3 by John Arbash Meinel
Have the ability to tell the log view that we only care about a specific file_id.
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()
278.1.2 by John Arbash Meinel
Add an extra box that pops up when we have per-file information.
359
        else:
360
            self.file_info_box.hide()
361
423.14.3 by Jelmer Vernooij
Always show bugs tab.
362
        self.bugs_table.clear()
423.14.1 by Jelmer Vernooij
Add bugs tab to display bug status change metadata.
363
        bugs_text = revision.properties.get('bugs', None)
364
        if bugs_text:
365
            for bugline in bugs_text.splitlines():
366
                (url, status) = bugline.split(" ")
423.14.2 by Jelmer Vernooij
Move bugs tab to separate widget.
367
                self.bugs_table.add_bug(url, status)
423.14.1 by Jelmer Vernooij
Add bugs tab to display bug status change metadata.
368
423.7.4 by Daniel Schierbeck
Made revisionview and branchview update when a tag is added.
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
399.1.13 by Daniel Schierbeck
Merged with mainline.
377
    def _update_signature(self, widget, param):
399.3.17 by Daniel Schierbeck
Moved signature handling into signature widget.
378
        self.signature_table.set_revision(self._revision)
399.1.13 by Daniel Schierbeck
Merged with mainline.
379
412.1.13 by Daniel Schierbeck
Re-added support for displaying the children of a revision.
380
    def set_children(self, children):
381
        self._add_parents_or_children(children,
382
                                      self.children_widgets,
383
                                      self.children_table)
384
147 by Jelmer Vernooij
Remove a bunch of duplicate functionality.
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
412.1.4 by Daniel Schierbeck
Made tag list smarter.
392
    def _add_tags(self, *args):
399.1.13 by Daniel Schierbeck
Merged with mainline.
393
        if self._revision is None:
394
            return
423.7.4 by Daniel Schierbeck
Made revisionview and branchview update when a tag is added.
395
412.1.4 by Daniel Schierbeck
Made tag list smarter.
396
        if self._tagdict.has_key(self._revision.revision_id):
397
            tags = self._tagdict[self._revision.revision_id]
398
        else:
399
            tags = []
400
            
241 by Jelmer Vernooij
Show tags in bzr viz.
401
        if tags == []:
402
            self.tags_list.hide()
403
            self.tags_label.hide()
404
            return
405
423.3.1 by Daniel Schierbeck
Made the tag list be a comma-separated line instead of a vertically stacked box.
406
        self.tags_list.set_text(", ".join(tags))
407
241 by Jelmer Vernooij
Show tags in bzr viz.
408
        self.tags_list.show_all()
409
        self.tags_label.show_all()
410
        
256.2.23 by Gary van der Merwe
Show Children
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)
147 by Jelmer Vernooij
Remove a bunch of duplicate functionality.
417
256.2.23 by Gary van der Merwe
Show Children
418
        for idx, revid in enumerate(revids):
147 by Jelmer Vernooij
Remove a bunch of duplicate functionality.
419
            align = gtk.Alignment(0.0, 0.0)
256.2.23 by Gary van der Merwe
Show Children
420
            widgets.append(align)
421
            table.attach(align, 1, 2, idx, idx + 1,
147 by Jelmer Vernooij
Remove a bunch of duplicate functionality.
422
                                      gtk.EXPAND | gtk.FILL, gtk.FILL)
0.1.1 by Dan Loda
First working version of xannotate.
423
            align.show()
147 by Jelmer Vernooij
Remove a bunch of duplicate functionality.
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
148 by Jelmer Vernooij
Clean up interface a bit: don't show diff button when no diff can be accessed, use label instead of button when there is no callback set.
434
            if self._show_callback is not None:
435
                button = gtk.Button()
436
                button.add(image)
437
                button.connect("clicked", self._show_clicked_cb,
256.2.23 by Gary van der Merwe
Show Children
438
                               self._revision.revision_id, revid)
148 by Jelmer Vernooij
Clean up interface a bit: don't show diff button when no diff can be accessed, use label instead of button when there is no callback set.
439
                hbox.pack_start(button, expand=False, fill=True)
440
                button.show()
147 by Jelmer Vernooij
Remove a bunch of duplicate functionality.
441
412.1.9 by Daniel Schierbeck
Removed the use of RevisionView.set_go_callback().
442
            button = gtk.Button(revid)
443
            button.connect("clicked",
412.1.14 by Daniel Schierbeck
Fixed bug in the way the child buttons worked.
444
                    lambda w, r: self.set_revision(self._branch.repository.get_revision(r)), revid)
147 by Jelmer Vernooij
Remove a bunch of duplicate functionality.
445
            button.set_use_underline(False)
446
            hbox.pack_start(button, expand=False, fill=True)
447
            button.show()
0.1.1 by Dan Loda
First working version of xannotate.
448
324.2.1 by Daniel Schierbeck
Turned the logview into a notebook.
449
    def _create_general(self):
0.1.1 by Dan Loda
First working version of xannotate.
450
        vbox = gtk.VBox(False, 6)
451
        vbox.set_border_width(6)
452
        vbox.pack_start(self._create_headers(), expand=False, fill=True)
324.2.1 by Daniel Schierbeck
Turned the logview into a notebook.
453
        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)
291 by Jelmer Vernooij
Put children widget on a new line.
460
        vbox.pack_start(self._create_parents(), expand=False, fill=True)
412.1.13 by Daniel Schierbeck
Re-added support for displaying the children of a revision.
461
        vbox.pack_start(self._create_children(), expand=False, fill=True)
324.2.1 by Daniel Schierbeck
Turned the logview into a notebook.
462
        self.append_page(vbox, tab_label=gtk.Label("Relations"))
0.1.1 by Dan Loda
First working version of xannotate.
463
        vbox.show()
324.2.4 by Daniel Schierbeck
Added 'Changes' page to logview.
464
399.1.10 by Daniel Schierbeck
Improved implementation of the Signature page.
465
    def _create_signature(self):
399.3.17 by Daniel Schierbeck
Moved signature handling into signature widget.
466
        self.signature_table = SignatureTab(self._branch.repository)
399.1.15 by Jelmer Vernooij
Move signature tab to a separate class.
467
        self.append_page(self.signature_table, tab_label=gtk.Label('Signature'))
399.1.10 by Daniel Schierbeck
Improved implementation of the Signature page.
468
        self.connect_after('notify::revision', self._update_signature)
469
0.1.1 by Dan Loda
First working version of xannotate.
470
    def _create_headers(self):
241 by Jelmer Vernooij
Show tags in bzr viz.
471
        self.table = gtk.Table(rows=5, columns=2)
0.1.1 by Dan Loda
First working version of xannotate.
472
        self.table.set_row_spacings(6)
473
        self.table.set_col_spacings(6)
474
        self.table.show()
147 by Jelmer Vernooij
Remove a bunch of duplicate functionality.
475
476
        align = gtk.Alignment(1.0, 0.5)
477
        label = gtk.Label()
478
        label.set_markup("<b>Revision Id:</b>")
479
        align.add(label)
480
        self.table.attach(align, 0, 1, 0, 1, gtk.FILL, gtk.FILL)
481
        align.show()
482
        label.show()
483
484
        align = gtk.Alignment(0.0, 0.5)
412.1.5 by Daniel Schierbeck
Made the revision id label use signals when updating.
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)
147 by Jelmer Vernooij
Remove a bunch of duplicate functionality.
490
        self.table.attach(align, 1, 2, 0, 1, gtk.EXPAND | gtk.FILL, gtk.FILL)
491
        align.show()
412.1.5 by Daniel Schierbeck
Made the revision id label use signals when updating.
492
        revision_id.show()
147 by Jelmer Vernooij
Remove a bunch of duplicate functionality.
493
0.1.1 by Dan Loda
First working version of xannotate.
494
        align = gtk.Alignment(1.0, 0.5)
259 by Aaron Bentley
Add author support to gannotate and log viewer
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)
0.1.1 by Dan Loda
First working version of xannotate.
512
        label = gtk.Label()
513
        label.set_markup("<b>Committer:</b>")
514
        align.add(label)
259 by Aaron Bentley
Add author support to gannotate and log viewer
515
        self.table.attach(align, 0, 1, 2, 3, gtk.FILL, gtk.FILL)
0.1.1 by Dan Loda
First working version of xannotate.
516
        align.show()
517
        label.show()
518
519
        align = gtk.Alignment(0.0, 0.5)
520
        self.committer = gtk.Label()
521
        self.committer.set_selectable(True)
522
        align.add(self.committer)
259 by Aaron Bentley
Add author support to gannotate and log viewer
523
        self.table.attach(align, 1, 2, 2, 3, gtk.EXPAND | gtk.FILL, gtk.FILL)
0.1.1 by Dan Loda
First working version of xannotate.
524
        align.show()
525
        self.committer.show()
526
147 by Jelmer Vernooij
Remove a bunch of duplicate functionality.
527
        align = gtk.Alignment(0.0, 0.5)
528
        label = gtk.Label()
529
        label.set_markup("<b>Branch nick:</b>")
530
        align.add(label)
259 by Aaron Bentley
Add author support to gannotate and log viewer
531
        self.table.attach(align, 0, 1, 3, 4, gtk.FILL, gtk.FILL)
147 by Jelmer Vernooij
Remove a bunch of duplicate functionality.
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)
259 by Aaron Bentley
Add author support to gannotate and log viewer
539
        self.table.attach(align, 1, 2, 3, 4, gtk.EXPAND | gtk.FILL, gtk.FILL)
147 by Jelmer Vernooij
Remove a bunch of duplicate functionality.
540
        self.branchnick_label.show()
541
        align.show()
542
0.1.1 by Dan Loda
First working version of xannotate.
543
        align = gtk.Alignment(1.0, 0.5)
544
        label = gtk.Label()
545
        label.set_markup("<b>Timestamp:</b>")
546
        align.add(label)
259 by Aaron Bentley
Add author support to gannotate and log viewer
547
        self.table.attach(align, 0, 1, 4, 5, gtk.FILL, gtk.FILL)
0.1.1 by Dan Loda
First working version of xannotate.
548
        align.show()
549
        label.show()
550
551
        align = gtk.Alignment(0.0, 0.5)
552
        self.timestamp = gtk.Label()
553
        self.timestamp.set_selectable(True)
554
        align.add(self.timestamp)
259 by Aaron Bentley
Add author support to gannotate and log viewer
555
        self.table.attach(align, 1, 2, 4, 5, gtk.EXPAND | gtk.FILL, gtk.FILL)
0.1.1 by Dan Loda
First working version of xannotate.
556
        align.show()
557
        self.timestamp.show()
558
241 by Jelmer Vernooij
Show tags in bzr viz.
559
        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)
563
        align.show()
261 by Aaron Bentley
Fix tags formatting
564
        self.table.attach(align, 0, 1, 5, 6, gtk.FILL, gtk.FILL)
241 by Jelmer Vernooij
Show tags in bzr viz.
565
        self.tags_label.show()
566
567
        align = gtk.Alignment(0.0, 0.5)
423.3.1 by Daniel Schierbeck
Made the tag list be a comma-separated line instead of a vertically stacked box.
568
        self.tags_list = gtk.Label()
241 by Jelmer Vernooij
Show tags in bzr viz.
569
        align.add(self.tags_list)
261 by Aaron Bentley
Fix tags formatting
570
        self.table.attach(align, 1, 2, 5, 6, gtk.EXPAND | gtk.FILL, gtk.FILL)
241 by Jelmer Vernooij
Show tags in bzr viz.
571
        align.show()
572
        self.tags_list.show()
573
412.1.4 by Daniel Schierbeck
Made tag list smarter.
574
        self.connect('notify::revision', self._add_tags)
575
0.1.1 by Dan Loda
First working version of xannotate.
576
        return self.table
256.2.23 by Gary van der Merwe
Show Children
577
    
291 by Jelmer Vernooij
Put children widget on a new line.
578
    def _create_parents(self):
579
        hbox = gtk.HBox(True, 3)
256.2.23 by Gary van der Merwe
Show Children
580
        
581
        self.parents_table = self._create_parents_or_children_table(
582
            "<b>Parents:</b>")
147 by Jelmer Vernooij
Remove a bunch of duplicate functionality.
583
        self.parents_widgets = []
256.2.23 by Gary van der Merwe
Show Children
584
        hbox.pack_start(self.parents_table)
291 by Jelmer Vernooij
Put children widget on a new line.
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)
256.2.23 by Gary van der Merwe
Show Children
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()
147 by Jelmer Vernooij
Remove a bunch of duplicate functionality.
603
604
        label = gtk.Label()
256.2.23 by Gary van der Merwe
Show Children
605
        label.set_markup(text)
147 by Jelmer Vernooij
Remove a bunch of duplicate functionality.
606
        align = gtk.Alignment(0.0, 0.5)
607
        align.add(label)
256.2.23 by Gary van der Merwe
Show Children
608
        table.attach(align, 0, 1, 0, 1, gtk.FILL, gtk.FILL)
147 by Jelmer Vernooij
Remove a bunch of duplicate functionality.
609
        label.show()
610
        align.show()
611
256.2.23 by Gary van der Merwe
Show Children
612
        return table
147 by Jelmer Vernooij
Remove a bunch of duplicate functionality.
613
0.1.1 by Dan Loda
First working version of xannotate.
614
    def _create_message_view(self):
412.1.6 by Daniel Schierbeck
Made the message buffer use signals when updating.
615
        msg_buffer = gtk.TextBuffer()
616
        self.connect('notify::revision',
617
                lambda w, p: msg_buffer.set_text(self._revision.message))
324.2.2 by Daniel Schierbeck
Surrounded the commit message textview with a scrolled window and added a shadow.
618
        window = gtk.ScrolledWindow()
619
        window.set_policy(gtk.POLICY_NEVER, gtk.POLICY_AUTOMATIC)
620
        window.set_shadow_type(gtk.SHADOW_IN)
412.1.6 by Daniel Schierbeck
Made the message buffer use signals when updating.
621
        tv = gtk.TextView(msg_buffer)
0.1.1 by Dan Loda
First working version of xannotate.
622
        tv.set_editable(False)
623
        tv.set_wrap_mode(gtk.WRAP_WORD)
399.1.13 by Daniel Schierbeck
Merged with mainline.
624
0.1.1 by Dan Loda
First working version of xannotate.
625
        tv.modify_font(pango.FontDescription("Monospace"))
626
        tv.show()
324.2.2 by Daniel Schierbeck
Surrounded the commit message textview with a scrolled window and added a shadow.
627
        window.add(tv)
628
        window.show()
629
        return window
0.1.1 by Dan Loda
First working version of xannotate.
630
423.14.1 by Jelmer Vernooij
Add bugs tab to display bug status change metadata.
631
    def _create_bugs(self):
423.14.2 by Jelmer Vernooij
Move bugs tab to separate widget.
632
        self.bugs_table = BugsTab()
423.14.1 by Jelmer Vernooij
Add bugs tab to display bug status change metadata.
633
        self.append_page(self.bugs_table, tab_label=gtk.Label('Bugs'))
634
278.1.2 by John Arbash Meinel
Add an extra box that pops up when we have per-file information.
635
    def _create_file_info_view(self):
278.1.45 by John Arbash Meinel
Switch to a new tab for per-file messages.
636
        self.file_info_box = gtk.VBox(False, 6)
637
        self.file_info_box.set_border_width(6)
278.1.2 by John Arbash Meinel
Add an extra box that pops up when we have per-file information.
638
        self.file_info_buffer = gtk.TextBuffer()
278.1.44 by John Arbash Meinel
Merge in trunk, and update logview per-file commit messages.
639
        window = gtk.ScrolledWindow()
640
        window.set_policy(gtk.POLICY_NEVER, gtk.POLICY_AUTOMATIC)
641
        window.set_shadow_type(gtk.SHADOW_IN)
278.1.2 by John Arbash Meinel
Add an extra box that pops up when we have per-file information.
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()
278.1.44 by John Arbash Meinel
Merge in trunk, and update logview per-file commit messages.
647
        window.add(tv)
648
        window.show()
649
        self.file_info_box.pack_start(window)
278.1.2 by John Arbash Meinel
Add an extra box that pops up when we have per-file information.
650
        self.file_info_box.hide() # Only shown when there are per-file messages
278.1.45 by John Arbash Meinel
Switch to a new tab for per-file messages.
651
        self.append_page(self.file_info_box, tab_label=gtk.Label('Per-file'))
278.1.2 by John Arbash Meinel
Add an extra box that pops up when we have per-file information.
652