/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: 2007-12-06 23:37:06 UTC
  • mto: This revision was merged to the branch mainline in revision 417.
  • Revision ID: daniel.schierbeck@gmail.com-20071206233706-eeinks66w86r3gfm
Fixed bug in gmissing.

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