/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.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)
41
 
 
42
 
    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)
 
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
        
 
68
        self._show_callback = None
 
69
        self._clicked_callback = None
 
70
 
 
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
 
100
 
 
101
    def set_show_callback(self, callback):
 
102
        self._show_callback = callback
 
103
 
 
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
 
 
122
        self._revision = revision
 
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))
 
139
        try:
 
140
            self.branchnick_label.set_text(revision.properties['branch-nick'])
 
141
        except KeyError:
 
142
            self.branchnick_label.set_text("")
 
143
 
 
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()
 
177
 
 
178
    def _show_clicked_cb(self, widget, revid, parentid):
 
179
        """Callback for when the show button for a parent is clicked."""
 
180
        self._show_callback(revid, parentid)
 
181
 
 
182
    def _go_clicked_cb(self, widget, revid):
 
183
        """Callback for when the go button for a parent is clicked."""
 
184
 
 
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 = []
53
190
            
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)
 
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):
 
217
            align = gtk.Alignment(0.0, 0.0)
 
218
            widgets.append(align)
 
219
            table.attach(align, 1, 2, idx, idx + 1,
 
220
                                      gtk.EXPAND | gtk.FILL, gtk.FILL)
60
221
            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):
 
222
 
 
223
            hbox = gtk.HBox(False, spacing=6)
 
224
            align.add(hbox)
 
225
            hbox.show()
 
226
 
 
227
            image = gtk.Image()
 
228
            image.set_from_stock(
 
229
                gtk.STOCK_FIND, gtk.ICON_SIZE_SMALL_TOOLBAR)
 
230
            image.show()
 
231
 
 
232
            if self._show_callback is not None:
 
233
                button = gtk.Button()
 
234
                button.add(image)
 
235
                button.connect("clicked", self._show_clicked_cb,
 
236
                               self._revision.revision_id, revid)
 
237
                hbox.pack_start(button, expand=False, fill=True)
 
238
                button.show()
 
239
 
 
240
            button = gtk.Button(revid)
 
241
            button.connect("clicked",
 
242
                    lambda w, r: self.set_revision(self._branch.repository.get_revision(revid)), revid)
 
243
            button.set_use_underline(False)
 
244
            hbox.pack_start(button, expand=False, fill=True)
 
245
            button.show()
 
246
 
 
247
    def _create_general(self):
84
248
        vbox = gtk.VBox(False, 6)
85
249
        vbox.set_border_width(6)
86
250
        vbox.pack_start(self._create_headers(), expand=False, fill=True)
87
251
        vbox.pack_start(self._create_message_view())
88
 
        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"))
89
262
        vbox.show()
90
263
 
91
264
    def _create_headers(self):
92
 
        self.table = gtk.Table(rows=4, columns=2)
 
265
        self.table = gtk.Table(rows=5, columns=2)
93
266
        self.table.set_row_spacings(6)
94
267
        self.table.set_col_spacings(6)
95
268
        self.table.show()
96
 
        
 
269
 
 
270
        align = gtk.Alignment(1.0, 0.5)
 
271
        label = gtk.Label()
 
272
        label.set_markup("<b>Revision Id:</b>")
 
273
        align.add(label)
 
274
        self.table.attach(align, 0, 1, 0, 1, gtk.FILL, gtk.FILL)
 
275
        align.show()
 
276
        label.show()
 
277
 
 
278
        align = gtk.Alignment(0.0, 0.5)
 
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)
 
284
        self.table.attach(align, 1, 2, 0, 1, gtk.EXPAND | gtk.FILL, gtk.FILL)
 
285
        align.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()
 
304
 
97
305
        align = gtk.Alignment(1.0, 0.5)
98
306
        label = gtk.Label()
99
307
        label.set_markup("<b>Committer:</b>")
100
308
        align.add(label)
101
 
        self.table.attach(align, 0, 1, 0, 1, gtk.FILL, gtk.FILL)
 
309
        self.table.attach(align, 0, 1, 2, 3, gtk.FILL, gtk.FILL)
102
310
        align.show()
103
311
        label.show()
104
312
 
106
314
        self.committer = gtk.Label()
107
315
        self.committer.set_selectable(True)
108
316
        align.add(self.committer)
109
 
        self.table.attach(align, 1, 2, 0, 1, gtk.EXPAND | gtk.FILL, gtk.FILL)
 
317
        self.table.attach(align, 1, 2, 2, 3, gtk.EXPAND | gtk.FILL, gtk.FILL)
110
318
        align.show()
111
319
        self.committer.show()
112
320
 
 
321
        align = gtk.Alignment(0.0, 0.5)
 
322
        label = gtk.Label()
 
323
        label.set_markup("<b>Branch nick:</b>")
 
324
        align.add(label)
 
325
        self.table.attach(align, 0, 1, 3, 4, gtk.FILL, gtk.FILL)
 
326
        label.show()
 
327
        align.show()
 
328
 
 
329
        align = gtk.Alignment(0.0, 0.5)
 
330
        self.branchnick_label = gtk.Label()
 
331
        self.branchnick_label.set_selectable(True)
 
332
        align.add(self.branchnick_label)
 
333
        self.table.attach(align, 1, 2, 3, 4, gtk.EXPAND | gtk.FILL, gtk.FILL)
 
334
        self.branchnick_label.show()
 
335
        align.show()
 
336
 
113
337
        align = gtk.Alignment(1.0, 0.5)
114
338
        label = gtk.Label()
115
339
        label.set_markup("<b>Timestamp:</b>")
116
340
        align.add(label)
117
 
        self.table.attach(align, 0, 1, 1, 2, gtk.FILL, gtk.FILL)
 
341
        self.table.attach(align, 0, 1, 4, 5, gtk.FILL, gtk.FILL)
118
342
        align.show()
119
343
        label.show()
120
344
 
122
346
        self.timestamp = gtk.Label()
123
347
        self.timestamp.set_selectable(True)
124
348
        align.add(self.timestamp)
125
 
        self.table.attach(align, 1, 2, 1, 2, gtk.EXPAND | gtk.FILL, gtk.FILL)
 
349
        self.table.attach(align, 1, 2, 4, 5, gtk.EXPAND | gtk.FILL, gtk.FILL)
126
350
        align.show()
127
351
        self.timestamp.show()
128
352
 
129
353
        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)
 
354
        self.tags_label = gtk.Label()
 
355
        self.tags_label.set_markup("<b>Tags:</b>")
 
356
        align.add(self.tags_label)
134
357
        align.show()
135
 
        label.show()
 
358
        self.table.attach(align, 0, 1, 5, 6, gtk.FILL, gtk.FILL)
 
359
        self.tags_label.show()
136
360
 
137
361
        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)
 
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)
142
365
        align.show()
143
 
        self.revision_id.show()
 
366
        self.tags_list.show()
 
367
        self.tags_widgets = []
 
368
 
 
369
        self.connect('notify::revision', self._add_tags)
144
370
 
145
371
        return self.table
146
372
 
 
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>")
 
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()
 
399
 
 
400
        label = gtk.Label()
 
401
        label.set_markup(text)
 
402
        align = gtk.Alignment(0.0, 0.5)
 
403
        align.add(label)
 
404
        table.attach(align, 0, 1, 0, 1, gtk.FILL, gtk.FILL)
 
405
        label.show()
 
406
        align.show()
 
407
 
 
408
        return table
 
409
 
147
410
    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
 
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'))
155
443