/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: Jelmer Vernooij
  • Date: 2008-06-29 18:31:29 UTC
  • mto: This revision was merged to the branch mainline in revision 518.
  • Revision ID: jelmer@samba.org-20080629183129-syqvz3xm5gqagzsx
Fix use of smart_add.

Show diffs side-by-side

added added

removed removed

Lines of Context:
18
18
import pygtk
19
19
pygtk.require("2.0")
20
20
import gtk
 
21
import pango
21
22
import gobject
22
 
import pango
23
 
from gpg import GPGSubprocess
 
23
import webbrowser
24
24
 
 
25
from bzrlib.plugins.gtk import icon_path
25
26
from bzrlib.osutils import format_date
26
27
from bzrlib.util.bencode import bdecode
27
28
 
28
 
gpg = GPGSubprocess()
 
29
try:
 
30
    from bzrlib.plugins.gtk import seahorse
 
31
except ImportError:
 
32
    has_seahorse = False
 
33
else:
 
34
    has_seahorse = True
 
35
 
 
36
PAGE_GENERAL = 0
 
37
PAGE_RELATIONS = 1
 
38
PAGE_SIGNATURE = 2
 
39
PAGE_BUGS = 3
 
40
 
 
41
 
 
42
def _open_link(widget, uri):
 
43
    for cmd in ['sensible-browser', 'xdg-open']:
 
44
        if webbrowser._iscommand(cmd):
 
45
            webbrowser._tryorder.insert(0, '%s "%%s"' % cmd)
 
46
    webbrowser.open(uri)
 
47
 
 
48
gtk.link_button_set_uri_hook(_open_link)
 
49
 
 
50
class BugsTab(gtk.VBox):
 
51
 
 
52
    def __init__(self):
 
53
        super(BugsTab, self).__init__(False, 6)
 
54
    
 
55
        table = gtk.Table(rows=2, columns=2)
 
56
 
 
57
        table.set_row_spacings(6)
 
58
        table.set_col_spacing(0, 16)
 
59
 
 
60
        image = gtk.Image()
 
61
        image.set_from_file(icon_path("bug.png"))
 
62
        table.attach(image, 0, 1, 0, 1, gtk.FILL)
 
63
 
 
64
        align = gtk.Alignment(0.0, 0.1)
 
65
        self.label = gtk.Label()
 
66
        align.add(self.label)
 
67
        table.attach(align, 1, 2, 0, 1, gtk.FILL)
 
68
 
 
69
        treeview = self.construct_treeview()
 
70
        table.attach(treeview, 1, 2, 1, 2, gtk.FILL | gtk.EXPAND)
 
71
 
 
72
        self.set_border_width(6)
 
73
        self.pack_start(table, expand=False)
 
74
 
 
75
        self.clear()
 
76
        self.show_all()
 
77
 
 
78
    def set_revision(self, revision):
 
79
        if revision is None:
 
80
            return
 
81
 
 
82
        self.clear()
 
83
        bugs_text = revision.properties.get('bugs', '')
 
84
        for bugline in bugs_text.splitlines():
 
85
                (url, status) = bugline.split(" ")
 
86
                if status == "fixed":
 
87
                    self.add_bug(url, status)
 
88
        
 
89
        if self.num_bugs == 0:
 
90
            return
 
91
        elif self.num_bugs == 1:
 
92
            label = "bug"
 
93
        else:
 
94
            label = "bugs"
 
95
 
 
96
        self.label.set_markup("<b>Bugs fixed</b>\n" +
 
97
                              "This revision claims to fix " +
 
98
                              "%d %s." % (self.num_bugs, label))
 
99
 
 
100
    def construct_treeview(self):
 
101
        self.bugs = gtk.ListStore(gobject.TYPE_STRING, gobject.TYPE_STRING)
 
102
        self.treeview = gtk.TreeView(self.bugs)
 
103
        self.treeview.set_headers_visible(False)
 
104
 
 
105
        uri_column = gtk.TreeViewColumn('Bug URI', gtk.CellRendererText(), text=0)
 
106
        self.treeview.append_column(uri_column)
 
107
 
 
108
        self.treeview.connect('row-activated', self.on_row_activated)
 
