/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-01-23 16:36:21 UTC
  • mto: (423.1.8 trunk)
  • mto: This revision was merged to the branch mainline in revision 429.
  • Revision ID: daniel.schierbeck@gmail.com-20080123163621-x8kublc38ojipnly
Made the revision popup menu correctly add tags.

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
21
23
 
22
24
from bzrlib.osutils import format_date
23
 
 
24
 
 
25
 
class LogView(gtk.ScrolledWindow):
 
25
from bzrlib.util.bencode import bdecode
 
26
 
 
27
class RevisionView(gtk.Notebook):
26
28
    """ Custom widget for commit log details.
27
29
 
28
30
    A variety of bzr tools may need to implement such a thing. This is a
29
31
    start.
30
32
    """
31
33
 
32
 
    def __init__(self, revision=None):
33
 
        gtk.ScrolledWindow.__init__(self)
34
 
        self.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
35
 
        self.set_shadow_type(gtk.SHADOW_NONE)
36
 
        self._create()
 
34
    __gproperties__ = {
 
35
        'branch': (
 
36
            gobject.TYPE_PYOBJECT,
 
37
            'Branch',
 
38
            'The branch holding the revision being displayed',
 
39
            gobject.PARAM_CONSTRUCT_ONLY | gobject.PARAM_WRITABLE
 
40
        ),
 
41
 
 
42
        'revision': (
 
43
            gobject.TYPE_PYOBJECT,
 
44
            'Revision',
 
45
            'The revision being displayed',
 
46
            gobject.PARAM_READWRITE
 
47
        ),
 
48
 
 
49
        'children': (
 
50
            gobject.TYPE_PYOBJECT,
 
51
            'Children',
 
52
            'Child revisions',
 
53
            gobject.PARAM_READWRITE
 
54
        ),
 
55
 
 
56
        'file-id': (
 
57
            gobject.TYPE_PYOBJECT,
 
58
            'File Id',
 
59
            'The file id',
 
60
            gobject.PARAM_READWRITE
 
61
        )
 
62
    }
 
63
 
 
64
 
 
65
    def __init__(self, branch=None):
 
66
        gtk.Notebook.__init__(self)
 
67
 
 
68
        self._create_general()
 
69
        self._create_relations()
 
70
        self._create_file_info_view()
 
71
 
 
72
        self.set_current_page(0)
 
73
        
37
74
        self._show_callback = None
38
 
        self._go_callback = None
39
75
        self._clicked_callback = None
40
76
 
41
 
        if revision is not None:
42
 
            self.set_revision(revision)
 
77
        self._revision = None
 
78
        self._branch = branch
 
79
 
 
80
        self.update_tags()
 
81
 
 
82
        self.set_file_id(None)
 
83
 
 
84
    def do_get_property(self, property):
 
85
        if property.name == 'branch':
 
86
            return self._branch
 
87
        elif property.name == 'revision':
 
88
            return self._revision
 
89
        elif property.name == 'children':
 
90
            return self._children
 
91
        elif property.name == 'file-id':
 
92
            return self._file_id
 
93
        else:
 
94
            raise AttributeError, 'unknown property %s' % property.name
 
95
 
 
96
    def do_set_property(self, property, value):
 
97
        if property.name == 'branch':
 
98
            self._branch = value
 
99
        elif property.name == 'revision':
 
100
            self._set_revision(value)
 
101
        elif property.name == 'children':
 
102
            self.set_children(value)
 
103
        elif property.name == 'file-id':
 
104
            self._file_id = value
 
105
        else:
 
106
            raise AttributeError, 'unknown property %s' % property.name
43
107
 
44
108
    def set_show_callback(self, callback):
45
109
        self._show_callback = callback
46
110
 
47
 
    def set_go_callback(self, callback):
48
 
        self._go_callback = callback
 
111
    def set_file_id(self, file_id):
 
112
        """Set a specific file id that we want to track.
 
113
 
 
114
        This just effects the display of a per-file commit message.
 
115
        If it is set to None, then all commit messages will be shown.
 
116
        """
 
117
        self.set_property('file-id', file_id)
49
118
 
50
119
    def set_revision(self, revision):
 
120
        if revision != self._revision:
 
