/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: 2012-07-09 15:23:26 UTC
  • mto: This revision was merged to the branch mainline in revision 794.
  • Revision ID: jelmer@samba.org-20120709152326-dzxb8zoz0btull7n
Remove bzr-notify.

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 Gdk
 
21
from gi.repository import Gtk
 
22
from gi.repository import Pango
24
23
import re
25
24
 
26
 
from bzrlib import patiencediff, tsort
 
25
from bzrlib import patiencediff
27
26
from bzrlib.errors import NoSuchRevision
28
27
from bzrlib.revision import NULL_REVISION, CURRENT_REVISION
29
28
 
30
 
from colormap import AnnotateColorMap, AnnotateColorSaturation
 
29
from bzrlib.plugins.gtk.annotate.colormap import AnnotateColorSaturation
 
30
from bzrlib.plugins.gtk.i18n import _i18n
31
31
from bzrlib.plugins.gtk.revisionview import RevisionView
32
32
from bzrlib.plugins.gtk.window import Window
33
33
 
45
45
class GAnnotateWindow(Window):
46
46
    """Annotate window."""
47
47
 
48
 
    def __init__(self, all=False, plain=False, parent=None):
 
48
    def __init__(self, all=False, plain=False, parent=None, branch=None):
49
49
        self.all = all
50
50
        self.plain = plain
51
 
        
52
 
        Window.__init__(self, parent)
53
 
        
54
 
        self.set_icon(self.render_icon(gtk.STOCK_FIND, gtk.ICON_SIZE_BUTTON))
 
51
        self._branch = branch
 
52
 
 
53
        super(GAnnotateWindow, self).__init__(parent=parent)
 
54
 
 
55
        self.set_icon(
 
56
            self.render_icon_pixbuf(Gtk.STOCK_FIND, Gtk.IconSize.BUTTON))
55
57
        self.annotate_colormap = AnnotateColorSaturation()
56
58
 
57
59
        self._create()
67
69
        self.revisionview.set_file_id(file_id)
68
70
        self.revision_id = getattr(tree, 'get_revision_id', 
69
71
                                   lambda: CURRENT_REVISION)()
70
 
        
 
72
 
71
73
        # [revision id, line number, author, revno, highlight color, line]
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
 
        
 
74
        self.annomodel = Gtk.ListStore(GObject.TYPE_STRING,
 
75
                                       GObject.TYPE_INT,
 
76
                                       GObject.TYPE_STRING,
 
77
                                       GObject.TYPE_STRING,
 
78
                                       GObject.TYPE_STRING,
 
79
                                       GObject.TYPE_STRING)
 
80
 
79
81
        last_seen = None
80
82
        try:
81
83
            branch.lock_read()
82
84
            branch.repository.lock_read()
 
85
            self.dotted = {}
 
86
            revno_map = self.branch.get_revision_id_to_revno_map()
 
87
            for revision_id, revno in revno_map.iteritems():
 
88
                self.dotted[revision_id] = '.'.join(str(num) for num in revno)
83
89
            for line_no, (revision, revno, line)\
84
 
                    in enumerate(self._annotate(tree, file_id)):
 
90
                in enumerate(self._annotate(tree, file_id)):
85
91
                if revision.revision_id == last_seen and not self.all:
86
92
                    revno = author = ""
87
93
                else:
88
94
                    last_seen = revision.revision_id
89
 
                    author = revision.get_apparent_author()
 
95
                    author = ", ".join(revision.get_apparent_authors())
90
96
 
91
97
                if revision.revision_id not in self.revisions:
92
98
                    self.revisions[revision.revision_id] = revision
97
103
                                       revno,
98
104
                                       None,
99
105
                                       line.rstrip("\r\n")
100
 
                                      ])
 
106
                                       ])
101
107
                self.annotations.append(revision)
102
108
 
103
109
            if not self.plain:
109
115
 
110
116
        self.annoview.set_model(self.annomodel)
