/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: Curtis Hovey
  • Date: 2011-08-01 14:46:23 UTC
  • mto: This revision was merged to the branch mainline in revision 741.
  • Revision ID: sinzui.is@verizon.net-20110801144623-ldjf0bu7kyi5bxzu
Updated commit to gtk3.

Show diffs side-by-side

added added

removed removed

Lines of Context:
16
16
 
17
17
import time
18
18
 
19
 
import pygtk
20
 
pygtk.require("2.0")
21
 
import gobject
22
 
import gtk
23
 
import pango
 
19
from gi.repository import GObject
 
20
from gi.repository import Gtk
 
21
from gi.repository import Pango
24
22
import re
25
23
 
26
 
from bzrlib import patiencediff, tsort
 
24
from bzrlib import patiencediff
27
25
from bzrlib.errors import NoSuchRevision
28
26
from bzrlib.revision import NULL_REVISION, CURRENT_REVISION
29
27
 
30
 
from colormap import AnnotateColorMap, AnnotateColorSaturation
 
28
from bzrlib.plugins.gtk.annotate.colormap import AnnotateColorSaturation
31
29
from bzrlib.plugins.gtk.revisionview import RevisionView
32
30
from bzrlib.plugins.gtk.window import Window
33
31
 
49
47
        self.all = all
50
48
        self.plain = plain
51
49
        self._branch = branch
52
 
        
 
50
 
53
51
        Window.__init__(self, parent)
54
 
        
55
 
        self.set_icon(self.render_icon(gtk.STOCK_FIND, gtk.ICON_SIZE_BUTTON))
 
52
 
 
53
        self.set_icon(self.render_icon(Gtk.STOCK_FIND, Gtk.IconSize.BUTTON))
56
54
        self.annotate_colormap = AnnotateColorSaturation()
57
55
 
58
56
        self._create()
68
66
        self.revisionview.set_file_id(file_id)
69
67
        self.revision_id = getattr(tree, 'get_revision_id', 
70
68
                                   lambda: CURRENT_REVISION)()
71
 
        
 
69
 
72
70
        # [revision id, line number, author, revno, highlight color, line]
73
 
        self.annomodel = gtk.ListStore(gobject.TYPE_STRING,
74
 
                                       gobject.TYPE_STRING,
75
 
                                       gobject.TYPE_STRING,
76
 
                                       gobject.TYPE_STRING,
77
 
                                       gobject.TYPE_STRING,
78
 
                                       gobject.TYPE_STRING)
79
 
        
 
71
        self.annomodel = Gtk.ListStore(GObject.TYPE_STRING,
 
72
                                       GObject.TYPE_INT,
 
73
                                       GObject.TYPE_STRING,
 
74
                                       GObject.TYPE_STRING,
 
75
                                       GObject.TYPE_STRING,
 
76
                                       GObject.TYPE_STRING)
 
77
 
80
78
        last_seen = None
81
79
        try:
82
80
            branch.lock_read()
86
84
            for revision_id, revno in revno_map.iteritems():
87
85
                self.dotted[revision_id] = '.'.join(str(num) for num in revno)
88
86
            for line_no, (revision, revno, line)\
89
 
                    in enumerate(self._annotate(tree, file_id)):
 
87
                in enumerate(self._annotate(tree, file_id)):
90
88
                if revision.revision_id == last_seen and not self.all:
91
89
                    revno = author = ""
92
90
                else:
93
91
                    last_seen = revision.revision_id
94
 
                    author = revision.get_apparent_author()
 
92
                    author = ", ".join(revision.get_apparent_authors())
95
93
 
96
94
                if revision.revision_id not in self.revisions:
97
95
                    self.revisions[revision.revision_id] = revision
102
100
                                       revno,
103
101
                                       None,
104
102
                                       line.rstrip("\r\n")
105
 
                                      ])
 
103
                                       ])
106
104
                self.annotations.append(revision)
107
105
 
108
106
            if not self.plain:
125
123
            # bar?
126
124
            print("gannotate: Line number %d does't exist. Defaulting to "
127
125
                  "line 1." % lineno)
128
 
            return
 
126
            return
129
127
        else:
