/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: 2010-05-25 17:09:02 UTC
  • mto: This revision was merged to the branch mainline in revision 691.
  • Revision ID: jelmer@samba.org-20100525170902-3to8g5iw7ovw79kh
Split out olive into a separate directory.

Show diffs side-by-side

added added

removed removed

Lines of Context:
16
16
 
17
17
import time
18
18
 
19
 
from gi.repository import GObject
20
 
from gi.repository import Gtk
21
 
from gi.repository import Pango
 
19
import pygtk
 
20
pygtk.require("2.0")
 
21
import gobject
 
22
import gtk
 
23
import pango
22
24
import re
23
25
 
24
 
from bzrlib import patiencediff
 
26
from bzrlib import patiencediff, tsort
25
27
from bzrlib.errors import NoSuchRevision
26
28
from bzrlib.revision import NULL_REVISION, CURRENT_REVISION
27
29
 
28
 
from bzrlib.plugins.gtk.annotate.colormap import AnnotateColorSaturation
 
30
from colormap import AnnotateColorMap, AnnotateColorSaturation
29
31
from bzrlib.plugins.gtk.revisionview import RevisionView
30
32
from bzrlib.plugins.gtk.window import Window
31
33
 
47
49
        self.all = all
48
50
        self.plain = plain
49
51
        self._branch = branch
50
 
 
 
52
        
51
53
        Window.__init__(self, parent)
52
 
 
53
 
        self.set_icon(self.render_icon(Gtk.STOCK_FIND, Gtk.IconSize.BUTTON))
 
54
        
 
55
        self.set_icon(self.render_icon(gtk.STOCK_FIND, gtk.ICON_SIZE_BUTTON))
54
56
        self.annotate_colormap = AnnotateColorSaturation()
55
57
 
56
58
        self._create()
66
68
        self.revisionview.set_file_id(file_id)
67
69
        self.revision_id = getattr(tree, 'get_revision_id', 
68
70
                                   lambda: CURRENT_REVISION)()
69
 
 
 
71
        
70
72
        # [revision id, line number, author, revno, highlight color, line]
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
 
 
 
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
        
78
80
        last_seen = None
79
81
        try:
80
82
            branch.lock_read()
84
86
            for revision_id, revno in revno_map.iteritems():
85
87
                self.dotted[revision_id] = '.'.join(str(num) for num in revno)
86
88
            for line_no, (revision, revno, line)\
87
 
                in enumerate(self._annotate(tree, file_id)):
 
89
                    in enumerate(self._annotate(tree, file_id)):
88
90
                if revision.revision_id == last_seen and not self.all:
89
91
                    revno = author = ""
90
92
                else:
100
102
                                       revno,
101
103
                                       None,
102
104
                                       line.rstrip("\r\n")
103
 
                                       ])
 
105
                                      ])
104
106
                self.annotations.append(revision)
105
107
 
106
108
            if not self.plain:
123
125
            # bar?
124
126
            print("gannotate: Line number %d does't exist. Defaulting to "
125
127
                  "line 1." % lineno)
126
 
            return
 
128
            return
127
129
        else:
128
130
            row = lineno - 1
129
131
 
191
193
        self.revisionview = self._create_log_view()
192
194
        self.annoview = self._create_annotate_view()
193
195
 
194
 
        vbox = Gtk.VBox(False)
 
196
        vbox = gtk.VBox(False)
195
197
        vbox.show()
196
198
 
197
 
        sw = Gtk.ScrolledWindow()
198
 
        sw.set_policy(Gtk.PolicyType.AUTOMATIC, Gtk.PolicyType.AUTOMATIC)
199
 
        sw.set_shadow_type(Gtk.ShadowType.IN)
 
199
        sw = gtk.ScrolledWindow()
 
200
        sw.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
 
201
        sw.set_shadow_type(gtk.SHADOW_IN)
200
202
        sw.add(self.annoview)
201
203
        self.annoview.gwindow = self
202
204
        sw.show()
203
205
 
204
 
        swbox = Gtk.VBox()
205
 
        swbox.pack_start(sw, True, True, 0)
 
206
        swbox = gtk.VBox()
 