111
117
        self.annoview.grab_focus()
 
118
        my_revno = self.dotted.get(self.revision_id, 'current')
 
119
        title = '%s (%s) - gannotate' % (self.tree.id2path(file_id), my_revno)
 
120
        self.set_title(title)
112
121
 
113
122
    def jump_to_line(self, lineno):
114
123
        if lineno > len(self.annomodel) or lineno < 1:
117
126
            # bar?
118
127
            print("gannotate: Line number %d does't exist. Defaulting to "
119
128
                  "line 1." % lineno)
120
 
            return
 
129
            return
121
130
        else:
122
131
            row = lineno - 1
123
132
 
124
 
        self.annoview.set_cursor(row)
125
 
        self.annoview.scroll_to_cell(row, use_align=True)
126
 
 
127
 
    def _dotted_revnos(self, repository, revision_id):
128
 
        """Return a dict of revision_id -> dotted revno
129
 
        
130
 
        :param repository: The repository to get the graph from
131
 
        :param revision_id: The last revision for which this info is needed
132
 
        """
133
 
        graph = repository.get_revision_graph(revision_id)
134
 
        dotted = {}
135
 
        for n, revision_id, d, revno, e in tsort.merge_sort(graph, 
136
 
            revision_id, generate_revno=True):
137
 
            dotted[revision_id] = '.'.join(str(num) for num in revno)
138
 
        return dotted
 
133
        tree_path = Gtk.TreePath(path=row)
 
134
        self.annoview.set_cursor(tree_path, None, False)
 
135
        self.annoview.scroll_to_cell(tree_path, use_align=True)
139
136
 
140
137
    def _annotate(self, tree, file_id):
141
138
        current_revision = FakeRevision(CURRENT_REVISION)
143
140
        current_revision.timestamp = time.time()
144
141
        current_revision.message = '[Not yet committed]'
145
142
        current_revision.parent_ids = tree.get_parent_ids()
146
 
        current_revision.properties['branch-nick'] = self.branch.nick
 
143
        current_revision.properties['branch-nick'] = self.branch._get_nick(local=True)
147
144
        current_revno = '%d?' % (self.branch.revno() + 1)
148
145
        repository = self.branch.repository
149
146
        if self.revision_id == CURRENT_REVISION:
150
147
            revision_id = self.branch.last_revision()
151
148
        else:
152
149
            revision_id = self.revision_id
153
 
        dotted = self._dotted_revnos(repository, revision_id)
154
150
        revision_cache = RevisionCache(repository, self.revisions)
155
151
        for origin, text in tree.annotate_iter(file_id):
156
152
            rev_id = origin
160
156
            else:
161
157
                try:
162
158
                    revision = revision_cache.get_revision(rev_id)
163
 
                    revno = dotted.get(rev_id, 'merge')
 
159
                    revno = self.dotted.get(rev_id, 'merge')
164
160
                    if len(revno) > 15:
165
161
                        revno = 'merge'
166
162
                except NoSuchRevision:
172
168
    def _highlight_annotation(self, model, path, iter, now):
173
169
        revision_id, = model.get(iter, REVISION_ID_COL)
174
170
        revision = self.revisions[revision_id]
175
 
        model.set(iter, HIGHLIGHT_COLOR_COL,
176
 
                  self.annotate_colormap.get_color(revision, now))
 
171
        # XXX sinzui 2011-08-12: What does get_color return?
 
172
        color = self.annotate_colormap.get_color(revision, now)
 
173
        model.set_value(iter, HIGHLIGHT_COLOR_COL, color)
177
174
 
178
175
    def _selected_revision(self):
179
176
        (path, col) = self.annoview.get_cursor()
183
180
 
184
181
    def _activate_selected_revision(self, w):
185
182
        rev_id = self._selected_revision()
186
 
        if rev_id is None:
 
183
        if not rev_id or rev_id == NULL_REVISION:
187
184
            return
188
185
        selected = self.revisions[rev_id]
189
186
        self.revisionview.set_revision(selected)
198
195
        self.revisionview = self._create_log_view()
199
196
        self.annoview = self._create_annotate_view()
200
197
 
201
 
        vbox = gtk.VBox(False)
 
198
        vbox = Gtk.VBox(homogeneous=False, spacing=0)
202
199
        vbox.show()
203
200
 
204
 
        sw = gtk.ScrolledWindow()
205
 
        sw.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
206
 
        sw.set_shadow_type(gtk.SHADOW_IN)
 
201
        sw = Gtk.ScrolledWindow()
 
202
        sw.set_policy(Gtk.PolicyType.AUTOMATIC, Gtk.PolicyType.AUTOMATIC)
 
203
        sw.set_shadow_type(Gtk.ShadowType.IN)
207
204
        sw.add(self.annoview)
208
205
        self.annoview.gwindow = self
209
206
        sw.show()
210
207
 
211
 
        swbox = gtk.VBox()
212
 
        swbox.pack_start(sw)
 
208
        swbox = Gtk.VBox()
 
209
        swbox.pack_start(sw, True, True, 0)
213
210
        swbox.show()
214
211
 
215
 
        hbox = gtk.HBox(False, 6)
 
212
        hbox = Gtk.HBox(homogeneous=False, spacing=6)
216
213
        self.back_button = self._create_back_button()
217
 
        hbox.pack_start(self.back_button, expand=False, fill=True)
 
214
        hbox.pack_start(self.back_button, False, True, 0)
218
215
        self.forward_button = self._create_forward_button()
219
 
        hbox.pack_start(self.forward_button, expand=False, fill=True)
 
216
        hbox.pack_start(self.forward_button, False, True, 0)
 
217
        self.find_button = self._create_find_button()
 
218
        hbox.pack_start(self.find_button, False, True, 0)
 
219
        self.goto_button = self._create_goto_button()
 
220
        hbox.pack_start(self.goto_button, False, True, 0)
220
221
        hbox.show()
221
 
        vbox.pack_start(hbox, expand=False, fill=True)
222
 
        
223
 
        self.pane = pane = gtk.VPaned()
 
222
        vbox.pack_start(hbox, False, True, 0)
 
223
 
 
224
        self.pane = pane = Gtk.Paned.new(Gtk.Orientation.VERTICAL)
224
225
        pane.add1(swbox)
225
226
        pane.add2(self.revisionview)
226
227
        pane.show()
227
 
        vbox.pack_start(pane, expand=True, fill=True)
 
228
        vbox.pack_start(pane, True, True, 0)
228
229
 
229
230
        self._search = SearchBox()
230
 
        swbox.pack_start(self._search, expand=False, fill=True)
231
 
        accels = gtk.AccelGroup()