130
128
            row = lineno - 1
131
129
 
139
137
        current_revision.timestamp = time.time()
140
138
        current_revision.message = '[Not yet committed]'
141
139
        current_revision.parent_ids = tree.get_parent_ids()
142
 
        current_revision.properties['branch-nick'] = self.branch.nick
 
140
        current_revision.properties['branch-nick'] = self.branch._get_nick(local=True)
143
141
        current_revno = '%d?' % (self.branch.revno() + 1)
144
142
        repository = self.branch.repository
145
143
        if self.revision_id == CURRENT_REVISION:
193
191
        self.revisionview = self._create_log_view()
194
192
        self.annoview = self._create_annotate_view()
195
193
 
196
 
        vbox = gtk.VBox(False)
 
194
        vbox = Gtk.VBox(False)
197
195
        vbox.show()
198
196
 
199
 
        sw = gtk.ScrolledWindow()
200
 
        sw.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
201
 
        sw.set_shadow_type(gtk.SHADOW_IN)
 
197
        sw = Gtk.ScrolledWindow()
 
198
        sw.set_policy(Gtk.PolicyType.AUTOMATIC, Gtk.PolicyType.AUTOMATIC)
 
199
        sw.set_shadow_type(Gtk.ShadowType.IN)
202
200
        sw.add(self.annoview)
203
201
        self.annoview.gwindow = self
204
202
        sw.show()
205
203
 
206
 
        swbox = gtk.VBox()
207
 
        swbox.pack_start(sw)
 
204
        swbox = Gtk.VBox()
 
205
        swbox.pack_start(sw, True, True, 0)
208
206
        swbox.show()
209
207
 
210
 
        hbox = gtk.HBox(False, 6)
 
208
        hbox = Gtk.HBox(False, 6)
211
209
        self.back_button = self._create_back_button()
212
210
        hbox.pack_start(self.back_button, expand=False, fill=True)
213
211
        self.forward_button = self._create_forward_button()
214
212
        hbox.pack_start(self.forward_button, expand=False, fill=True)
 
213
        self.find_button = self._create_find_button()
 
214
        hbox.pack_start(self.find_button, expand=False, fill=True)
 
215
        self.goto_button = self._create_goto_button()
 
216
        hbox.pack_start(self.goto_button, expand=False, fill=True)
215
217
        hbox.show()
216
218
        vbox.pack_start(hbox, expand=False, fill=True)
217
 
        
218
 
        self.pane = pane = gtk.VPaned()
 
219
 
 
220
        self.pane = pane = Gtk.VPaned()
219
221
        pane.add1(swbox)
220
222
        pane.add2(self.revisionview)
221
223
        pane.show()
223
225
 
224
226
        self._search = SearchBox()
225
227
        swbox.pack_start(self._search, expand=False, fill=True)
226
 
        accels = gtk.AccelGroup()