207
        swbox.pack_start(sw)
206
208
        swbox.show()
207
209
 
208
 
        hbox = Gtk.HBox(False, 6)
 
210
        hbox = gtk.HBox(False, 6)
209
211
        self.back_button = self._create_back_button()
210
212
        hbox.pack_start(self.back_button, expand=False, fill=True)
211
213
        self.forward_button = self._create_forward_button()
212
214
        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)
217
215
        hbox.show()
218
216
        vbox.pack_start(hbox, expand=False, fill=True)
219
 
 
220
 
        self.pane = pane = Gtk.VPaned()
 
217
        
 
218
        self.pane = pane = gtk.VPaned()
221
219
        pane.add1(swbox)
222
220
        pane.add2(self.revisionview)
223
221
        pane.show()
225
223
 
226
224
        self._search = SearchBox()
227
225
        swbox.pack_start(self._search, expand=False, fill=True)
228
 
        accels = Gtk.AccelGroup()
229
 
        accels.connect_group(Gdk.KEY_f, Gdk.EventMask.CONTROL_MASK,
230
 
                             Gtk.ACCEL_LOCKED,
 
226
        accels = gtk.AccelGroup()
 
227
        accels.connect_group(gtk.keysyms.f, gtk.gdk.CONTROL_MASK,
 
228
                             gtk.ACCEL_LOCKED,
231
229
                             self._search_by_text)
232
 
        accels.connect_group(Gdk.KEY_g, Gdk.EventMask.CONTROL_MASK,
233
 
                             Gtk.ACCEL_LOCKED,
 
230
        accels.connect_group(gtk.keysyms.g, gtk.gdk.CONTROL_MASK,
 
231
                             gtk.ACCEL_LOCKED,
234
232
                             self._search_by_line)
235
233
        self.add_accel_group(accels)
236
234
 
237
235
        self.add(vbox)
238
236
 
239
 
    def _search_by_text(self, *ignored): # (accel_group, window, key, modifiers):
 
237
    def _search_by_text(self, accel_group, window, key, modifiers):
240
238
        self._search.show_for('text')
241
239
        self._search.set_target(self.annoview, TEXT_LINE_COL)
242
240
 
243
 
    def _search_by_line(self, *ignored): # accel_group, window, key, modifiers):
 
241
    def _search_by_line(self, accel_group, window, key, modifiers):
244
242
        self._search.show_for('line')
245
243
        self._search.set_target(self.annoview, LINE_NUM_COL)
246
244
 
258
256
            else:
259
257
                tree2 = repository.revision_tree(NULL_REVISION)
260
258
        from bzrlib.plugins.gtk.diff import DiffWindow
261
 
        window = DiffWindow(self)
 
259
        window = DiffWindow()
262
260
        window.set_diff("Diff for line %d" % (row+1), tree1, tree2)
263
261
        window.set_file(tree1.id2path(self.file_id))
264
262
        window.show()
265
263
 
266
264
 
267
265
    def _create_annotate_view(self):
268
 
        tv = Gtk.TreeView()
 
266
        tv = gtk.TreeView()
269
267
        tv.set_rules_hint(False)
270
268
        tv.connect("cursor-changed", self._activate_selected_revision)
271
269
        tv.show()
272
270
        tv.connect("row-activated", self.line_diff)
273
271
 
274
 
        cell = Gtk.CellRendererText()
 
272
        cell = gtk.CellRendererText()
275
273
        cell.set_property("xalign", 1.0)
276
274
        cell.set_property("ypad", 0)
277
275
        cell.set_property("family", "Monospace")
278
276
        cell.set_property("cell-background-gdk",
279
 
                          tv.get_style().bg[Gtk.StateType.NORMAL])
280
 
        col = Gtk.TreeViewColumn()
 
277
                          tv.get_style().bg[gtk.STATE_NORMAL])
 
278
        col = gtk.TreeViewColumn()
281
279
        col.set_resizable(False)
282
 
        col.pack_start(cell, True, True, 0)
 
280
        col.pack_start(cell, expand=True)
283
281
        col.add_attribute(cell, "text", LINE_NUM_COL)
284
282
        tv.append_column(col)
285
283
 
286
 
        cell = Gtk.CellRendererText()
 
284
        cell = gtk.CellRendererText()
287
285
        cell.set_property("ypad", 0)
288
 
        cell.set_property("ellipsize", Pango.EllipsizeMode.END)
 
286
        cell.set_property("ellipsize", pango.ELLIPSIZE_END)
289
287
        cell.set_property("cell-background-gdk",
290
 
                          self.get_style().bg[Gtk.StateType.NORMAL])
291
 
        col = Gtk.TreeViewColumn("Committer")
 
288
                          self.get_style().bg[gtk.STATE_NORMAL])
 