232
 
        accels.connect_group(gtk.keysyms.f, gtk.gdk.CONTROL_MASK,
233
 
                             gtk.ACCEL_LOCKED,
 
231
        swbox.pack_start(self._search, False, True, 0)
 
232
        accels = Gtk.AccelGroup()
 
233
        accels.connect(Gdk.KEY_f, Gdk.ModifierType.CONTROL_MASK,
 
234
                             Gtk.AccelFlags.LOCKED,
234
235
                             self._search_by_text)
235
 
        accels.connect_group(gtk.keysyms.g, gtk.gdk.CONTROL_MASK,
236
 
                             gtk.ACCEL_LOCKED,
 
236
        accels.connect(Gdk.KEY_g, Gdk.ModifierType.CONTROL_MASK,
 
237
                             Gtk.AccelFlags.LOCKED,
237
238
                             self._search_by_line)
238
239
        self.add_accel_group(accels)
239
240
 
240
241
        self.add(vbox)
241
242
 
242
 
    def _search_by_text(self, accel_group, window, key, modifiers):
 
243
    def _search_by_text(self, *ignored): # (accel_group, window, key, modifiers):
243
244
        self._search.show_for('text')
244
245
        self._search.set_target(self.annoview, TEXT_LINE_COL)
245
246
 
246
 
    def _search_by_line(self, accel_group, window, key, modifiers):
 
247
    def _search_by_line(self, *ignored): # accel_group, window, key, modifiers):
247
248
        self._search.show_for('line')
248
249
        self._search.set_target(self.annoview, LINE_NUM_COL)
249
250
 
250
 
    def row_diff(self, tv, path, tvc):
251
 
        row = path[0]
 
251
    def line_diff(self, tv, path, tvc):
 
252
        row = path.get_indices()[0]
252
253
        revision = self.annotations[row]
253
254
        repository = self.branch.repository
254
255
        if revision.revision_id == CURRENT_REVISION:
261
262
            else:
262
263
                tree2 = repository.revision_tree(NULL_REVISION)
263
264
        from bzrlib.plugins.gtk.diff import DiffWindow
264
 
        window = DiffWindow()
265
 
        window.set_diff("Diff for row %d" % (row+1), tree1, tree2)
 
265
        window = DiffWindow(self)
 
266
        window.set_diff("Diff for line %d" % (row+1), tree1, tree2)
266
267
        window.set_file(tree1.id2path(self.file_id))
267
268
        window.show()
268
269
 
269
270
 
270
271
    def _create_annotate_view(self):
271
 
        tv = gtk.TreeView()
 
272
        tv = Gtk.TreeView()
272
273
        tv.set_rules_hint(False)
273
274
        tv.connect("cursor-changed", self._activate_selected_revision)
274
275
        tv.show()
275
 
        tv.connect("row-activated", self.row_diff)
 
276
        tv.connect("row-activated", self.line_diff)
276
277
 
277
 
        cell = gtk.CellRendererText()
 
278
        cell = Gtk.CellRendererText()
278
279
        cell.set_property("xalign", 1.0)
279
280
        cell.set_property("ypad", 0)
280
281
        cell.set_property("family", "Monospace")
281
282
        cell.set_property("cell-background-gdk",
282
 
                          tv.get_style().bg[gtk.STATE_NORMAL])
283
 
        col = gtk.TreeViewColumn()
 
283
                          tv.get_style().bg[Gtk.StateType.NORMAL])
 
284
        col = Gtk.TreeViewColumn()
284
285
        col.set_resizable(False)
285
 
        col.pack_start(cell, expand=True)
 
286
        col.pack_start(cell, True)
286
287
        col.add_attribute(cell, "text", LINE_NUM_COL)
287
288
        tv.append_column(col)
288
289
 
289
 
        cell = gtk.CellRendererText()
 
290
        cell = Gtk.CellRendererText()
290
291
        cell.set_property("ypad", 0)
291
 
        cell.set_property("ellipsize", pango.ELLIPSIZE_END)
 
292
        cell.set_property("ellipsize", Pango.EllipsizeMode.END)
292
293
        cell.set_property("cell-background-gdk",
293
 
                          self.get_style().bg[gtk.STATE_NORMAL])
294
 
        col = gtk.TreeViewColumn("Committer")
 
294
                          self.get_style().bg[Gtk.StateType.NORMAL])
 
295
        col = Gtk.TreeViewColumn("Committer")
295
296
        col.set_resizable(True)
296
 
        col.pack_start(cell, expand=True)
 
297
        col.pack_start(cell, True)
297
298
        col.add_attribute(cell, "text", COMMITTER_COL)
298
299
        tv.append_column(col)
299
300
 
300
 
        cell = gtk.CellRendererText()
 
301
        cell = Gtk.CellRendererText()
301
302
        cell.set_property("xalign", 1.0)
302
303
        cell.set_property("ypad", 0)
303
304
        cell.set_property("cell-background-gdk",
304
 
                          self.get_style().bg[gtk.STATE_NORMAL])