227
 
        accels.connect_group(gtk.keysyms.f, gtk.gdk.CONTROL_MASK,
228
 
                             gtk.ACCEL_LOCKED,
 
228
        accels = Gtk.AccelGroup()
 
229
        accels.connect_group(Gdk.KEY_f, Gdk.EventMask.CONTROL_MASK,
 
230
                             Gtk.ACCEL_LOCKED,
229
231
                             self._search_by_text)
230
 
        accels.connect_group(gtk.keysyms.g, gtk.gdk.CONTROL_MASK,
231
 
                             gtk.ACCEL_LOCKED,
 
232
        accels.connect_group(Gdk.KEY_g, Gdk.EventMask.CONTROL_MASK,
 
233
                             Gtk.ACCEL_LOCKED,
232
234
                             self._search_by_line)
233
235
        self.add_accel_group(accels)
234
236
 
235
237
        self.add(vbox)
236
238
 
237
 
    def _search_by_text(self, accel_group, window, key, modifiers):
 
239
    def _search_by_text(self, *ignored): # (accel_group, window, key, modifiers):
238
240
        self._search.show_for('text')
239
241
        self._search.set_target(self.annoview, TEXT_LINE_COL)
240
242
 
241
 
    def _search_by_line(self, accel_group, window, key, modifiers):
 
243
    def _search_by_line(self, *ignored): # accel_group, window, key, modifiers):
242
244
        self._search.show_for('line')
243
245
        self._search.set_target(self.annoview, LINE_NUM_COL)
244
246
 
256
258
            else:
257
259
                tree2 = repository.revision_tree(NULL_REVISION)
258
260
        from bzrlib.plugins.gtk.diff import DiffWindow
259
 
        window = DiffWindow()
 
261
        window = DiffWindow(self)
260
262
        window.set_diff("Diff for line %d" % (row+1), tree1, tree2)
261
263
        window.set_file(tree1.id2path(self.file_id))
262
264
        window.show()
263
265
 
264
266
 
265
267
    def _create_annotate_view(self):
266
 
        tv = gtk.TreeView()
 
268
        tv = Gtk.TreeView()
267
269
        tv.set_rules_hint(False)
268
270
        tv.connect("cursor-changed", self._activate_selected_revision)
269
271
        tv.show()
270
272
        tv.connect("row-activated", self.line_diff)
271
273
 
272
 
        cell = gtk.CellRendererText()
 
274
        cell = Gtk.CellRendererText()
273
275
        cell.set_property("xalign", 1.0)
274
276
        cell.set_property("ypad", 0)
275
277
        cell.set_property("family", "Monospace")
276
278
        cell.set_property("cell-background-gdk",
277
 
                          tv.get_style().bg[gtk.STATE_NORMAL])
278
 
        col = gtk.TreeViewColumn()
 
279
                          tv.get_style().bg[Gtk.StateType.NORMAL])
 
280
        col = Gtk.TreeViewColumn()
279
281
        col.set_resizable(False)
280
 
        col.pack_start(cell, expand=True)
 
282
        col.pack_start(cell, True, True, 0)
281
283
        col.add_attribute(cell, "text", LINE_NUM_COL)
282
284
        tv.append_column(col)
283
285
 
284
 
        cell = gtk.CellRendererText()
 
286
        cell = Gtk.CellRendererText()
285
287
        cell.set_property("ypad", 0)
286
 
        cell.set_property("ellipsize", pango.ELLIPSIZE_END)
 
288
        cell.set_property("ellipsize", Pango.EllipsizeMode.END)
287
289
        cell.set_property("cell-background-gdk",
288
 
                          self.get_style().bg[gtk.STATE_NORMAL])
289
 
        col = gtk.TreeViewColumn("Committer")
 
290
                          self.get_style().bg[Gtk.StateType.NORMAL])
 
291
        col = Gtk.TreeViewColumn("Committer")
290
292
        col.set_resizable(True)
291
 
        col.pack_start(cell, expand=True)
 
293
        col.pack_start(cell, True, True, 0)
292
294
        col.add_attribute(cell, "text", COMMITTER_COL)
293
295
        tv.append_column(col)
294
296
 
295
 
        cell = gtk.CellRendererText()
 
297
        cell = Gtk.CellRendererText()
296
298
        cell.set_property("xalign", 1.0)
297
299
        cell.set_property("ypad", 0)
298
300
        cell.set_property("cell-background-gdk",
299
 
                          self.get_style().bg[gtk.STATE_NORMAL])
300
 
        col = gtk.TreeViewColumn("Revno")
 
301
                          self.get_style().bg[Gtk.StateType.NORMAL])
 
302
        col = Gtk.TreeViewColumn("Revno")
301
303
        col.set_resizable(False)
302
 
        col.pack_start(cell, expand=True)
 
304
        col.pack_start(cell, True, True, 0)
303
305
        col.add_attribute(cell, "markup", REVNO_COL)
304
306
        tv.append_column(col)
305
307
 
306
 
        cell = gtk.CellRendererText()
 
308
        cell = Gtk.CellRendererText()
307
309
        cell.set_property("ypad", 0)
308
310
        cell.set_property("family", "Monospace")
309
 
        col = gtk.TreeViewColumn()
 
311
        col = Gtk.TreeViewColumn()
310
312
        col.set_resizable(False)
311
 
        col.pack_start(cell, expand=True)
 
313
        col.pack_start(cell, True, True, 0)
