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