305
 
        col = gtk.TreeViewColumn("Revno")
 
305
                          self.get_style().bg[Gtk.StateType.NORMAL])
 
306
        col = Gtk.TreeViewColumn("Revno")
306
307
        col.set_resizable(False)
307
 
        col.pack_start(cell, expand=True)
 
308
        col.pack_start(cell, True)
308
309
        col.add_attribute(cell, "markup", REVNO_COL)
309
310
        tv.append_column(col)
310
311
 
311
 
        cell = gtk.CellRendererText()
 
312
        cell = Gtk.CellRendererText()
312
313
        cell.set_property("ypad", 0)
313
314
        cell.set_property("family", "Monospace")
314
 
        col = gtk.TreeViewColumn()
 
315
        col = Gtk.TreeViewColumn()
315
316
        col.set_resizable(False)
316
 
        col.pack_start(cell, expand=True)
 
317
        col.pack_start(cell, True)
317
318
#        col.add_attribute(cell, "foreground", HIGHLIGHT_COLOR_COL)
318
319
        col.add_attribute(cell, "background", HIGHLIGHT_COLOR_COL)
319
320
        col.add_attribute(cell, "text", TEXT_LINE_COL)
320
321
        tv.append_column(col)
321
322
 
322
 
        # FIXME: Now that C-f is now used for search by text we
323
 
        # may as well disable the auto search.
324
 
        tv.set_search_column(LINE_NUM_COL)
 
323
        # interactive substring search
 
324
        def search_equal_func(model, column, key, iter):
 
325
            return model.get_value(iter, TEXT_LINE_COL).lower().find(key.lower()) == -1
 
326
 
 
327
        tv.set_enable_search(True)
 
328
        tv.set_search_equal_func(search_equal_func, None)
325
329
 
326
330
        return tv
327
331
 
328
332
    def _create_log_view(self):
329
 
        lv = RevisionView()
 
333
        lv = RevisionView(self._branch)
330
334
        lv.show()
331
335
        return lv
332
336
 
333
337
    def _create_back_button(self):
334
 
        button = gtk.Button()
 
338
        button = Gtk.Button()
335
339
        button.set_use_stock(True)
336
340
        button.set_label("gtk-go-back")
337
341
        button.connect("clicked", lambda w: self.go_back())
338
 
        button.set_relief(gtk.RELIEF_NONE)
 
342
        button.set_relief(Gtk.ReliefStyle.NONE)
339
343
        button.show()
340
344
        return button
341
345
 
342
346
    def _create_forward_button(self):
343
 
        button = gtk.Button()
 
347
        button = Gtk.Button()
344
348
        button.set_use_stock(True)
345
349
        button.set_label("gtk-go-forward")
346
350
        button.connect("clicked", lambda w: self.go_forward())
347
 
        button.set_relief(gtk.RELIEF_NONE)
 
351
        button.set_relief(Gtk.ReliefStyle.NONE)
348
352
        button.show()
349
353
        button.set_sensitive(False)
350
354
        return button
351
355
 
 
356
    def _create_find_button(self):
 
357
        button = Gtk.Button()
 
358
        button.set_use_stock(True)
 
359
        button.set_label("gtk-find")
 
360
        button.set_tooltip_text("Search for text (Ctrl+F)")
 
361
        button.connect("clicked", self._search_by_text)
 
362
        button.set_relief(Gtk.ReliefStyle.NONE)
 
363
        button.show()
 
364
        button.set_sensitive(True)
 
365
        return button
 
366
 
 
367
    def _create_goto_button(self):
 
368
        button = Gtk.Button()
 
369
        button.set_label("Goto Line")
 
370
        button.set_tooltip_text("Scroll to a line by entering its number (Ctrl+G)")
 
371
        button.connect("clicked", self._search_by_line)
 
372
        button.set_relief(Gtk.ReliefStyle.NONE)
 