312
314
#        col.add_attribute(cell, "foreground", HIGHLIGHT_COLOR_COL)
313
315
        col.add_attribute(cell, "background", HIGHLIGHT_COLOR_COL)
314
316
        col.add_attribute(cell, "text", TEXT_LINE_COL)
315
317
        tv.append_column(col)
316
318
 
317
 
        # FIXME: Now that C-f is now used for search by text we
318
 
        # may as well disable the auto search.
319
 
        tv.set_search_column(LINE_NUM_COL)
 
319
        # interactive substring search
 
320
        def search_equal_func(model, column, key, iter):
 
321
            return model.get_value(iter, TEXT_LINE_COL).lower().find(key.lower()) == -1
 
322
 
 
323
        tv.set_enable_search(True)
 
324
        tv.set_search_equal_func(search_equal_func)
320
325
 
321
326
        return tv
322
327
 
326
331
        return lv
327
332
 
328
333
    def _create_back_button(self):
329
 
        button = gtk.Button()
 
334
        button = Gtk.Button()
330
335
        button.set_use_stock(True)
331
336
        button.set_label("gtk-go-back")
332
337
        button.connect("clicked", lambda w: self.go_back())
333
 
        button.set_relief(gtk.RELIEF_NONE)
 
338
        button.set_relief(Gtk.ReliefStyle.NONE)
334
339
        button.show()
335
340
        return button
336
341
 
337
342
    def _create_forward_button(self):
338
 
        button = gtk.Button()
 
343
        button = Gtk.Button()
339
344
        button.set_use_stock(True)
340
345
        button.set_label("gtk-go-forward")
341
346
        button.connect("clicked", lambda w: self.go_forward())
342
 
        button.set_relief(gtk.RELIEF_NONE)
 
347
        button.set_relief(Gtk.ReliefStyle.NONE)
343
348
        button.show()
344
349
        button.set_sensitive(False)
345
350
        return button
346
351
 
 
352
    def _create_find_button(self):
 
353
        button = Gtk.Button()
 
354
        button.set_use_stock(True)
 
355
        button.set_label("gtk-find")
 
356
        button.set_tooltip_text("Search for text (Ctrl+F)")
 
357
        button.connect("clicked", self._search_by_text)
 
358
        button.set_relief(Gtk.ReliefStyle.NONE)
 
359
        button.show()
 
360
        button.set_sensitive(True)
 
361
        return button
 
362
 
 
363
    def _create_goto_button(self):
 
364
        button = Gtk.Button()
 
365
        button.set_label("Goto Line")
 
366
        button.set_tooltip_text("Scroll to a line by entering its number (Ctrl+G)")
 
367
        button.connect("clicked", self._search_by_line)
 
368
        button.set_relief(Gtk.ReliefStyle.NONE)
 
369
        button.show()
 
370
        button.set_sensitive(True)
 
371
        return button
 
372
 
347
373
    def go_back(self):
348
374
        last_tree = self.tree
349
375
        rev_id = self._selected_revision()
389
415
                return j - i
390
416
 
391
417
 
392
 
class FakeRevision:
 
