/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 viz/branchwin.py

  • Committer: Jelmer Vernooij
  • Date: 2006-05-19 16:37:13 UTC
  • Revision ID: jelmer@samba.org-20060519163713-be77b31c72cbc7e8
Move visualisation code to a separate directory, preparing for bundling 
the GTK+ plugins for bzr.

Show diffs side-by-side

added added

removed removed

Lines of Context:
10
10
__author__    = "Scott James Remnant <scott@ubuntu.com>"
11
11
 
12
12
 
13
 
import os
14
 
 
15
13
import gtk
16
14
import gobject
17
15
import pango
29
27
    for a particular branch.
30
28
    """
31
29
 
32
 
    def __init__(self):
 
30
    def __init__(self, app=None):
33
31
        gtk.Window.__init__(self, gtk.WINDOW_TOPLEVEL)
34
32
        self.set_border_width(0)
35
33
        self.set_title("bzrk")
36
34
 
 
35
        self.app = app
 
36
 
37
37
        # Use three-quarters of the screen by default
38
38
        screen = self.get_screen()
39
39
        monitor = screen.get_monitor_geometry(0)
52
52
 
53
53
    def construct(self):
54
54
        """Construct the window contents."""
 
55
        vbox = gtk.VBox(spacing=0)
 
56
        self.add(vbox)
 
57
 
 
58
        vbox.pack_start(self.construct_navigation(), expand=False, fill=True)
 
59
 
55
60
        paned = gtk.VPaned()
56
61
        paned.pack1(self.construct_top(), resize=True, shrink=False)
57
 
        paned.pack2(self.construct_bottom(), resize=True, shrink=True)
58
 
        self.add(paned)
 
62
        paned.pack2(self.construct_bottom(), resize=False, shrink=True)
59
63
        paned.show()
 
64
        vbox.pack_start(paned, expand=True, fill=True)
 
65
        vbox.set_focus_child(paned)
 
66
 
 
67
        vbox.show()
60
68
 
61
69
    def construct_top(self):
62
70
        """Construct the top-half of the window."""
63
 
        vbox = gtk.VBox(spacing=6)
64
 
        vbox.set_border_width(12)
65
 
        vbox.show()
66
 
 
67
71
        scrollwin = gtk.ScrolledWindow()
68
72
        scrollwin.set_policy(gtk.POLICY_NEVER, gtk.POLICY_AUTOMATIC)
69
73
        scrollwin.set_shadow_type(gtk.SHADOW_IN)
70
 
        vbox.pack_start(scrollwin, expand=True, fill=True)
71
74
        scrollwin.show()
72
75
 
73
76
        self.treeview = gtk.TreeView()
74
77
        self.treeview.set_rules_hint(True)
75
78
        self.treeview.set_search_column(4)
76
79
        self.treeview.connect("cursor-changed", self._treeview_cursor_cb)
 
80
        self.treeview.connect("row-activated", self._treeview_row_activated_cb)
77
81
        scrollwin.add(self.treeview)
78
82
        self.treeview.show()
79
83
 
80
84
        cell = CellRendererGraph()
81
85
        column = gtk.TreeViewColumn()
82
 
        column.set_resizable(False)
 
86
        column.set_resizable(True)
83
87
        column.pack_start(cell, expand=False)
84
88
        column.add_attribute(cell, "node", 1)
85
89
        column.add_attribute(cell, "in-lines", 2)
112
116
        column.add_attribute(cell, "text", 6)
113
117
        self.treeview.append_column(column)
114
118
 
115
 
        hbox = gtk.HBox(False, spacing=6)
116
 
        vbox.pack_start(hbox, expand=False, fill=False)
 
119
        return scrollwin
 
120
 
 
121
    def construct_navigation(self):
 
122
        """Construct the navigation buttons."""
 
123
        frame = gtk.Frame()
 
124
        frame.set_shadow_type(gtk.SHADOW_OUT)
 
125
        frame.show()
 
126
        
 
127
        hbox = gtk.HBox(spacing=12)
 
128
        frame.add(hbox)
117
129
        hbox.show()
118
130
 
119
131
        self.back_button = gtk.Button(stock=gtk.STOCK_GO_BACK)
 
132
        self.back_button.set_relief(gtk.RELIEF_NONE)
120
133
        self.back_button.add_accelerator("clicked", self.accel_group, ord('['),
121
134
                                         0, 0)
122
135
        self.back_button.connect("clicked", self._back_clicked_cb)
124
137
        self.back_button.show()
125
138
 
126
139
        self.fwd_button = gtk.Button(stock=gtk.STOCK_GO_FORWARD)
 
140
        self.fwd_button.set_relief(gtk.RELIEF_NONE)
127
141
        self.fwd_button.add_accelerator("clicked", self.accel_group, ord(']'),
128
142
                                        0, 0)
129
143
        self.fwd_button.connect("clicked", self._fwd_clicked_cb)
130
144
        hbox.pack_start(self.fwd_button, expand=False, fill=True)
131
145
        self.fwd_button.show()
132
146
 
133
 
        return vbox
 
147
        return frame
134
148
 
135
149
    def construct_bottom(self):
136
150
        """Construct the bottom half of the window."""
137
 
        label = gtk.Label("test")
138
 
        label.show()
139
 
 
140
 
        return label
141
 
 
142
 
    def set_branch(self, branch, start):
 
151
        scrollwin = gtk.ScrolledWindow()
 
152
        scrollwin.set_policy(gtk.POLICY_NEVER, gtk.POLICY_AUTOMATIC)
 
153
        scrollwin.set_shadow_type(gtk.SHADOW_NONE)
 
154
        (width, height) = self.get_size()
 
155
        scrollwin.set_size_request(width, int(height / 2.5))
 
156
        scrollwin.show()
 
157
 
 
158
        vbox = gtk.VBox(False, spacing=6)
 
159
        vbox.set_border_width(6)
 
160
        scrollwin.add_with_viewport(vbox)
 
161
        vbox.show()
 
162
 
 
163
        table = gtk.Table(rows=4, columns=2)
 
164
        table.set_row_spacings(6)
 
165
        table.set_col_spacings(6)
 
166
        vbox.pack_start(table, expand=False, fill=True)
 
167
        table.show()
 
168
 
 
169
        align = gtk.Alignment(0.0, 0.5)
 
170
        label = gtk.Label()
 
171
        label.set_markup("<b>Revision:</b>")
 
172
        align.add(label)
 
173
        table.attach(align, 0, 1, 0, 1, gtk.FILL, gtk.FILL)
 
174
        label.show()
 
175
        align.show()
 
176
 
 
177
        align = gtk.Alignment(0.0, 0.5)
 
178
        self.revid_label = gtk.Label()
 
179
        self.revid_label.set_selectable(True)
 
180
        align.add(self.revid_label)
 
181
        table.attach(align, 1, 2, 0, 1, gtk.EXPAND | gtk.FILL, gtk.FILL)
 
182
        self.revid_label.show()
 
183
        align.show()
 
184
 
 
185
        align = gtk.Alignment(0.0, 0.5)
 
186
        label = gtk.Label()
 
187
        label.set_markup("<b>Committer:</b>")
 
188
        align.add(label)
 
189
        table.attach(align, 0, 1, 1, 2, gtk.FILL, gtk.FILL)
 
190
        label.show()
 
191
        align.show()
 
192
 
 
193
        align = gtk.Alignment(0.0, 0.5)
 
194
        self.committer_label = gtk.Label()
 
195
        self.committer_label.set_selectable(True)
 
196
        align.add(self.committer_label)
 
197
        table.attach(align, 1, 2, 1, 2, gtk.EXPAND | gtk.FILL, gtk.FILL)
 
198
        self.committer_label.show()
 
199
        align.show()
 
200
 
 
201
        align = gtk.Alignment(0.0, 0.5)
 
202
        label = gtk.Label()
 
203
        label.set_markup("<b>Branch nick:</b>")
 
204
        align.add(label)
 
205
        table.attach(align, 0, 1, 2, 3, gtk.FILL, gtk.FILL)
 
206
        label.show()
 
207
        align.show()
 
208
 
 
209
        align = gtk.Alignment(0.0, 0.5)
 
210
        self.branchnick_label = gtk.Label()
 
211
        self.branchnick_label.set_selectable(True)
 
212
        align.add(self.branchnick_label)
 
213
        table.attach(align, 1, 2, 2, 3, gtk.EXPAND | gtk.FILL, gtk.FILL)
 
214
        self.branchnick_label.show()
 
215
        align.show()
 
216
 
 
217
        align = gtk.Alignment(0.0, 0.5)
 
218
        label = gtk.Label()
 
219
        label.set_markup("<b>Timestamp:</b>")
 
220
        align.add(label)
 
221
        table.attach(align, 0, 1, 3, 4, gtk.FILL, gtk.FILL)
 
222
        label.show()
 
223
        align.show()
 
224
 
 
225
        align = gtk.Alignment(0.0, 0.5)
 
226
        self.timestamp_label = gtk.Label()
 
227
        self.timestamp_label.set_selectable(True)
 
228
        align.add(self.timestamp_label)
 
229
        table.attach(align, 1, 2, 3, 4, gtk.EXPAND | gtk.FILL, gtk.FILL)
 
230
        self.timestamp_label.show()
 
231
        align.show()
 
232
 
 
233
        self.parents_table = gtk.Table(rows=1, columns=2)
 
234
        self.parents_table.set_row_spacings(3)
 
235
        self.parents_table.set_col_spacings(6)
 
236
        self.parents_table.show()
 
237
        vbox.pack_start(self.parents_table, expand=False, fill=True)
 
238
        self.parents_widgets = []
 
239
 
 
240
        label = gtk.Label()
 
241
        label.set_markup("<b>Parents:</b>")
 
242
        align = gtk.Alignment(0.0, 0.5)
 
243
        align.add(label)
 
244
        self.parents_table.attach(align, 0, 1, 0, 1, gtk.FILL, gtk.FILL)
 
245
        label.show()
 
246
        align.show()
 
247
 
 
248
        self.message_buffer = gtk.TextBuffer()
 
249
        textview = gtk.TextView(self.message_buffer)
 
250
        textview.set_editable(False)
 
251
        textview.set_wrap_mode(gtk.WRAP_WORD)
 
252
        textview.modify_font(pango.FontDescription("Monospace"))
 
253
        vbox.pack_start(textview, expand=True, fill=True)
 
254
        textview.show()
 
255
 
 
256
        return scrollwin
 
257
 
 
258
    def set_branch(self, branch, start, maxnum):
143
259
        """Set the branch and start position for this window.
