/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: 2006-09-29 20:59:52 UTC
  • mfrom: (0.8.92 merge)
  • Revision ID: jelmer@samba.org-20060929205952-32ce1f02b7cf334b
MergeĀ OliveĀ code.

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
 
        '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 = []
 
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)
190
53
            
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)
 
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)
221
60
            align.show()
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):
 
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):
248
84
        vbox = gtk.VBox(False, 6)
249
85
        vbox.set_border_width(6)
250
86
        vbox.pack_start(self._create_headers(), expand=False, fill=True)
251
87
        vbox.pack_start(self._create_message_view())
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"))
 
88
        self.add_with_viewport(vbox)
262
89
        vbox.show()
263
90
 
264
91
    def _create_headers(self):
265
 
        self.table = gtk.Table(rows=5, columns=2)
 
92
        self.table = gtk.Table(rows=4, columns=2)
266
93
        self.table.set_row_spacings(6)
267
94
        self.table.set_col_spacings(6)
268
95
        self.table.show()
269
 
 
 
96
        
270
97
        align = gtk.Alignment(1.0, 0.5)
271
98
        label = gtk.Label()
272
 
        label.set_markup("<b>Revision Id:</b>")
 
99
        label.set_markup("<b>Committer:</b>")
273
100
        align.add(label)
274
101
        self.table.attach(align, 0, 1, 0, 1, gtk.FILL, gtk.FILL)
275
102
        align.show()
276
103
        label.show()
277
104
 
278
105
        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
 
 
305
 
        align = gtk.Alignment(1.0, 0.5)
306
 
        label = gtk.Label()
307
 
        label.set_markup("<b>Committer:</b>")
308
 
        align.add(label)
309
 
        self.table.attach(align, 0, 1, 2, 3, gtk.FILL, gtk.FILL)
310
 
        align.show()
311
 
        label.show()
312
 
 
313
 
        align = gtk.Alignment(0.0, 0.5)
314
106
        self.committer = gtk.Label()
315
107
        self.committer.set_selectable(True)
316
108
        align.add(self.committer)
317
 
        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)
318
110
        align.show()
319
111
        self.committer.show()
320
112
 
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
 
 
337
113
        align = gtk.Alignment(1.0, 0.5)
338
114
        label = gtk.Label()
339
115
        label.set_markup("<b>Timestamp:</b>")
340
116
        align.add(label)
341
 
        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)
342
118
        align.show()
343
119
        label.show()
344
120
 
346
122
        self.timestamp = gtk.Label()
347
123
        self.timestamp.set_selectable(True)
348
124
        align.add(self.timestamp)
349
 
        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)
350
126
        align.show()
351
127
        self.timestamp.show()
352
128
 
353
129
        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)
 
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)
357
134
        align.show()
358
 
        self.table.attach(align, 0, 1, 5, 6, gtk.FILL, gtk.FILL)
359
 
        self.tags_label.show()
 
135
        label.show()
360
136
 
361
137
        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)
 
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)
365
142
        align.show()
366
 
        self.tags_list.show()
367
 
        self.tags_widgets = []
368
 
 
369
 
        self.connect('notify::revision', self._add_tags)
 
143
        self.revision_id.show()
370
144
 
371
145
        return self.table
372
146
 
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
 
 
410
147
    def _create_message_view(self):
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'))
 
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
443
155