373
        button.show()
 
374
        button.set_sensitive(True)
 
375
        return button
 
376
 
352
377
    def go_back(self):
353
378
        last_tree = self.tree
354
379
        rev_id = self._selected_revision()
373
398
        rev_id = self._selected_revision()
374
399
        if self.file_id in target_tree:
375
400
            offset = self.get_scroll_offset(target_tree)
376
 
            (row,), col = self.annoview.get_cursor()
 
401
            path, col = self.annoview.get_cursor()
 
402
            (row,) = path.get_indices()
377
403
            self.annotate(target_tree, self.branch, self.file_id)
378
404
            new_row = row+offset
379
405
            if new_row < 0:
380
406
                new_row = 0
381
 
            self.annoview.set_cursor(new_row)
 
407
            new_path = Gtk.TreePath(path=new_row)
 
408
            self.annoview.set_cursor(new_path, None, False)
382
409
            return True
383
410
        else:
384
411
            return False
386
413
    def get_scroll_offset(self, tree):
387
414
        old = self.tree.get_file(self.file_id)
388
415
        new = tree.get_file(self.file_id)
389
 
        (row,), col = self.annoview.get_cursor()
 
416
        path, col = self.annoview.get_cursor()
 
417
        (row,) = path.get_indices()
390
418
        matcher = patiencediff.PatienceSequenceMatcher(None, old.readlines(),
391
419
                                                       new.readlines())
392
420
        for i, j, n in matcher.get_matching_blocks():
394
422
                return j - i
395
423
 
396
424
 
397
 
class FakeRevision:
 
