/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 annotate/logview.py

  • Committer: Jelmer Vernooij
  • Date: 2007-02-01 15:50:40 UTC
  • Revision ID: jelmer@samba.org-20070201155040-3hq4mfbxs99kzazy
add framework for tests.

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>
3
2
 
4
3
# This program is free software; you can redistribute it and/or modify
5
4
# it under the terms of the GNU General Public License as published by
19
18
pygtk.require("2.0")
20
19
import gtk
21
20
import pango
22
 
import gobject
23
21
 
24
22
from bzrlib.osutils import format_date
25
 
from bzrlib.util.bencode import bdecode
26
 
 
27
 
class RevisionView(gtk.Notebook):
 
23
 
 
24
 
 
25
class LogView(gtk.ScrolledWindow):
28
26
    """ Custom widget for commit log details.
29
27
 
30
28
    A variety of bzr tools may need to implement such a thing. This is a
31
29
    start.
32
30
    """
33
31
 
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)
 
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)
121
41
 
122
42
    def set_revision(self, revision):
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 = []
 
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)
199
53
            
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)
 
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)
230
60
            align.show()
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):
 
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):
257
84
        vbox = gtk.VBox(False, 6)
258
85
        vbox.set_border_width(6)
259
86
        vbox.pack_start(self._create_headers(), expand=False, fill=True)
260
87
        vbox.pack_start(self._create_message_view())
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"))
 
88
        self.add_with_viewport(vbox)
270
89
        vbox.show()
271
90
 
272
91
    def _create_headers(self):
273
 
        self.table = gtk.Table(rows=5, columns=2)
 
92
        self.table = gtk.Table(rows=4, columns=2)
274
93
        self.table.set_row_spacings(6)
275
94
        self.table.set_col_spacings(6)
276
95
        self.table.show()
277
 
 
 
96
        
278
97
        align = gtk.Alignment(1.0, 0.5)
279
98
        label = gtk.Label()
280
 
        label.set_markup("<b>Revision Id:</b>")
 
99
        label.set_markup("<b>Committer:</b>")
281
100
        align.add(label)
282
101
        self.table.attach(align, 0, 1, 0, 1, gtk.FILL, gtk.FILL)
283
102
        align.show()
284
103
        label.show()
285
104
 
286
105
        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
 
 
313
 
        align = gtk.Alignment(1.0, 0.5)
314
 
        label = gtk.Label()
315
 
        label.set_markup("<b>Committer:</b>")
316
 
        align.add(label)
317
 
        self.table.attach(align, 0, 1, 2, 3, gtk.FILL, gtk.FILL)
318
 
        align.show()
319
 
        label.show()
320
 
 
321
 
        align = gtk.Alignment(0.0, 0.5)
322
106
        self.committer = gtk.Label()
323
107
        self.committer.set_selectable(True)
324
108
        align.add(self.committer)
325
 
        self.table.attach(align, 1, 2, 2, 3, gtk.EXPAND | gtk.FILL, gtk.FILL)
 
109
        self.table.attach(align, 1, 2, 0, 1, gtk.EXPAND | gtk.FILL, gtk.FILL)
326
110
        align.show()
327
111
        self.committer.show()
328
112
 
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
 
 
345
113
        align = gtk.Alignment(1.0, 0.5)
346
114
        label = gtk.Label()
347
115
        label.set_markup("<b>Timestamp:</b>")
348
116
        align.add(label)
349
 
        self.table.attach(align, 0, 1, 4, 5, gtk.FILL, gtk.FILL)
 
117
        self.table.attach(align, 0, 1, 1, 2, gtk.FILL, gtk.FILL)
350
118
        align.show()
351
119
        label.show()
352
120
 
354
122
        self.timestamp = gtk.Label()
355
123
        self.timestamp.set_selectable(True)
356
124
        align.add(self.timestamp)
357
 
        self.table.attach(align, 1, 2, 4, 5, gtk.EXPAND | gtk.FILL, gtk.FILL)
 
125
        self.table.attach(align, 1, 2, 1, 2, gtk.EXPAND | gtk.FILL, gtk.FILL)
358
126
        align.show()
359
127
        self.timestamp.show()
360
128
 
361
129
        align = gtk.Alignment(1.0, 0.5)
362
 
        self.tags_label = gtk.Label()
363
 
        self.tags_label.set_markup("<b>Tags:</b>")
364
 
        align.add(self.tags_label)
 
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)
365
134
        align.show()
366
 
        self.table.attach(align, 0, 1, 5, 6, gtk.FILL, gtk.FILL)
367
 
        self.tags_label.show()
 
135
        label.show()
368
136
 
369
137
        align = gtk.Alignment(0.0, 0.5)
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)
 
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)
373
142
        align.show()
374
 
        self.tags_list.show()
375
 
        self.tags_widgets = []
376
 
 
377
 
        self.connect('notify::revision', self._add_tags)
 
143
        self.revision_id.show()
378
144
 
379
145
        return self.table
380
146
 
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
 
 
418
147
    def _create_message_view(self):
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'))
 
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
451
155