/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/gannotate.py

  • Committer: Jelmer Vernooij
  • Date: 2008-03-14 02:13:27 UTC
  • mto: (452.2.2 trunk)
  • mto: This revision was merged to the branch mainline in revision 453.
  • Revision ID: jelmer@samba.org-20080314021327-q1pabtpneeasz8qv
Fix support for default value in BranchSelectionDialog.

Show diffs side-by-side

added added

removed removed

Lines of Context:
28
28
from bzrlib.revision import NULL_REVISION, CURRENT_REVISION
29
29
 
30
30
from colormap import AnnotateColorMap, AnnotateColorSaturation
31
 
from bzrlib.plugins.gtk.logview import LogView
 
31
from bzrlib.plugins.gtk.revisionview import RevisionView
 
32
from bzrlib.plugins.gtk.window import Window
32
33
 
33
34
 
34
35
(
41
42
) = range(6)
42
43
 
43
44
 
44
 
class GAnnotateWindow(gtk.Window):
 
45
class GAnnotateWindow(Window):
45
46
    """Annotate window."""
46
47
 
47
 
    def __init__(self, all=False, plain=False):
 
48
    def __init__(self, all=False, plain=False, parent=None):
48
49
        self.all = all
49
50
        self.plain = plain
50
51
        
51
 
        gtk.Window.__init__(self, gtk.WINDOW_TOPLEVEL)
 
52
        Window.__init__(self, parent)
52
53
        
53
54
        self.set_icon(self.render_icon(gtk.STOCK_FIND, gtk.ICON_SIZE_BUTTON))
54
55
        self.annotate_colormap = AnnotateColorSaturation()
55
56
 
56
57
        self._create()
57
58
        self.revisions = {}
 
59
        self.history = []
 
60
        self._no_back = set()
58
61
 
59
62
    def annotate(self, tree, branch, file_id):
60
63
        self.annotations = []
61
64
        self.branch = branch
62
65
        self.tree = tree
63
66
        self.file_id = file_id
 
67
        self.revisionview.set_file_id(file_id)
64
68
        self.revision_id = getattr(tree, 'get_revision_id', 
65
69
                                   lambda: CURRENT_REVISION)()
66
70
        
67
 
        # [revision id, line number, committer, revno, highlight color, line]
 
71
        # [revision id, line number, author, revno, highlight color, line]