121
            self.set_property('revision', revision)
 
122
 
 
123
    def get_revision(self):
 
124
        return self.get_property('revision')
 
125
 
 
126
    def _set_revision(self, revision):
 
127
        if revision is None: return
 
128
 
51
129
        self._revision = revision
52
 
        self.revision_id.set_text(revision.revision_id)
53
 
        self.committer.set_text(revision.committer)
54
 
        self.timestamp.set_text(format_date(revision.timestamp,
55
 
                                            revision.timezone))
56
 
        self.message_buffer.set_text(revision.message)
 
130
        if revision.committer is not None:
 
131
            self.committer.set_text(revision.committer)
 
132
        else:
 
133
            self.committer.set_text("")
 
134
        author = revision.properties.get('author', '')
 
135
        if author != '':
 
136
            self.author.set_text(author)
 
137
            self.author.show()
 
138
            self.author_label.show()
 
139
        else:
 
140
            self.author.hide()
 
141
            self.author_label.hide()
 
142
 
 
143
        if revision.timestamp is not None:
 
144
            self.timestamp.set_text(format_date(revision.timestamp,
 
145
                                                revision.timezone))
57
146
        try:
58
147
            self.branchnick_label.set_text(revision.properties['branch-nick'])
59
148
        except KeyError:
60
149
            self.branchnick_label.set_text("")
61
150
 
62
 
        self._add_parents(revision.parent_ids)
 
151
        self._add_parents_or_children(revision.parent_ids,
 
152
                                      self.parents_widgets,
 
153
                                      self.parents_table)
 
154
        
 
155
        file_info = revision.properties.get('file-info', None)
 
156
        if file_info is not None:
 
157
            file_info = bdecode(file_info.encode('UTF-8'))
 
158
 
 
159
        if file_info:
 
160
            if self._file_id is None:
 
161
                text = []
 
162
                for fi in file_info:
 
163
                    text.append('%(path)s\n%(message)s' % fi)
 
164
                self.file_info_buffer.set_text('\n'.join(text))
 
165
                self.file_info_box.show()
 
166
            else:
 
167
                text = []
 
168
                for fi in file_info:
 
169
                    if fi['file_id'] == self._file_id:
 
170
                        text.append(fi['message'])
 
171
                if text:
 
172
                    self.file_info_buffer.set_text('\n'.join(text))
 
173
                    self.file_info_box.show()
 
174
                else:
 
175
                    self.file_info_box.hide()
 
176
        else:
 
177
            self.file_info_box.hide()
 
178
 
 
179
    def update_tags(self):
 
180
        if self._branch is not None and self._branch.supports_tags():
 
181
            self._tagdict = self._branch.tags.get_reverse_tag_dict()
 
182
        else:
 
183
            self._tagdict = {}
 
184
 
 
185
        self._add_tags()
 
186
 
 
187
    def set_children(self, children):
 
188
        self._add_parents_or_children(children,
 
189
                                      self.children_widgets,
 
190
                                      self.children_table)
63
191
 
64
192
    def _show_clicked_cb(self, widget, revid, parentid):
65
193
        """Callback for when the show button for a parent is clicked."""
67
195
 
68
196
    def _go_clicked_cb(self, widget, revid):
69
197
        """Callback for when the go button for a parent is clicked."""
70
 
        self._go_callback(revid)
71
 
 
72
 
    def _add_parents(self, parent_ids):
73
 
        for widget in self.parents_widgets:
74
 
            self.parents_table.remove(widget)
 
198
 
 
199
    def _add_tags(self, *args):
 
200
        if self._revision is None: return
 
201
 
 
202
        if self._tagdict.has_key(self._revision.revision_id):
 
203
            tags = self._tagdict[self._revision.revision_id]
 
204
        else:
 
205
            tags = []
75
206
            
76
 
        self.parents_widgets = []
77
 
        self.parents_table.resize(max(len(parent_ids), 1), 2)
78
 
 
79
 
        for idx, parent_id in enumerate(parent_ids):
 
207
        if tags == []:
 
208
            self.tags_list.hide()
 
209
            self.tags_label.hide()
 
210
            return
 
211
 
 
212
        self.tags_list.set_text(", ".join(tags))
 