109
 
 
110
        win = gtk.ScrolledWindow()
 
111
        win.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
 
112
        win.set_shadow_type(gtk.SHADOW_IN)
 
113
        win.add(self.treeview)
 
114
 
 
115
        return win
 
116
 
 
117
    def clear(self):
 
118
        self.num_bugs = 0
 
119
        self.bugs.clear()
 
120
        self.set_sensitive(False)
 
121
        self.label.set_markup("<b>No bugs fixed</b>\n" +
 
122
                              "This revision does not claim to fix any bugs.")
 
123
 
 
124
    def add_bug(self, url, status):
 
125
        self.num_bugs += 1
 
126
        self.bugs.append([url, status])
 
127
        self.set_sensitive(True)
 
128
 
 
129
    def get_num_bugs(self):
 
130
        return self.num_bugs
 
131
 
 
132
    def on_row_activated(self, treeview, path, column):
 
133
        uri = self.bugs.get_value(self.bugs.get_iter(path), 0)
 
134
        _open_link(self, uri)
 
135
 
 
136
 
 
137
class SignatureTab(gtk.VBox):
 
138
 
 
139
    def __init__(self, repository):
 
140
        self.key = None
 
141
        self.revision = None
 
142
        self.repository = repository
 
143
 
 
144
        super(SignatureTab, self).__init__(False, 6)
 
145
        signature_box = gtk.Table(rows=3, columns=3)
 
146
        signature_box.set_col_spacing(0, 16)
 
147
        signature_box.set_col_spacing(1, 12)
 
148
        signature_box.set_row_spacings(6)
 
149
 
 
150
        self.signature_image = gtk.Image()
 
151
        signature_box.attach(self.signature_image, 0, 1, 0, 1, gtk.FILL)
 
152
 
 
153
        align = gtk.Alignment(0.0, 0.1)
 
154
        self.signature_label = gtk.Label()
 
155
        align.add(self.signature_label)
 
156
        signature_box.attach(align, 1, 3, 0, 1, gtk.FILL)
 
157
 
 
158
        align = gtk.Alignment(0.0, 0.5)
 
159
        self.signature_key_id_label = gtk.Label()
 
160
        self.signature_key_id_label.set_markup("<b>Key Id:</b>")
 
161
        align.add(self.signature_key_id_label)
 
162
        signature_box.attach(align, 1, 2, 1, 2, gtk.FILL, gtk.FILL)
 
163
 
 
164
        align = gtk.Alignment(0.0, 0.5)
 
165
        self.signature_key_id = gtk.Label()
 
166
        self.signature_key_id.set_selectable(True)
 
167
        align.add(self.signature_key_id)
 
168
        signature_box.attach(align, 2, 3, 1, 2, gtk.EXPAND | gtk.FILL, gtk.FILL)
 
169
 
 
170
        align = gtk.Alignment(0.0, 0.5)
 
171
        self.signature_fingerprint_label = gtk.Label()
 
172
        self.signature_fingerprint_label.set_markup("<b>Fingerprint:</b>")
 
173
        align.add(self.signature_fingerprint_label)
 
174
        signature_box.attach(align, 1, 2, 2, 3, gtk.FILL, gtk.FILL)
 
175
 
 
176
        align = gtk.Alignment(0.0, 0.5)
 
177
        self.signature_fingerprint = gtk.Label()
 
178
        self.signature_fingerprint.set_selectable(True)
 
179
        align.add(self.signature_fingerprint)
 
180
        signature_box.attach(align, 2, 3, 2, 3, gtk.EXPAND | gtk.FILL, gtk.FILL)
 
181
 
 
182
        align = gtk.Alignment(0.0, 0.5)
 
183
        self.signature_trust_label = gtk.Label()
 
184
        self.signature_trust_label.set_markup("<b>Trust:</b>")
 
185
        align.add(self.signature_trust_label)
 
186
        signature_box.attach(align, 1, 2, 3, 4, gtk.FILL, gtk.FILL)
 
187
 
 
188
        align = gtk.Alignment(0.0, 0.5)
 
189
        self.signature_trust = gtk.Label()
 
