/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-28 19:26:53 UTC
  • mto: (450.1.13 trunk)
  • mto: This revision was merged to the branch mainline in revision 458.
  • Revision ID: jelmer@samba.org-20080328192653-trzptkwahx1tulz9
Add module for preferences code.

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