289
        col = gtk.TreeViewColumn("Committer")
292
290
        col.set_resizable(True)
293
 
        col.pack_start(cell, True, True, 0)
 
291
        col.pack_start(cell, expand=True)
294
292
        col.add_attribute(cell, "text", COMMITTER_COL)
295
293
        tv.append_column(col)
296
294
 
297
 
        cell = Gtk.CellRendererText()
 
295
        cell = gtk.CellRendererText()
298
296
        cell.set_property("xalign", 1.0)
299
297
        cell.set_property("ypad", 0)
300
298
        cell.set_property("cell-background-gdk",
301
 
                          self.get_style().bg[Gtk.StateType.NORMAL])
302
 
        col = Gtk.TreeViewColumn("Revno")
 
299
                          self.get_style().bg[gtk.STATE_NORMAL])
 
300
        col = gtk.TreeViewColumn("Revno")
303
301
        col.set_resizable(False)
304
 
        col.pack_start(cell, True, True, 0)
 
302
        col.pack_start(cell, expand=True)
305
303
        col.add_attribute(cell, "markup", REVNO_COL)
306
304
        tv.append_column(col)
307
305
 
308
 
        cell = Gtk.CellRendererText()
 
306
        cell = gtk.CellRendererText()
309
307
        cell.set_property("ypad", 0)
310
308
        cell.set_property("family", "Monospace")
311
 
        col = Gtk.TreeViewColumn()
 
309
        col = gtk.TreeViewColumn()
312
310
        col.set_resizable(False)
313
 
        col.pack_start(cell, True, True, 0)
 
311
        col.pack_start(cell, expand=True)
314
312
#        col.add_attribute(cell, "foreground", HIGHLIGHT_COLOR_COL)
315
313
        col.add_attribute(cell, "background", HIGHLIGHT_COLOR_COL)
316
314
        col.add_attribute(cell, "text", TEXT_LINE_COL)
317
315
        tv.append_column(col)
318
316
 
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)
 
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)
325
320
 
326
321
        return tv
327
322
 
331
326
        return lv
332
327
 
333
328
    def _create_back_button(self):
334
 
        button = Gtk.Button()
 
329
        button = gtk.Button()
335
330
        button.set_use_stock(True)
336
331
        button.set_label("gtk-go-back")
337
332
        button.connect("clicked", lambda w: self.go_back())
338
 
        button.set_relief(Gtk.ReliefStyle.NONE)
 
333
        button.set_relief(gtk.RELIEF_NONE)
339
334
        button.show()
340
335
        return button
341
336
 
342
337
    def _create_forward_button(self):
343
 
        button = Gtk.Button()
 
338
        button = gtk.Button()
344
339
        button.set_use_stock(True)
345
340
        button.set_label("gtk-go-forward")
346
341
        button.connect("clicked", lambda w: self.go_forward())
347
 
        button.set_relief(Gtk.ReliefStyle.NONE)
 
342
        button.set_relief(gtk.RELIEF_NONE)
348
343
        button.show()
349
344
        button.set_sensitive(False)
350
345
        return button
351
346
 
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
 
 
373
347
    def go_back(self):
374
348
        last_tree = self.tree
375
349
        rev_id = self._selected_revision()
450
424
            self.__cache[revision_id] = revision
451
425
        return self.__cache[revision_id]
452
426
 
453
 
class SearchBox(Gtk.HBox):
 
427
class SearchBox(gtk.HBox):
454
428
    """A button box for searching in text or lines of annotations"""