425
class FakeRevision(object):
398
426
    """ A fake revision.
399
427
 
400
428
    For when a revision is referenced but not present.
409
437
        self.timezone = 0
410
438
        self.properties = {}
411
439
 
412
 
    def get_apparent_author(self):
413
 
        return self.committer
 
440
    def get_apparent_authors(self):
 
441
        return [self.committer]
414
442
 
415
443
 
416
444
class RevisionCache(object):
417
445
    """A caching revision source"""
 
446
 
418
447
    def __init__(self, real_source, seed_cache=None):
419
448
        self.__real_source = real_source
420
449
        if seed_cache is None:
428
457
            self.__cache[revision_id] = revision
429
458
        return self.__cache[revision_id]
430
459
 
431
 
class SearchBox(gtk.HBox):
 
460
 
 
461
class SearchBox(Gtk.HBox):
432
462
    """A button box for searching in text or lines of annotations"""
433
463
    def __init__(self):
434
 
        gtk.HBox.__init__(self, False, 6)
 
464
        super(SearchBox, self).__init__(homogeneous=False, spacing=6)
435
465
 
436
466
        # Close button
437
 
        button = gtk.Button()
438
 
        image = gtk.Image()
439
 
        image.set_from_stock('gtk-stop', gtk.ICON_SIZE_BUTTON)
 
467
        button = Gtk.Button()
 
468
        image = Gtk.Image()
 
469
        image.set_from_stock('gtk-stop', Gtk.IconSize.BUTTON)
440
470
        button.set_image(image)
441
 
        button.set_relief(gtk.RELIEF_NONE)
442
 
        button.connect("clicked", lambda w: self.hide_all())
443
 
        self.pack_start(button, expand=False, fill=False)
 
471
        button.set_relief(Gtk.ReliefStyle.NONE)
 
472
        button.connect("clicked", lambda w: self.hide())
 
473
        self.pack_start(button, False, False, 0)
444
474
 
445
475
        # Search entry
446
 
        label = gtk.Label()
 
476
        label = Gtk.Label()
447
477
        self._label = label
448
 
        self.pack_start(label, expand=False, fill=False)
 
478
        self.pack_start(label, False, False, 0)
449
479
 
450
 
        entry = gtk.Entry()
 
480
        entry = Gtk.Entry()
451
481
        self._entry = entry
452
482
        entry.connect("activate", lambda w, d: self._do_search(d),
453
483
                      'forward')
454
 
        self.pack_start(entry, expand=False, fill=False)
 
484
        self.pack_start(entry, False, False, 0)
455
485
 
456
486
        # Next/previous buttons
457
 
        button = gtk.Button('_Next')
458
 
        image = gtk.Image()
459
 
        image.set_from_stock('gtk-go-forward', gtk.ICON_SIZE_BUTTON)
 
487
        button = Gtk.Button(_i18n('_Next'), use_underline=True)
 
488
        image = Gtk.Image()
 
489
        image.set_from_stock('gtk-go-forward', Gtk.IconSize.BUTTON)
460
490
        button.set_image(image)
461
491
        button.connect("clicked", lambda w, d: self._do_search(d),
462
492
                       'forward')
463
 
        self.pack_start(button, expand=False, fill=False)
 
493
        self.pack_start(button, False, False, 0)
464
494
 
465
 
        button = gtk.Button('_Previous')
466
 
        image = gtk.Image()
467
 
        image.set_from_stock('gtk-go-back', gtk.ICON_SIZE_BUTTON)
 
495
        button = Gtk.Button(_i18n('_Previous'), use_underline=True)
 
496
        image = Gtk.Image()
 
497
        image.set_from_stock('gtk-go-back', Gtk.IconSize.BUTTON)
468
498
        button.set_image(image)
469
499
        button.connect("clicked", lambda w, d: self._do_search(d),
470
500
                       'backward')
471
 
        self.pack_start(button, expand=False, fill=False)
 
501
        self.pack_start(button, False, False, 0)
472
502
 
473
503
        # Search options
474
 
        check = gtk.CheckButton('Match case')
 
504
        check = Gtk.CheckButton('Match case')
475
505
        self._match_case = check
476
 
        self.pack_start(check, expand=False, fill=False)
 
506
        self.pack_start(check, False, False, 0)
477
507
 
478
 
        check = gtk.CheckButton('Regexp')
 
508
        check = Gtk.CheckButton('Regexp')
479
509
        check.connect("toggled", lambda w: self._set_label())
480
510
        self._regexp = check
481
 
        self.pack_start(check, expand=False, fill=False)
 
511
        self.pack_start(check, False, False, 0)
482
512
 
483
513
        self._view = None
484
514
        self._column = None
511
541
 
512
542
    def _match(self, model, iterator, column):
513
543
        matching_case = self._match_case.get_active()
514
 
        string, = model.get(iterator, column)
 
544
        cell_value, = model.get(iterator, column)
515
545
        key = self._entry.get_text()
516
 
        if self._regexp.get_active():
 
546
        if column == LINE_NUM_COL:
 
547
            # FIXME: For goto-line there are faster algorithms than searching 
 
548
            # every line til we find the right one! -- mbp 2011-01-27
 
549
            return key.strip() == str(cell_value)
 
550
        elif self._regexp.get_active():
517
551
            if matching_case:
518
 
                match = re.compile(key).search(string, 1)
 
552
                match = re.compile(key).search(cell_value, 1)
519
553
            else:
520
 
                match = re.compile(key, re.I).search(string, 1)
 
554
                match = re.compile(key, re.I).search(cell_value, 1)
521
555
        else:
522
556
            if not matching_case:
523
 
                string = string.lower()
 
557
                cell_value = cell_value.lower()
524
558
                key = key.lower()
525
 
            match = string.find(key) != -1
 
559
            match = cell_value.find(key) != -1
526
560
 
527
561
        return match
528
562
 
560
594
        for row in iterate(model, start):
561
595
            if self._match(model, row, self._column):
562
596
                path = model.get_path(row)
563
 
                self._view.set_cursor(path)
 
597
                self._view.set_cursor(path, None, False)
564
598
                self._view.scroll_to_cell(path, use_align=True)
565
599
                break