68
72
        self.annomodel = gtk.ListStore(gobject.TYPE_STRING,
69
73
                                       gobject.TYPE_STRING,
70
74
                                       gobject.TYPE_STRING,
76
80
        try:
77
81
            branch.lock_read()
78
82
            branch.repository.lock_read()
 
83
            self.dotted = {}
 
84
            revno_map = self.branch.get_revision_id_to_revno_map()
 
85
            for revision_id, revno in revno_map.iteritems():
 
86
                self.dotted[revision_id] = '.'.join(str(num) for num in revno)
79
87
            for line_no, (revision, revno, line)\
80
88
                    in enumerate(self._annotate(tree, file_id)):
81
89
                if revision.revision_id == last_seen and not self.all:
82
 
                    revno = committer = ""
 
90
                    revno = author = ""
83
91
                else:
84
92
                    last_seen = revision.revision_id
85
 
                    committer = revision.committer
 
93
                    author = revision.get_apparent_author()
86
94
 
87
95
                if revision.revision_id not in self.revisions:
88
96
                    self.revisions[revision.revision_id] = revision
89
97
 
90
98
                self.annomodel.append([revision.revision_id,
91
99
                                       line_no + 1,
92
 
                                       committer,
 
100
                                       author,
93
101
                                       revno,
94
102
                                       None,
95
103
                                       line.rstrip("\r\n")
105
113
 
106
114
        self.annoview.set_model(self.annomodel)
107
115
        self.annoview.grab_focus()
 
116
        my_revno = self.dotted.get(self.revision_id, 'current')
 
117
        title = '%s (%s) - gannotate' % (self.tree.id2path(file_id), my_revno)
 
118
        self.set_title(title)
108
119
 
109
120
    def jump_to_line(self, lineno):
110
121
        if lineno > len(self.annomodel) or lineno < 1:
120
131
        self.annoview.set_cursor(row)
121
132
        self.annoview.scroll_to_cell(row, use_align=True)
122
133
 
123
 
    def _dotted_revnos(self, repository, revision_id):
124
 
        """Return a dict of revision_id -> dotted revno
125
 
        
126
 
        :param repository: The repository to get the graph from
127
 
        :param revision_id: The last revision for which this info is needed
128
 
        """
129
 
        graph = repository.get_revision_graph(revision_id)
130
 
        dotted = {}
131
 
        for n, revision_id, d, revno, e in tsort.merge_sort(graph, 
132
 
            revision_id, generate_revno=True):
133
 
            dotted[revision_id] = '.'.join(str(num) for num in revno)
134
 
        return dotted
135
134
 
136
135
    def _annotate(self, tree, file_id):
137
136
        current_revision = FakeRevision(CURRENT_REVISION)
146
145
            revision_id = self.branch.last_revision()
147
146
        else:
148
147
            revision_id = self.revision_id
149
 
        dotted = self._dotted_revnos(repository, revision_id)
150
148
        revision_cache = RevisionCache(repository, self.revisions)
151
149
        for origin, text in tree.annotate_iter(file_id):
152
150
            rev_id = origin
156
154
            else:
157
155
                try:
158
156
                    revision = revision_cache.get_revision(rev_id)
159
 
                    revno = dotted.get(rev_id, 'merge')
 
157
                    revno = self.dotted.get(rev_id, 'merge')
160
158
                    if len(revno) > 15:
161
159
                        revno = 'merge'
162
160
                except NoSuchRevision:
177
175
            return None
178
176
        return self.annomodel[path][REVISION_ID_COL]
179
177
 
180
 
    def _show_log(self, w):
 
178
    def _activate_selected_revision(self, w):
181
179
        rev_id = self._selected_revision()
182
180
        if rev_id is None:
183
181
            return
184
 
        self.logview.set_revision(self.revisions[rev_id])
 
182
        selected = self.revisions[rev_id]
 
183
        self.revisionview.set_revision(selected)
 
184
        if (len(selected.parent_ids) != 0 and selected.parent_ids[0] not in
 
185
            self._no_back):
 
186
            enable_back = True
 
187
        else:
 
188
            enable_back = False
 
189
        self.back_button.set_sensitive(enable_back)
185
190
 
186
191
    def _create(self):
187
 
        self.logview = self._create_log_view()
 
192
        self.revisionview = self._create_log_view()
188
193
        self.annoview = self._create_annotate_view()
189
194
 
190
 
        vbox = gtk.VBox(False, 12)
191
 
        vbox.set_border_width(12)
 
195
        vbox = gtk.VBox(False)
192
196
        vbox.show()
193
197
 
194
198
        sw = gtk.ScrolledWindow()
197
201
        sw.add(self.annoview)
198
202
        self.annoview.gwindow = self
199
203
        sw.show()
 
204
 
 
205
        swbox = gtk.VBox()
 
206
        swbox.pack_start(sw)
 
207
        swbox.show()
 
208
 
 
209
        hbox = gtk.HBox(False, 6)
 
210
        self.back_button = self._create_back_button()
 
211
        hbox.pack_start(self.back_button, expand=False, fill=True)
 
212
        self.forward_button = self._create_forward_button()
 
213
        hbox.pack_start(self.forward_button, expand=False, fill=True)
 
214
        hbox.show()
 
215
        vbox.pack_start(hbox, expand=False, fill=True)
200
216
        
201
217
        self.pane = pane = gtk.VPaned()
202
 
        pane.add1(sw)
203
 
        pane.add2(self.logview)
 
218
        pane.add1(swbox)
 
219
        pane.add2(self.revisionview)
204
220
        pane.show()
205
221
        vbox.pack_start(pane, expand=True, fill=True)
206
222
 
207
223
        self._search = SearchBox()
208
 
        vbox.pack_start(self._search, expand=False, fill=True)
 
224
        swbox.pack_start(self._search, expand=False, fill=True)
209
225
        accels = gtk.AccelGroup()
210
226
        accels.connect_group(gtk.keysyms.f, gtk.gdk.CONTROL_MASK,
211
227
                             gtk.ACCEL_LOCKED,
215
231
                             self._search_by_line)
216
232
        self.add_accel_group(accels)
217
233
 
218
 
        hbox = gtk.HBox(True, 6)
219
 
        hbox.pack_start(self._create_prev_button(), expand=False, fill=True)
220
 
        hbox.pack_end(self._create_button_box(), expand=False, fill=True)
221
 
        hbox.show()
222
 
        vbox.pack_start(hbox, expand=False, fill=True)
223
 
 
224
234
        self.add(vbox)
225
235
 
226
236
    def _search_by_text(self, accel_group, window, key, modifiers):
231
241
        self._search.show_for('line')
232
242
        self._search.set_target(self.annoview, LINE_NUM_COL)
233
243
 
234
 
    def row_diff(self, tv, path, tvc):
 
244
    def line_diff(self, tv, path, tvc):
235
245
        row = path[0]
236
246
        revision = self.annotations[row]
237
247
        repository = self.branch.repository
246
256
                tree2 = repository.revision_tree(NULL_REVISION)
247
257
        from bzrlib.plugins.gtk.diff import DiffWindow
248
258
        window = DiffWindow()
249
 
        window.set_diff("Diff for row %d" % (row+1), tree1, tree2)
 
259
        window.set_diff("Diff for line %d" % (row+1), tree1, tree2)
250
260
        window.set_file(tree1.id2path(self.file_id))
251
261
        window.show()
252
262
 
254
264
    def _create_annotate_view(self):
255
265
        tv = gtk.TreeView()
256
266
        tv.set_rules_hint(False)
257
 
        tv.connect("cursor-changed", self._show_log)
 
267
        tv.connect("cursor-changed", self._activate_selected_revision)
258
268
        tv.show()
259
 
        tv.connect("row-activated", self.row_diff)
 
269
        tv.connect("row-activated", self.line_diff)
260
270
 
261
271
        cell = gtk.CellRendererText()
262
272
        cell.set_property("xalign", 1.0)
310
320
        return tv
311
321
 
312
322
    def _create_log_view(self):
313
 
        lv = LogView()
 
323
        lv = RevisionView()
314
324
        lv.show()
315
325
        return lv
316
326
 
317
 
    def _create_button_box(self):
318
 
        box = gtk.HButtonBox()
319
 
        box.set_layout(gtk.BUTTONBOX_END)
320
 
        box.show()
321
 
 
322
 
        button = gtk.Button()
323
 
        button.set_use_stock(True)
324
 
        button.set_label("gtk-close")
325
 
        button.connect("clicked", lambda w: self.destroy())
326
 
        button.show()
327
 
 
328
 
        box.pack_start(button, expand=False, fill=False)
329
 
 
330
 
        return box
331
 
 
332
 
    def _create_prev_button(self):
333
 
        box = gtk.HButtonBox()
334
 
        box.set_layout(gtk.BUTTONBOX_START)
335
 
        box.show()
336
 
        
 
327
    def _create_back_button(self):
337
328
        button = gtk.Button()
338
329
        button.set_use_stock(True)
339
330
        button.set_label("gtk-go-back")
340
331
        button.connect("clicked", lambda w: self.go_back())
341
 
        button.show()
342
 
        box.pack_start(button, expand=False, fill=False)
343
 
        return box
 
332
        button.set_relief(gtk.RELIEF_NONE)
 
333
        button.show()
 
334
        return button
 
335
 
 
336
    def _create_forward_button(self):
 
337
        button = gtk.Button()
 
338
        button.set_use_stock(True)
 
339
        button.set_label("gtk-go-forward")
 
340
        button.connect("clicked", lambda w: self.go_forward())
 
341
        button.set_relief(gtk.RELIEF_NONE)
 
342
        button.show()
 
343
        button.set_sensitive(False)
 
344
        return button
344
345
 
345
346
    def go_back(self):
 
347
        last_tree = self.tree
346
348
        rev_id = self._selected_revision()
347
349
        parent_id = self.revisions[rev_id].parent_ids[0]
348
 
        tree = self.branch.repository.revision_tree(parent_id)
349
 
        if self.file_id in tree:
350
 
            offset = self.get_scroll_offset(tree)
 
350
        target_tree = self.branch.repository.revision_tree(parent_id)
 
351
        if self._go(target_tree):
 
352
            self.history.append(last_tree)
 
353
            self.forward_button.set_sensitive(True)
 
354
        else:
 
355
            self._no_back.add(parent_id)
 
356
            self.back_button.set_sensitive(False)
 
357
 
 
358
    def go_forward(self):
 
359
        if len(self.history) == 0:
 
360
            return
 
361
        target_tree = self.history.pop()
 
362
        if len(self.history) == 0:
 
363
            self.forward_button.set_sensitive(False)
 
364
        self._go(target_tree)
 
365
 
 
366
    def _go(self, target_tree):
 
367
        rev_id = self._selected_revision()
 
368
        if self.file_id in target_tree:
 
369
            offset = self.get_scroll_offset(target_tree)
351
370
            (row,), col = self.annoview.get_cursor()
352
 
            self.annotate(tree, self.branch, self.file_id)
353
 
            self.annoview.set_cursor(row+offset)
 
371
            self.annotate(target_tree, self.branch, self.file_id)
 
372
            new_row = row+offset
 
373
            if new_row < 0:
 
374
                new_row = 0
 
375
            self.annoview.set_cursor(new_row)
 
376
            return True
 
377
        else:
 
378
            return False
354
379
 
355
380
    def get_scroll_offset(self, tree):
356
381
        old = self.tree.get_file(self.file_id)
363
388
                return j - i
364
389
 
365
390
 
366
 
 
367
391
class FakeRevision:
368
392
    """ A fake revision.
369
393
 
379
403
        self.timezone = 0
380
404
        self.properties = {}
381
405
 
 
406
    def get_apparent_author(self):
 
407
        return self.committer
 
408
 
382
409
 
383
410
class RevisionCache(object):
384
411
    """A caching revision source"""