213
 
 
214
        self.tags_list.show_all()
 
215
        self.tags_label.show_all()
 
216
        
 
217
    def _add_parents_or_children(self, revids, widgets, table):
 
218
        while len(widgets) > 0:
 
219
            widget = widgets.pop()
 
220
            table.remove(widget)
 
221
        
 
222
        table.resize(max(len(revids), 1), 2)
 
223
 
 
224
        for idx, revid in enumerate(revids):
80
225
            align = gtk.Alignment(0.0, 0.0)
81
 
            self.parents_widgets.append(align)
82
 
            self.parents_table.attach(align, 1, 2, idx, idx + 1,
 
226
            widgets.append(align)
 
227
            table.attach(align, 1, 2, idx, idx + 1,
83
228
                                      gtk.EXPAND | gtk.FILL, gtk.FILL)
84
229
            align.show()
85
230
 
96
241
                button = gtk.Button()
97
242
                button.add(image)
98
243
                button.connect("clicked", self._show_clicked_cb,
99
 
                               self._revision.revision_id, parent_id)
 
244
                               self._revision.revision_id, revid)
100
245
                hbox.pack_start(button, expand=False, fill=True)
101
246
                button.show()
102
247
 
103
 
            if self._go_callback is not None:
104
 
                button = gtk.Button(parent_id)
105
 
                button.connect("clicked", self._go_clicked_cb, parent_id)
106
 
            else:
107
 
                button = gtk.Label(parent_id)
 
248
            button = gtk.Button(revid)
 
249
            button.connect("clicked",
 
250
                    lambda w, r: self.set_revision(self._branch.repository.get_revision(r)), revid)
108
251
            button.set_use_underline(False)
109
252
            hbox.pack_start(button, expand=False, fill=True)
110
253
            button.show()
111
254
 
112
 
    def _create(self):
 
255
    def _create_general(self):
113
256
        vbox = gtk.VBox(False, 6)
114
257
        vbox.set_border_width(6)
115
258
        vbox.pack_start(self._create_headers(), expand=False, fill=True)
116
 
        vbox.pack_start(self._create_parents_table(), expand=False, fill=True)
117
259
        vbox.pack_start(self._create_message_view())
118
 
        self.add_with_viewport(vbox)
 
260
        self.append_page(vbox, tab_label=gtk.Label("General"))
 
261
        vbox.show()
 
262
 
 
263
    def _create_relations(self):
 
264
        vbox = gtk.VBox(False, 6)
 
265
        vbox.set_border_width(6)
 
266
        vbox.pack_start(self._create_parents(), expand=False, fill=True)
 
267
        vbox.pack_start(self._create_children(), expand=False, fill=True)
 
268
        self.append_page(vbox, tab_label=gtk.Label("Relations"))
119
269
        vbox.show()
120
270
 
121
271
    def _create_headers(self):
122
 
        self.table = gtk.Table(rows=4, columns=2)
 
272
        self.table = gtk.Table(rows=5, columns=2)
123
273
        self.table.set_row_spacings(6)
124
274
        self.table.set_col_spacings(6)
125
275
        self.table.show()
133
283
        label.show()
134
284
 
135
285
        align = gtk.Alignment(0.0, 0.5)
136
 
        self.revision_id = gtk.Label()
137
 
        self.revision_id.set_selectable(True)
138
 
        align.add(self.revision_id)
 
286
        revision_id = gtk.Label()
 
287
        revision_id.set_selectable(True)
 
288
        self.connect('notify::revision', 
 
289
                lambda w, p: revision_id.set_text(self._revision.revision_id))
 
290
        align.add(revision_id)
139
291
        self.table.attach(align, 1, 2, 0, 1, gtk.EXPAND | gtk.FILL, gtk.FILL)
140
292
        align.show()
141
 
        self.revision_id.show()
 
293
        revision_id.show()
 
294
 
 
295
        align = gtk.Alignment(1.0, 0.5)
 
296
        self.author_label = gtk.Label()
 
297
        self.author_label.set_markup("<b>Author:</b>")
 
298
        align.add(self.author_label)
 
299
        self.table.attach(align, 0, 1, 1, 2, gtk.FILL, gtk.FILL)
 
