/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: John Arbash Meinel
  • Date: 2007-10-02 23:08:12 UTC
  • mto: (322.1.1 trunk) (330.3.3 trunk)
  • mto: This revision was merged to the branch mainline in revision 368.
  • Revision ID: john@arbash-meinel.com-20071002230812-h8i6pq8fwvodute4
Start testing with Unicode data.
It seems there is some brokenness with serializing Unicode messages.
But otherwise everything seems to be working.

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