/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-13 14:15:20 UTC
  • mto: (423.1.2 trunk)
  • mto: This revision was merged to the branch mainline in revision 429.
  • Revision ID: daniel.schierbeck@gmail.com-20080113141520-ol1on2ju8h833rh0
Moved the branch window class to the viz package.

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