300
        align.show()
 
301
        self.author_label.show()
 
302
 
 
303
        align = gtk.Alignment(0.0, 0.5)
 
304
        self.author = gtk.Label()
 
305
        self.author.set_selectable(True)
 
306
        align.add(self.author)
 
307
        self.table.attach(align, 1, 2, 1, 2, gtk.EXPAND | gtk.FILL, gtk.FILL)
 
308
        align.show()
 
309
        self.author.show()
 
310
        self.author.hide()
142
311
 
143
312
        align = gtk.Alignment(1.0, 0.5)
144
313
        label = gtk.Label()
145
314
        label.set_markup("<b>Committer:</b>")
146
315
        align.add(label)
147
 
        self.table.attach(align, 0, 1, 1, 2, gtk.FILL, gtk.FILL)
 
316
        self.table.attach(align, 0, 1, 2, 3, gtk.FILL, gtk.FILL)
148
317
        align.show()
149
318
        label.show()
150
319
 
152
321
        self.committer = gtk.Label()
153
322
        self.committer.set_selectable(True)
154
323
        align.add(self.committer)
155
 
        self.table.attach(align, 1, 2, 1, 2, gtk.EXPAND | gtk.FILL, gtk.FILL)
 
324
        self.table.attach(align, 1, 2, 2, 3, gtk.EXPAND | gtk.FILL, gtk.FILL)
156
325
        align.show()
157
326
        self.committer.show()
158
327
 
160
329
        label = gtk.Label()
161
330
        label.set_markup("<b>Branch nick:</b>")
162
331
        align.add(label)
163
 
        self.table.attach(align, 0, 1, 2, 3, gtk.FILL, gtk.FILL)
 
332
        self.table.attach(align, 0, 1, 3, 4, gtk.FILL, gtk.FILL)
164
333
        label.show()
165
334
        align.show()
166
335
 
168
337
        self.branchnick_label = gtk.Label()
169
338
        self.branchnick_label.set_selectable(True)
170
339
        align.add(self.branchnick_label)
171
 
        self.table.attach(align, 1, 2, 2, 3, gtk.EXPAND | gtk.FILL, gtk.FILL)
 
340
        self.table.attach(align, 1, 2, 3, 4, gtk.EXPAND | gtk.FILL, gtk.FILL)
172
341
        self.branchnick_label.show()
173
342
        align.show()
174
343
 
176
345
        label = gtk.Label()
177
346
        label.set_markup("<b>Timestamp:</b>")
178
347
        align.add(label)
179
 
        self.table.attach(align, 0, 1, 3, 4, gtk.FILL, gtk.FILL)
 
348
        self.table.attach(align, 0, 1, 4, 5, gtk.FILL, gtk.FILL)
180
349
        align.show()
181
350
        label.show()
182
351
 
184
353
        self.timestamp = gtk.Label()
185
354
        self.timestamp.set_selectable(True)
186
355
        align.add(self.timestamp)
187
 
        self.table.attach(align, 1, 2, 3, 4, gtk.EXPAND | gtk.FILL, gtk.FILL)
 
356
        self.table.attach(align, 1, 2, 4, 5, gtk.EXPAND | gtk.FILL, gtk.FILL)
188
357
        align.show()
189
358
        self.timestamp.show()
190
359
 
 
360
        align = gtk.Alignment(1.0, 0.5)
 
361
        self.tags_label = gtk.Label()
 
362
        self.tags_label.set_markup("<b>Tags:</b>")
 
363
        align.add(self.tags_label)
 
364
        align.show()
 
365
        self.table.attach(align, 0, 1, 5, 6, gtk.FILL, gtk.FILL)
 
366
        self.tags_label.show()
 
367
 
 
368
        align = gtk.Alignment(0.0, 0.5)
 
369
        self.tags_list = gtk.Label()
 
370
        align.add(self.tags_list)
 
371
        self.table.attach(align, 1, 2, 5, 6, gtk.EXPAND | gtk.FILL, gtk.FILL)
 
372
        align.show()
 
373
        self.tags_list.show()
 
374
 
 
375
        self.connect('notify::revision', self._add_tags)
 
376
 
