/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-03-15 20:42:00 UTC
  • mto: (450.1.11 trunk) (399.1.17 signatures)
  • mto: This revision was merged to the branch mainline in revision 458.
  • Revision ID: daniel.schierbeck@gmail.com-20080315204200-xtbkppagzh434n38
Added signature icons.

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 gobject
21
22
import pango
22
 
import gobject
23
 
import webbrowser
 
23
from gpg import GPGSubprocess
24
24
 
25
 
from bzrlib.plugins.gtk import icon_path
26
25
from bzrlib.osutils import format_date
27
26
from bzrlib.util.bencode import bdecode
28
27
 
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
 
 
 
28
gpg = GPGSubprocess()
274
29
 
275
30
class RevisionView(gtk.Notebook):
276
31
    """ Custom widget for commit log details.
309
64
        )
310
65
    }
311
66
 
312
 
    def __init__(self, branch=None, repository=None):
 
67
 
 
68
    def __init__(self, branch=None):
313
69
        gtk.Notebook.__init__(self)
314
70
 
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
 
 
322
71
        self._create_general()
323
72
        self._create_relations()
324
 
        # Disabled because testaments aren't verified yet:
325
 
        # if has_seahorse:
326
 
        #    self._create_signature()
 
73
        self._create_signature()
327
74
        self._create_file_info_view()
328
 
        self._create_bugs()
329
75
 
330
 
        self.set_current_page(PAGE_GENERAL)
331
 
        self.connect_after('switch-page', self._switch_page_cb)
 
76
        self.set_current_page(0)
332
77
        
333
78
        self._show_callback = None
334
79
        self._clicked_callback = None
335
80
 
336
81
        self._revision = None
337
82
        self._branch = branch
 
83
        self._repository = branch.repository
338
84
 
339
 
        self.update_tags()
 
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 = {}
340
89
 
341
90
        self.set_file_id(None)
342
91
 
382
131
    def get_revision(self):
383
132
        return self.get_property('revision')
384
133
 
 
134
    def set_children(self, children):
 
135
        self._add_parents_or_children(children,
 
136
                                      self.children_widgets,
 
137
                                      self.children_table)
 
138
 
385
139
    def _set_revision(self, revision):
386
140
        if revision is None: return
387
141
 
435
189
        else:
436
190
            self.file_info_box.hide()
437
191
 
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
 
 
466
192
    def _show_clicked_cb(self, widget, revid, parentid):
467
193
        """Callback for when the show button for a parent is clicked."""
468
194
        self._show_callback(revid, parentid)
471
197
        """Callback for when the go button for a parent is clicked."""
472
198
 
473
199
    def _add_tags(self, *args):
474
 
        if self._revision is None:
475
 
            return
476
 
 
477
200
        if self._tagdict.has_key(self._revision.revision_id):
478
201
            tags = self._tagdict[self._revision.revision_id]
479
202
        else:
522
245
 
523
246
            button = gtk.Button(revid)
524
247
            button.connect("clicked",
525
 
                    lambda w, r: self.set_revision(self._repository.get_revision(r)), revid)
 
248
                    lambda w, r: self.set_revision(self._branch.repository.get_revision(r)), revid)
526
249
            button.set_use_underline(False)
527
250
            hbox.pack_start(button, expand=False, fill=True)
528
251
            button.show()
544
267
        vbox.show()
545
268
 
546
269
    def _create_signature(self):
547
 
        self.signature_table = SignatureTab(self._repository)
548
 
        self.append_page(self.signature_table, tab_label=gtk.Label('Signature'))
 
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
 
549
302
        self.connect_after('notify::revision', self._update_signature)
550
303
 
551
304
    def _create_headers(self):
702
455
        tv = gtk.TextView(msg_buffer)
703
456
        tv.set_editable(False)
704
457
        tv.set_wrap_mode(gtk.WRAP_WORD)
705
 
 
706
458
        tv.modify_font(pango.FontDescription("Monospace"))
707
459
        tv.show()
708
460
        window.add(tv)
709
461
        window.show()
710
462
        return window
711
463
 
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
 
 
717
464
    def _create_file_info_view(self):
718
465
        self.file_info_box = gtk.VBox(False, 6)
719
466
        self.file_info_box.set_border_width(6)
732
479
        self.file_info_box.hide() # Only shown when there are per-file messages
733
480
        self.append_page(self.file_info_box, tab_label=gtk.Label('Per-file'))
734
481
 
 
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