190
        self.signature_trust.set_selectable(True)
 
191
        align.add(self.signature_trust)
 
192
        signature_box.attach(align, 2, 3, 3, 4, gtk.EXPAND | gtk.FILL, gtk.FILL)
 
193
 
 
194
        self.set_border_width(6)
 
195
        self.pack_start(signature_box, expand=False)
 
196
        self.show_all()
 
197
 
 
198
    def set_revision(self, revision):
 
199
        self.revision = revision
 
200
        revid = revision.revision_id
 
201
 
 
202
        if self.repository.has_signature_for_revision_id(revid):
 
203
            crypttext = self.repository.get_signature_text(revid)
 
204
            self.show_signature(crypttext)
 
205
        else:
 
206
            self.show_no_signature()
 
207
 
 
208
    def show_no_signature(self):
 
209
        self.signature_key_id_label.hide()
 
210
        self.signature_key_id.set_text("")
 
211
 
 
212
        self.signature_fingerprint_label.hide()
 
213
        self.signature_fingerprint.set_text("")
 
214
 
 
215
        self.signature_trust_label.hide()
 
216
        self.signature_trust.set_text("")
 
217
 
 
218
        self.signature_image.set_from_file(icon_path("sign-unknown.png"))
 
219
        self.signature_label.set_markup("<b>Authenticity unknown</b>\n" +
 
220
                                        "This revision has not been signed.")
 
221
 
 
222
    def show_signature(self, crypttext):
 
223
        key = seahorse.verify(crypttext)
 
224
 
 
225
        if key and key.is_available():
 
226
            if key.is_trusted():
 
227
                if key.get_display_name() == self.revision.committer:
 
228
                    self.signature_image.set_from_file(icon_path("sign-ok.png"))
 
229
                    self.signature_label.set_markup("<b>Authenticity confirmed</b>\n" +
 
230
                                                    "This revision has been signed with " +
 
231
                                                    "a trusted key.")
 
232
                else:
 
233
                    self.signature_image.set_from_file(icon_path("sign-bad.png"))
 
234
                    self.signature_label.set_markup("<b>Authenticity cannot be confirmed</b>\n" +
 
235
                                                    "Revision committer is not the same as signer.")
 
236
            else:
 
237
                self.signature_image.set_from_file(icon_path("sign-bad.png"))
 
238
                self.signature_label.set_markup("<b>Authenticity cannot be confirmed</b>\n" +
 
239
                                                "This revision has been signed, but the " +
 
240
                                                "key is not trusted.")
 
241
        else:
 
242
            self.show_no_signature()
 
243
            self.signature_image.set_from_file(icon_path("sign-bad.png"))
 
244
            self.signature_label.set_markup("<b>Authenticity cannot be confirmed</b>\n" +
 
245
                                            "Signature key not available.")
 
246
            return
 
247
 
 
248
        trust = key.get_trust()
 
249
 
 
250
        if trust <= seahorse.TRUST_NEVER:
 
251
            trust_text = 'never trusted'
 
252
        elif trust == seahorse.TRUST_UNKNOWN:
 
253
            trust_text = 'not trusted'
 
254
        elif trust == seahorse.TRUST_MARGINAL:
 
255
            trust_text = 'marginally trusted'
 
256
        elif trust == seahorse.TRUST_FULL:
 
257
            trust_text = 'fully trusted'
 
258
        elif trust == seahorse.TRUST_ULTIMATE:
 
259
            trust_text = 'ultimately trusted'
 
260
 
 
261
        self.signature_key_id_label.show()
 
262
        self.signature_key_id.set_text(key.get_id())
 
263
 
 
264
        fingerprint = key.get_fingerprint()
 
265
        if fingerprint == "":
 
266
            fingerprint = '<span foreground="dim grey">N/A</span>'
 
267
 
 
268
        self.signature_fingerprint_label.show()
 
269
        self.signature_fingerprint.set_markup(fingerprint)
 
270
 
 
271
        self.signature_trust_label.show()
 
272
        self.signature_trust.set_text('This key is ' + trust_text)
 
273
 
29
274
 