191
377
        return self.table
192
378
 
193
 
    def _create_parents_table(self):
194
 
        self.parents_table = gtk.Table(rows=1, columns=2)
195
 
        self.parents_table.set_row_spacings(3)
196
 
        self.parents_table.set_col_spacings(6)
197
 
        self.parents_table.show()
 
379
    
 
380
    def _create_parents(self):
 
381
        hbox = gtk.HBox(True, 3)
 
382
        
 
383
        self.parents_table = self._create_parents_or_children_table(
 
384
            "<b>Parents:</b>")
198
385
        self.parents_widgets = []
 
386
        hbox.pack_start(self.parents_table)
 
387
 
 
388
        hbox.show()
 
389
        return hbox
 
390
 
 
391
    def _create_children(self):
 
392
        hbox = gtk.HBox(True, 3)
 
393
        self.children_table = self._create_parents_or_children_table(
 
394
            "<b>Children:</b>")
 
395
        self.children_widgets = []
 
396
        hbox.pack_start(self.children_table)
 
397
        hbox.show()
 
398
        return hbox
 
399
        
 
400
    def _create_parents_or_children_table(self, text):
 
401
        table = gtk.Table(rows=1, columns=2)
 
402
        table.set_row_spacings(3)
 
403
        table.set_col_spacings(6)
 
404
        table.show()
199
405
 
200
406
        label = gtk.Label()
201
 
        label.set_markup("<b>Parents:</b>")
 
407
        label.set_markup(text)
202
408
        align = gtk.Alignment(0.0, 0.5)
203
409
        align.add(label)
204
 
        self.parents_table.attach(align, 0, 1, 0, 1, gtk.FILL, gtk.FILL)
 
410
        table.attach(align, 0, 1, 0, 1, gtk.FILL, gtk.FILL)
205
411
        label.show()
206
412
        align.show()
207
413
 
208
 
        return self.parents_table
 
414
        return table
209
415
 
210
416
    def _create_message_view(self):
211
 
        self.message_buffer = gtk.TextBuffer()
212
 
        tv = gtk.TextView(self.message_buffer)
213
 
        tv.set_editable(False)
214
 
        tv.set_wrap_mode(gtk.WRAP_WORD)
215
 
        tv.modify_font(pango.FontDescription("Monospace"))
216
 
        tv.show()
217
 
        return tv
 
417
        msg_buffer = gtk.TextBuffer()
 
418
        self.connect('notify::revision',
 
419
                lambda w, p: msg_buffer.set_text(self._revision.message))
 
420
        window = gtk.ScrolledWindow()
 
421
        window.set_policy(gtk.POLICY_NEVER, gtk.POLICY_AUTOMATIC)
 
422
        window.set_shadow_type(gtk.SHADOW_IN)
 
423
        tv = gtk.TextView(msg_buffer)
 
424
        tv.set_editable(False)
 
425
        tv.set_wrap_mode(gtk.WRAP_WORD)
 
426
        tv.modify_font(pango.FontDescription("Monospace"))
 
427
        tv.show()
 
428
        window.add(tv)
 
429
        window.show()
 
430
        return window
 
431
 
 
432
    def _create_file_info_view(self):
 
433
        self.file_info_box = gtk.VBox(False, 6)
 
434
        self.file_info_box.set_border_width(6)
 
435
        self.file_info_buffer = gtk.TextBuffer()
 
436
        window = gtk.ScrolledWindow()
 
437
        window.set_policy(gtk.POLICY_NEVER, gtk.POLICY_AUTOMATIC)
 
438
        window.set_shadow_type(gtk.SHADOW_IN)
 
439
        tv = gtk.TextView(self.file_info_buffer)
 
440
        tv.set_editable(False)
 
441
        tv.set_wrap_mode(gtk.WRAP_WORD)
 
442
        tv.modify_font(pango.FontDescription("Monospace"))
 
443
        tv.show()
 
444
        window.add(tv)
 
445
        window.show()
 
446
        self.file_info_box.pack_start(window)
 
447
        self.file_info_box.hide() # Only shown when there are per-file messages
 
448
        self.append_page(self.file_info_box, tab_label=gtk.Label('Per-file'))
218
449