/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-10-02 04:59:13 UTC
  • Revision ID: jelmer@samba.org-20071002045913-iavr7ft7nntc2pwr
Put children widget on a new line.

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