455
429
    def __init__(self):
456
 
        GObject.GObject.__init__(self, False, 6)
 
430
        gtk.HBox.__init__(self, False, 6)
457
431
 
458
432
        # Close button
459
 
        button = Gtk.Button()
460
 
        image = Gtk.Image()
461
 
        image.set_from_stock('gtk-stop', Gtk.IconSize.BUTTON)
 
433
        button = gtk.Button()
 
434
        image = gtk.Image()
 
435
        image.set_from_stock('gtk-stop', gtk.ICON_SIZE_BUTTON)
462
436
        button.set_image(image)
463
 
        button.set_relief(Gtk.ReliefStyle.NONE)
 
437
        button.set_relief(gtk.RELIEF_NONE)
464
438
        button.connect("clicked", lambda w: self.hide_all())
465
439
        self.pack_start(button, expand=False, fill=False)
466
440
 
467
441
        # Search entry
468
 
        label = Gtk.Label()
 
442
        label = gtk.Label()
469
443
        self._label = label
470
444
        self.pack_start(label, expand=False, fill=False)
471
445
 
472
 
        entry = Gtk.Entry()
 
446
        entry = gtk.Entry()
473
447
        self._entry = entry
474
448
        entry.connect("activate", lambda w, d: self._do_search(d),
475
449
                      'forward')
476
450
        self.pack_start(entry, expand=False, fill=False)
477
451
 
478
452
        # Next/previous buttons
479
 
        button = Gtk.Button('_Next')
480
 
        image = Gtk.Image()
481
 
        image.set_from_stock('gtk-go-forward', Gtk.IconSize.BUTTON)
 
453
        button = gtk.Button('_Next')
 
454
        image = gtk.Image()
 
455
        image.set_from_stock('gtk-go-forward', gtk.ICON_SIZE_BUTTON)
482
456
        button.set_image(image)
483
457
        button.connect("clicked", lambda w, d: self._do_search(d),
484
458
                       'forward')
485
459
        self.pack_start(button, expand=False, fill=False)
486
460
 
487
 
        button = Gtk.Button('_Previous')
488
 
        image = Gtk.Image()
489
 
        image.set_from_stock('gtk-go-back', Gtk.IconSize.BUTTON)
 
461
        button = gtk.Button('_Previous')
 
462
        image = gtk.Image()
 
463
        image.set_from_stock('gtk-go-back', gtk.ICON_SIZE_BUTTON)
490
464
        button.set_image(image)
491
465
        button.connect("clicked", lambda w, d: self._do_search(d),
492
466
                       'backward')
493
467
        self.pack_start(button, expand=False, fill=False)
494
468
 
495
469
        # Search options
496
 
        check = Gtk.CheckButton('Match case')
 
470
        check = gtk.CheckButton('Match case')
497
471
        self._match_case = check
498
472
        self.pack_start(check, expand=False, fill=False)
499
473
 
500
 
        check = Gtk.CheckButton('Regexp')
 
474
        check = gtk.CheckButton('Regexp')
501
475
        check.connect("toggled", lambda w: self._set_label())
502
476
        self._regexp = check
503
477
        self.pack_start(check, expand=False, fill=False)
533
507
 
534
508
    def _match(self, model, iterator, column):
535
509
        matching_case = self._match_case.get_active()
536
 
        cell_value, = model.get(iterator, column)
 
510
        string, = model.get(iterator, column)
537
511
        key = self._entry.get_text()
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
        if self._regexp.get_active():
543
513
            if matching_case:
544
 
                match = re.compile(key).search(cell_value, 1)
 
514
                match = re.compile(key).search(string, 1)
545
515
            else:
546
 
                match = re.compile(key, re.I).search(cell_value, 1)
 
516
                match = re.compile(key, re.I).search(string, 1)
547
517
        else:
548
518
            if not matching_case:
549
 
                cell_value = cell_value.lower()
 
519
                string = string.lower()
550
520
                key = key.lower()
551
 
            match = cell_value.find(key) != -1
 
521
            match = string.find(key) != -1
552
522
 
553
523
        return match
554
524