30
275
class RevisionView(gtk.Notebook):
31
276
    """ Custom widget for commit log details.
64
309
        )
65
310
    }
66
311
 
67
 
 
68
 
    def __init__(self, branch=None):
 
312
    def __init__(self, branch=None, repository=None):
69
313
        gtk.Notebook.__init__(self)
70
314
 
 
315
        self._revision = None
 
316
        self._branch = branch
 
317
        if branch is not None:
 
318
            self._repository = branch.repository
 
319
        else:
 
320
            self._repository = repository
 
321
 
71
322
        self._create_general()
72
323
        self._create_relations()
73
 
        self._create_signature()
 
324
        # Disabled because testaments aren't verified yet:
 
325
        # if has_seahorse:
 
326
        #    self._create_signature()
74
327
        self._create_file_info_view()
 
328
        self._create_bugs()
75
329
 
76
 
        self.set_current_page(0)
 
330
        self.set_current_page(PAGE_GENERAL)
 
331
        self.connect_after('switch-page', self._switch_page_cb)
77
332
        
78
333
        self._show_callback = None
79
334
        self._clicked_callback = None
80
335
 
81
336
        self._revision = None
82
337
        self._branch = branch
83
 
        self._repository = branch.repository
84
338
 
85
 
        if self._branch is not None and self._branch.supports_tags():
86
 
            self._tagdict = self._branch.tags.get_reverse_tag_dict()
87
 
        else:
88
 
            self._tagdict = {}
 
339
        self.update_tags()
89
340
 
90
341
        self.set_file_id(None)
91
342
 
131
382
    def get_revision(self):
132
383
        return self.get_property('revision')
133
384
 
134
 
    def set_children(self, children):
135
 
        self._add_parents_or_children(children,
136
 
                                      self.children_widgets,
137
 
                                      self.children_table)
138
 
 
139
385
    def _set_revision(self, revision):
140
386
        if revision is None: return
141
387
 
189
435
        else:
190
436
            self.file_info_box.hide()
191
437
 
 
438
    def update_tags(self):
 
439
        if self._branch is not None and self._branch.supports_tags():
 
440
            self._tagdict = self._branch.tags.get_reverse_tag_dict()
 
441
        else:
 
442
            self._tagdict = {}
 
443
 
 
444
        self._add_tags()
 
445
 
 
446
    def _update_signature(self, widget, param):
 
447
        if self.get_current_page() == PAGE_SIGNATURE:
 
448
            self.signature_table.set_revision(self._revision)
 
449
 
 
450
    def _update_bugs(self, widget, param):
 
451
        self.bugs_page.set_revision(self._revision)
 
452
        label = self.get_tab_label(self.bugs_page)
 
453
        label.set_sensitive(self.bugs_page.get_num_bugs() != 0)
 
454
 
 
455
    def set_children(self, children):
 
456
        self._add_parents_or_children(children,
 
457
                                      self.children_widgets,
 
458
                                      self.children_table)
 
459
 
 
460
    def _switch_page_cb(self, notebook, page, page_num):
 
461
        if page_num == PAGE_SIGNATURE:
 
462
            self.signature_table.set_revision(self._revision)
 
463
 
 
464
 
 
465
 
192
466
    def _show_clicked_cb(self, widget, revid, parentid):
193
467
        """Callback for when the show button for a parent is clicked."""
194
468
        self._show_callback(revid, parentid)
197
471
        """Callback for when the go button for a parent is clicked."""
198
472
 
199
473
    def _add_tags(self, *args):
 
474
        if self._revision is None:
 
475
            return
 
476
 
200
477
        if self._tagdict.has_key(self._revision.revision_id):
201
478
            tags = self._tagdict[self._revision.revision_id]
202
479
        else:
245
522
 
246
523
            button = gtk.Button(revid)
247
524
            button.connect("clicked",
248
 
                    lambda w, r: self.set_revision(self._branch.repository.get_revision(r)), revid)
 
525
                    lambda w, r: self.set_revision(self._repository.get_revision(r)), revid)
249
526
            button.set_use_underline(False)
250
527
            hbox.pack_start(button, expand=False, fill=True)
251
528
            button.show()
267
544
        vbox.show()
268
545
 
269
546
    def _create_signature(self):
270
 
        signature_box = gtk.Table(rows=1, columns=2)
271
 
        signature_box.set_col_spacing(0, 12)
272
 
 
273
 
        self.signature_image = gtk.Image()
274
 
        signature_box.attach(self.signature_image, 0, 1, 0, 1, gtk.FILL)
275
 
 
276
 
        self.signature_label = gtk.Label()
277
 
        signature_box.attach(self.signature_label, 1, 2, 0, 1, gtk.FILL)
278
 
 
279
 
        signature_info = gtk.Table(rows=1, columns=2)
280
 
        signature_info.set_row_spacings(6)
281
 
        signature_info.set_col_spacings(6)
282
 
 
283
 
        align = gtk.Alignment(1.0, 0.5)
284
 
        label = gtk.Label()
285
 
        label.set_markup("<b>Key Id:</b>")
286
 
        align.add(label)
287
 
        signature_info.attach(align, 0, 1, 0, 1, gtk.FILL, gtk.FILL)
288
 
 
289
 
        align = gtk.Alignment(0.0, 0.5)
290
 
        self.signature_key_id = gtk.Label()
291
 
        self.signature_key_id.set_selectable(True)
292
 
        align.add(self.signature_key_id)
293
 
        signature_info.attach(align, 1, 2, 0, 1, gtk.EXPAND | gtk.FILL, gtk.FILL)
294
 
 
295
 
        box = gtk.VBox(False, 6)
296
 
        box.set_border_width(6)
297
 
        box.pack_start(signature_box, expand=False)
298
 
        box.pack_start(signature_info, expand=False)
299
 
        box.show_all()
300
 
        self.append_page(box, tab_label=gtk.Label("Signature"))
301
 
 
 
547
        self.signature_table = SignatureTab(self._repository)
 
548
        self.append_page(self.signature_table, tab_label=gtk.Label('Signature'))
302
549
        self.connect_after('notify::revision', self._update_signature)
303
550
 
304
551
    def _create_headers(self):
455
702
        tv = gtk.TextView(msg_buffer)
456
703
        tv.set_editable(False)
457
704
        tv.set_wrap_mode(gtk.WRAP_WORD)
 
705
 
458
706
        tv.modify_font(pango.FontDescription("Monospace"))
459
707
        tv.show()
460
708
        window.add(tv)
461
709
        window.show()
462
710
        return window
463
711
 
 
712
    def _create_bugs(self):
 
713
        self.bugs_page = BugsTab()
 
714
        self.connect_after('notify::revision', self._update_bugs) 
 
715
        self.append_page(self.bugs_page, tab_label=gtk.Label('Bugs'))
 
716
 
464
717
    def _create_file_info_view(self):
465
718
        self.file_info_box = gtk.VBox(False, 6)
466
719
        self.file_info_box.set_border_width(6)
479
732
        self.file_info_box.hide() # Only shown when there are per-file messages
480
733
        self.append_page(self.file_info_box, tab_label=gtk.Label('Per-file'))
481
734
 
482
 
    def _update_signature(self, widget, param):
483
 
        revid = self._revision.revision_id
484
 
 
485
 
        if self._repository.has_signature_for_revision_id(revid):
486
 
            signature_text = self._repository.get_signature_text(revid)
487
 
            signature = gpg.verify(signature_text)
488
 
 
489
 
            if signature.key_id is not None:
490
 
                self.signature_key_id.set_text(signature.key_id)
491
 
 
492
 
            if signature.is_valid():
493
 
                self.signature_image.set_from_file("icons/sign-ok.png")
494
 
                self.signature_label.set_text("This revision has been signed.")
495
 
            else:
496
 
                self.signature_image.set_from_file("icons/sign-bad.png")
497
 
                self.signature_label.set_text("This revision has been signed, " + 
498
 
                        "but the authenticity of the signature cannot be verified.")
499
 
        else:
500
 
            self.signature_key_id.set_text("")
501
 
            self.signature_image.set_from_file("icons/sign-unknown.png")
502
 
            self.signature_label.set_text("This revision has not been signed.")
503
 
 
504