144
260
 
145
261
        Creates a new TreeModel and populates it with information about
146
262
        the new branch before updating the window title and model of the
147
263
        treeview itself.
148
264
        """
 
265
        self.branch = branch
 
266
 
149
267
        # [ revision, node, last_lines, lines, message, committer, timestamp ]
150
268
        self.model = gtk.ListStore(gobject.TYPE_PYOBJECT,
151
269
                                   gobject.TYPE_PYOBJECT,
156
274
        index = 0
157
275
 
158
276
        last_lines = []
159
 
        (revids, self.revisions, colours, self.children) \
160
 
                 = distances(branch, start)
161
 
        for revision, node, lines in graph(revids, self.revisions, colours):
 
277
        (self.revisions, colours, self.children, self.parent_ids,
 
278
         merge_sorted) = distances(branch, start)
 
279
        for (index, (revision, node, lines)) in enumerate(graph(
 
280
                self.revisions, colours, merge_sorted)):
 
281
            # FIXME: at this point we should be able to show the graph order
 
282
            # and lines with no message or commit data - and then incrementally
 
283
            # fill the timestamp, committer etc data as desired.
162
284
            message = revision.message.split("\n")[0]
163
285
            if revision.committer is not None:
164
286
                timestamp = format_date(revision.timestamp, revision.timezone)
165
287
            else:
166
288
                timestamp = None
167
 
 
168
 
            self.model.append([ revision, node, last_lines, lines,
169
 
                                message, revision.committer, timestamp ])
 
289
            self.model.append([revision, node, last_lines, lines,
 
290
                               message, revision.committer, timestamp])
170
291
            self.index[revision] = index
171
 
            index += 1
172
 
 
173
292
            last_lines = lines
 
293
            if maxnum is not None and index > maxnum:
 
294
                break
174
295
 
175
 
        self.set_title(os.path.basename(branch.base) + " - bzrk")
 
296
        self.set_title(branch.nick + " - bzrk")
176
297
        self.treeview.set_model(self.model)
177
298
 
178
299
    def _treeview_cursor_cb(self, *args):
180
301
        (path, col) = self.treeview.get_cursor()
181
302
        revision = self.model[path][0]
182
303
 
183
 
        self.back_button.set_sensitive(len(revision.parent_ids) > 0)
 
304
        self.back_button.set_sensitive(len(self.parent_ids[revision]) > 0)
184
305
        self.fwd_button.set_sensitive(len(self.children[revision]) > 0)
185
306
 
 
307
        if revision.committer is not None:
 
308
            branchnick = ""
 
309
            committer = revision.committer
 
310
            timestamp = format_date(revision.timestamp, revision.timezone)
 
311
            message = revision.message
 
312
            try:
 
313
                branchnick = revision.properties['branch-nick']
 
314
            except KeyError:
 
315
                pass
 
316
 
 
317
        else:
 
318
            committer = ""
 
319
            timestamp = ""
 
320
            message = ""
 
321
            branchnick = ""
 
322
 
 
323
        self.revid_label.set_text(revision.revision_id)
 
324
        self.branchnick_label.set_text(branchnick)
 
325
 
 
326
        self.committer_label.set_text(committer)
 
327
        self.timestamp_label.set_text(timestamp)
 
328
        self.message_buffer.set_text(message)
 
329
 
 
330
        for widget in self.parents_widgets:
 
331
            self.parents_table.remove(widget)
 
332
 
 
333
        self.parents_widgets = []
 
334
        self.parents_table.resize(max(len(self.parent_ids[revision]), 1), 2)
 
335
        
 
336
        for idx, parent_id in enumerate(self.parent_ids[revision]):
 
337
            align = gtk.Alignment(0.0, 0.0)
 
338
            self.parents_widgets.append(align)
 
339
            self.parents_table.attach(align, 1, 2, idx, idx + 1,
 
340
                                      gtk.EXPAND | gtk.FILL, gtk.FILL)
 
341
            align.show()
 
342
 
 
343
            hbox = gtk.HBox(False, spacing=6)
 
344
            align.add(hbox)
 
345
            hbox.show()
 
346
 
 
347
            image = gtk.Image()
 
348
            image.set_from_stock(
 
349
                gtk.STOCK_JUMP_TO, gtk.ICON_SIZE_SMALL_TOOLBAR)
 
350
            image.show()
 
351
 
 
352
            button = gtk.Button()
 
353
            button.add(image)
 
354
            button.connect("clicked", self._go_clicked_cb, parent_id)
 
355
            hbox.pack_start(button, expand=False, fill=True)
 
356
            button.show()
 
357
 
 
358
            image = gtk.Image()
 
359
            image.set_from_stock(
 
360
                gtk.STOCK_FIND, gtk.ICON_SIZE_SMALL_TOOLBAR)
 
361
            image.show()
 
362
 
 
363
            button = gtk.Button()
 
364
            button.add(image)
 
365
            button.set_sensitive(self.app is not None)
 
366
            button.connect("clicked", self._show_clicked_cb,
 
367
                           revision.revision_id, parent_id)
 
368
            hbox.pack_start(button, expand=False, fill=True)
 
369
            button.show()
 
370
 
 
371
            label = gtk.Label(parent_id)
 
372
            label.set_selectable(True)
 
373
            hbox.pack_start(label, expand=False, fill=True)
 
374
            label.show()
 
375
 
 
376
 
186
377
    def _back_clicked_cb(self, *args):
187
378
        """Callback for when the back button is clicked."""
188
379
        (path, col) = self.treeview.get_cursor()
189
380
        revision = self.model[path][0]
190
 
        if not len(revision.parent_ids):
 
381
        if not len(self.parent_ids[revision]):
191
382
            return
192
383
 
193
 
        for parent_id in revision.parent_ids:
 
384
        for parent_id in self.parent_ids[revision]:
194
385
            parent = self.revisions[parent_id]
195
386
            if same_branch(revision, parent):
196
387
                self.treeview.set_cursor(self.index[parent])
197
388
                break
198
389
        else:
199
 
            next = self.revisions[revision.parent_ids[0]]
 
390
            next = self.revisions[self.parent_ids[revision][0]]
200
391
            self.treeview.set_cursor(self.index[next])
 
392
        self.treeview.grab_focus()
201
393
 
202
394
    def _fwd_clicked_cb(self, *args):
203
395
        """Callback for when the forward button is clicked."""
213
405
        else:
214
406
            prev = list(self.children[revision])[0]
215
407
            self.treeview.set_cursor(self.index[prev])
 
408
        self.treeview.grab_focus()
 
409
 
 
410
    def _go_clicked_cb(self, widget, revid):
 
411
        """Callback for when the go button for a parent is clicked."""
 
412
        self.treeview.set_cursor(self.index[self.revisions[revid]])
 
413
        self.treeview.grab_focus()
 
414
 
 
415
    def _show_clicked_cb(self, widget, revid, parentid):
 
416
        """Callback for when the show button for a parent is clicked."""
 
417
        if self.app is not None:
 
418
            self.app.show_diff(self.branch, revid, parentid)
 
419
        self.treeview.grab_focus()
 
420
 
 
421
    def _treeview_row_activated_cb(self, widget, path, col):
 
422
        # TODO: more than one parent
 
423
        """Callback for when a treeview row gets activated."""
 
424
        revision = self.model[path][0]
 
425
        parent_id = self.parent_ids[revision][0]
 
426
        if self.app is not None:
 
427
            self.app.show_diff(self.branch, revision.revision_id, parent_id)
 
428
        self.treeview.grab_focus()