/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: Curtis Hovey
  • Date: 2011-09-05 03:44:26 UTC
  • mto: This revision was merged to the branch mainline in revision 741.
  • Revision ID: sinzui.is@verizon.net-20110905034426-p98pxnay9rmzkr99
Fix the initializer for many classes.
Replace Gtk.Dialog.vbox with .get_content_area().

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