418
class FakeRevision(object):
393
419
    """ A fake revision.
394
420
 
395
421
    For when a revision is referenced but not present.
404
430
        self.timezone = 0
405
431
        self.properties = {}
406
432
 
407
 
    def get_apparent_author(self):
408
 
        return self.committer
 
433
    def get_apparent_authors(self):
 
434
        return [self.committer]
409
435
 
410
436
 
411
437
class RevisionCache(object):
412
438
    """A caching revision source"""
 
439
 
413
440
    def __init__(self, real_source, seed_cache=None):
414
441
        self.__real_source = real_source
415
442
        if seed_cache is None:
423
450
            self.__cache[revision_id] = revision
424
451
        return self.__cache[revision_id]
425
452
 
426
 
class SearchBox(gtk.HBox):
 
453
class SearchBox(Gtk.HBox):
427
454
    """A button box for searching in text or lines of annotations"""
428
455
    def __init__(self):
429
 
        gtk.HBox.__init__(self, False, 6)
 
456
        GObject.GObject.__init__(self, False, 6)
430
457
 
431
458
        # Close button
432
 
        button = gtk.Button()
433
 
        image = gtk.Image()
434
 
        image.set_from_stock('gtk-stop', gtk.ICON_SIZE_BUTTON)
 
459
        button = Gtk.Button()
 
460
        image = Gtk.Image()
 
461
        image.set_from_stock('gtk-stop', Gtk.IconSize.BUTTON)
435
462
        button.set_image(image)
436
 
        button.set_relief(gtk.RELIEF_NONE)
 
463
        button.set_relief(Gtk.ReliefStyle.NONE)
437
464
        button.connect("clicked", lambda w: self.hide_all())
438
465
        self.pack_start(button, expand=False, fill=False)
439
466
 
440
467
        # Search entry
441
 
        label = gtk.Label()
 
468
        label = Gtk.Label()
442
469
        self._label = label
443
470
        self.pack_start(label, expand=False, fill=False)
444
471
 
445
 
        entry = gtk.Entry()
 
472
        entry = Gtk.Entry()
446
473
        self._entry = entry
447
474
        entry.connect("activate", lambda w, d: self._do_search(d),
448
475
                      'forward')
449
476
        self.pack_start(entry, expand=False, fill=False)
450
477
 
451
478
        # Next/previous buttons
452
 
        button = gtk.Button('_Next')
453
 
        image = gtk.Image()
454
 
        image.set_from_stock('gtk-go-forward', gtk.ICON_SIZE_BUTTON)
 
479
        button = Gtk.Button('_Next')
 
480
        image = Gtk.Image()
 
481
        image.set_from_stock('gtk-go-forward', Gtk.IconSize.BUTTON)
455
482
        button.set_image(image)
456
483
        button.connect("clicked", lambda w, d: self._do_search(d),
457
484
                       'forward')
458
485
        self.pack_start(button, expand=False, fill=False)
459
486
 
460
 
        button = gtk.Button('_Previous')
461
 
        image = gtk.Image()
462
 
        image.set_from_stock('gtk-go-back', gtk.ICON_SIZE_BUTTON)
 
487
        button = Gtk.Button('_Previous')
 
488
        image = Gtk.Image()
 
489
        image.set_from_stock('gtk-go-back', Gtk.IconSize.BUTTON)
463
490
        button.set_image(image)
464
491
        button.connect("clicked", lambda w, d: self._do_search(d),
465
492
                       'backward')
466
493
        self.pack_start(button, expand=False, fill=False)
467
494
 
468
495
        # Search options
469
 
        check = gtk.CheckButton('Match case')
 
496
        check = Gtk.CheckButton('Match case')
470
497
        self._match_case = check
471
498
        self.pack_start(check, expand=False, fill=False)
472
499
 
473
 
        check = gtk.CheckButton('Regexp')
 
500
        check = Gtk.CheckButton('Regexp')
474
501
        check.connect("toggled", lambda w: self._set_label())
475
502
        self._regexp = check
476
503
        self.pack_start(check, expand=False, fill=False)
506
533
 
507
534
    def _match(self, model, iterator, column):
508
535
        matching_case = self._match_case.get_active()
509
 
        string, = model.get(iterator, column)
 
536
        cell_value, = model.get(iterator, column)
510
537
        key = self._entry.get_text()
511
 
        if self._regexp.get_active():
 
538
        if column == LINE_NUM_COL:
 
539
            # FIXME: For goto-line there are faster algorithms than searching 
 
540
            # every line til we find the right one! -- mbp 2011-01-27
 
541
            return key.strip() == str(cell_value)
 
542
        elif self._regexp.get_active():
512
543
            if matching_case:
513
 
                match = re.compile(key).search(string, 1)
 
544
                match = re.compile(key).search(cell_value, 1)
514
545
            else:
515
 
                match = re.compile(key, re.I).search(string, 1)
 
546
                match = re.compile(key, re.I).search(cell_value, 1)
516
547
        else:
517
548
            if not matching_case:
518
 
                string = string.lower()
 
549
                cell_value = cell_value.lower()
519
550
                key = key.lower()
520
 
            match = string.find(key) != -1
 
551
            match = cell_value.find(key) != -1
521
552
 
522
553
        return match
523
554