/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: Vincent Ladeuil
  • Date: 2008-05-05 18:16:46 UTC
  • mto: (487.1.1 gtk)
  • mto: This revision was merged to the branch mainline in revision 490.
  • Revision ID: v.ladeuil+lp@free.fr-20080505181646-n95l8ltw2u6jtr26
Fix bug #187283 fix replacing _() by _i18n().

* genpot.sh 
Remove duplication. Add the ability to specify the genrated pot
file on command-line for debugging purposes.

* po/olive-gtk.pot:
Regenerated.

* __init__.py, branch.py, branchview/treeview.py, checkout.py,
commit.py, conflicts.py, diff.py, errors.py, initialize.py,
merge.py, nautilus-bzr.py, olive/__init__.py, olive/add.py,
olive/bookmark.py, olive/guifiles.py, olive/info.py,
olive/menu.py, olive/mkdir.py, olive/move.py, olive/remove.py,
olive/rename.py, push.py, revbrowser.py, status.py, tags.py:
Replace all calls to _() by calls to _i18n(), the latter being
defined in __init__.py and imported in the other modules from
there. This fix the problem encountered countless times when
running bzr selftest and getting silly error messages about
boolean not being callables.

Show diffs side-by-side

added added

removed removed

Lines of Context:
21
21
import gobject
22
22
import gtk
23
23
import pango
 
24
import re
24
25
 
 
26
from bzrlib import patiencediff, tsort
25
27
from bzrlib.errors import NoSuchRevision
 
28
from bzrlib.revision import NULL_REVISION, CURRENT_REVISION
26
29
 
27
30
from colormap import AnnotateColorMap, AnnotateColorSaturation
28
 
from logview import LogView
29
 
from spanselector import SpanSelector
 
31
from bzrlib.plugins.gtk.revisionview import RevisionView
 
32
from bzrlib.plugins.gtk.window import Window
30
33
 
31
34
 
32
35
(
39
42
) = range(6)
40
43
 
41
44
 
42
 
class GAnnotateWindow(gtk.Window):
 
45
class GAnnotateWindow(Window):
43
46
    """Annotate window."""
44
47
 
45
 
    def __init__(self, all=False, plain=False):
 
48
    def __init__(self, all=False, plain=False, parent=None):
46
49
        self.all = all
47
50
        self.plain = plain
48
51
        
49
 
        gtk.Window.__init__(self, gtk.WINDOW_TOPLEVEL)
 
52
        Window.__init__(self, parent)
50
53
        
51
54
        self.set_icon(self.render_icon(gtk.STOCK_FIND, gtk.ICON_SIZE_BUTTON))
52
55
        self.annotate_colormap = AnnotateColorSaturation()
53
56
 
54
57
        self._create()
55
 
 
56
 
        if self.plain:
57
 
            self.span_selector.hide()
58
 
 
59
 
    def annotate(self, branch, file_id):
60
58
        self.revisions = {}
 
59
        self.history = []
 
60
        self._no_back = set()
 
61
 
 
62
    def annotate(self, tree, branch, file_id):
 
63
        self.annotations = []
 
64
        self.branch = branch
 
65
        self.tree = tree
 
66
        self.file_id = file_id
 
67
        self.revisionview.set_file_id(file_id)
 
68
        self.revision_id = getattr(tree, 'get_revision_id', 
 
69
                                   lambda: CURRENT_REVISION)()
61
70
        
62
 
        # [revision id, line number, committer, revno, highlight color, line]
 
71
        # [revision id, line number, author, revno, highlight color, line]
63
72
        self.annomodel = gtk.ListStore(gobject.TYPE_STRING,
64
73
                                       gobject.TYPE_STRING,
65
74
                                       gobject.TYPE_STRING,
71
80
        try:
72
81
            branch.lock_read()
73
82
            branch.repository.lock_read()
 
83
            self.dotted = {}
 
84
            revno_map = self.branch.get_revision_id_to_revno_map()
 
85
            for revision_id, revno in revno_map.iteritems():
 
86
                self.dotted[revision_id] = '.'.join(str(num) for num in revno)
74
87
            for line_no, (revision, revno, line)\
75
 
                    in enumerate(self._annotate(branch, file_id)):
 
88
                    in enumerate(self._annotate(tree, file_id)):
76
89
                if revision.revision_id == last_seen and not self.all:
77
 
                    revno = committer = ""
 
90
                    revno = author = ""
78
91
                else:
79
92
                    last_seen = revision.revision_id
80
 
                    committer = revision.committer
 
93
                    author = revision.get_apparent_author()
81
94
 
82
95
                if revision.revision_id not in self.revisions:
83
96
                    self.revisions[revision.revision_id] = revision
84
97
 
85
98
                self.annomodel.append([revision.revision_id,
86
99
                                       line_no + 1,
87
 
                                       committer,
 
100
                                       author,
88
101
                                       revno,
89
102
                                       None,
90
103
                                       line.rstrip("\r\n")
91
104
                                      ])
 
105
                self.annotations.append(revision)
92
106
 
93
107
            if not self.plain:
94
 
                self._set_oldest_newest()
95
 
                # Recall that calling activate_default will emit "span-changed",
96
 
                # so self._span_changed_cb will take care of initial highlighting
97
 
                self.span_selector.activate_default()
 
108
                now = time.time()
 
109
                self.annomodel.foreach(self._highlight_annotation, now)
98
110
        finally:
99
111
            branch.repository.unlock()
100
112
            branch.unlock()
101
113
 
102
114
        self.annoview.set_model(self.annomodel)
103
115
        self.annoview.grab_focus()
 
116
        my_revno = self.dotted.get(self.revision_id, 'current')
 
117
        title = '%s (%s) - gannotate' % (self.tree.id2path(file_id), my_revno)
 
118
        self.set_title(title)
104
119
 
105
120
    def jump_to_line(self, lineno):
106
121
        if lineno > len(self.annomodel) or lineno < 1:
109
124
            # bar?
110
125
            print("gannotate: Line number %d does't exist. Defaulting to "
111
126
                  "line 1." % lineno)
 
127
            return
112
128
        else:
113
129
            row = lineno - 1
114
130
 
115
131
        self.annoview.set_cursor(row)
116
 
 
117
 
    def _annotate(self, branch, file_id):
118
 
        rev_hist = branch.revision_history()
119
 
        repository = branch.repository
120
 
        rev_tree = repository.revision_tree(branch.last_revision())
121
 
        rev_id = rev_tree.inventory[file_id].revision
122
 
        weave = repository.weave_store.get_weave(file_id,
123
 
                                                 branch.get_transaction())
124
 
        
125
 
        revision_cache = RevisionCache(repository)
126
 
        for origin, text in weave.annotate_iter(rev_id):
 
132
        self.annoview.scroll_to_cell(row, use_align=True)
 
133
 
 
134
 
 
135
    def _annotate(self, tree, file_id):
 
136
        current_revision = FakeRevision(CURRENT_REVISION)
 
137
        current_revision.committer = self.branch.get_config().username()
 
138
        current_revision.timestamp = time.time()
 
139
        current_revision.message = '[Not yet committed]'
 
140
        current_revision.parent_ids = tree.get_parent_ids()
 
141
        current_revision.properties['branch-nick'] = self.branch.nick
 
142
        current_revno = '%d?' % (self.branch.revno() + 1)
 
143
        repository = self.branch.repository
 
144
        if self.revision_id == CURRENT_REVISION:
 
145
            revision_id = self.branch.last_revision()
 
146
        else:
 
147
            revision_id = self.revision_id
 
148
        revision_cache = RevisionCache(repository, self.revisions)
 
149
        for origin, text in tree.annotate_iter(file_id):
127
150
            rev_id = origin
128
 
            try:
129
 
                revision = revision_cache.get_revision(rev_id)
130
 
                if rev_id in rev_hist:
131
 
                    revno = branch.revision_id_to_revno(rev_id)
132
 
                else:
133
 
                    revno = "merge"
134
 
            except NoSuchRevision:
135
 
                revision = NoneRevision(rev_id)
136
 
                revno = "?"
 
151
            if rev_id == CURRENT_REVISION:
 
152
                revision = current_revision
 
153
                revno = current_revno
 
154
            else:
 
155
                try:
 
156
                    revision = revision_cache.get_revision(rev_id)
 
157
                    revno = self.dotted.get(rev_id, 'merge')
 
158
                    if len(revno) > 15:
 
159
                        revno = 'merge'
 
160
                except NoSuchRevision:
 
161
                    revision = FakeRevision(rev_id)
 
162
                    revno = "?"
137
163
 
138
164
            yield revision, revno, text
139
165
 
140
 
    def _set_oldest_newest(self):
141
 
        rev_dates = map(lambda i: self.revisions[i].timestamp, self.revisions)
142
 
        oldest = min(rev_dates)
143
 
        newest = max(rev_dates)
144
 
 
145
 
        span = self._span_from_seconds(time.time() - oldest)
146
 
        self.span_selector.set_to_oldest_span(span)
147
 
        
148
 
        span = self._span_from_seconds(newest - oldest)
149
 
        self.span_selector.set_newest_to_oldest_span(span)
150
 
 
151
 
    def _span_from_seconds(self, seconds):
152
 
        return (seconds / (24 * 60 * 60))
153
 
    
154
 
    def _span_changed_cb(self, w, span):
155
 
        self.annotate_colormap.set_span(span)
156
 
        now = time.time()
157
 
        self.annomodel.foreach(self._highlight_annotation, now)
158
 
 
159
166
    def _highlight_annotation(self, model, path, iter, now):
160
167
        revision_id, = model.get(iter, REVISION_ID_COL)
161
168
        revision = self.revisions[revision_id]
162
169
        model.set(iter, HIGHLIGHT_COLOR_COL,
163
170
                  self.annotate_colormap.get_color(revision, now))
164
171
 
165
 
    def _show_log(self, w):
 
172
    def _selected_revision(self):
166
173
        (path, col) = self.annoview.get_cursor()
167
 
        rev_id = self.annomodel[path][REVISION_ID_COL]
168
 
        self.logview.set_revision(self.revisions[rev_id])
 
174
        if path is None:
 
175
            return None
 
176
        return self.annomodel[path][REVISION_ID_COL]
 
177
 
 
178
    def _activate_selected_revision(self, w):
 
179
        rev_id = self._selected_revision()
 
180
        if not rev_id or rev_id == NULL_REVISION:
 
181
            return
 
182
        selected = self.revisions[rev_id]
 
183
        self.revisionview.set_revision(selected)
 
184
        if (len(selected.parent_ids) != 0 and selected.parent_ids[0] not in
 
185
            self._no_back):
 
186
            enable_back = True
 
187
        else:
 
188
            enable_back = False
 
189
        self.back_button.set_sensitive(enable_back)
169
190
 
170
191
    def _create(self):
171
 
        self.logview = self._create_log_view()
 
192
        self.revisionview = self._create_log_view()
172
193
        self.annoview = self._create_annotate_view()
173
 
        self.span_selector = self._create_span_selector()
174
194
 
175
 
        vbox = gtk.VBox(False, 12)
176
 
        vbox.set_border_width(12)
 
195
        vbox = gtk.VBox(False)
177
196
        vbox.show()
178
197
 
179
198
        sw = gtk.ScrolledWindow()
180
199
        sw.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
181
200
        sw.set_shadow_type(gtk.SHADOW_IN)
182
201
        sw.add(self.annoview)
 
202
        self.annoview.gwindow = self
183
203
        sw.show()
 
204
 
 
205
        swbox = gtk.VBox()
 
206
        swbox.pack_start(sw)
 
207
        swbox.show()
 
208
 
 
209
        hbox = gtk.HBox(False, 6)
 
210
        self.back_button = self._create_back_button()
 
211
        hbox.pack_start(self.back_button, expand=False, fill=True)
 
212
        self.forward_button = self._create_forward_button()
 
213
        hbox.pack_start(self.forward_button, expand=False, fill=True)
 
214
        hbox.show()
 
215
        vbox.pack_start(hbox, expand=False, fill=True)
184
216
        
185
217
        self.pane = pane = gtk.VPaned()
186
 
        pane.add1(sw)
187
 
        pane.add2(self.logview)
 
218
        pane.add1(swbox)
 
219
        pane.add2(self.revisionview)
188
220
        pane.show()
189
221
        vbox.pack_start(pane, expand=True, fill=True)
190
 
        
191
 
        hbox = gtk.HBox(True, 6)
192
 
        hbox.pack_start(self.span_selector, expand=False, fill=True)
193
 
        hbox.pack_start(self._create_button_box(), expand=False, fill=True)
194
 
        hbox.show()
195
 
        vbox.pack_start(hbox, expand=False, fill=True)
 
222
 
 
223
        self._search = SearchBox()
 
224
        swbox.pack_start(self._search, expand=False, fill=True)
 
225
        accels = gtk.AccelGroup()
 
226
        accels.connect_group(gtk.keysyms.f, gtk.gdk.CONTROL_MASK,
 
227
                             gtk.ACCEL_LOCKED,
 
228
                             self._search_by_text)
 
229
        accels.connect_group(gtk.keysyms.g, gtk.gdk.CONTROL_MASK,
 
230
                             gtk.ACCEL_LOCKED,
 
231
                             self._search_by_line)
 
232
        self.add_accel_group(accels)
196
233
 
197
234
        self.add(vbox)
198
235
 
 
236
    def _search_by_text(self, accel_group, window, key, modifiers):
 
237
        self._search.show_for('text')
 
238
        self._search.set_target(self.annoview, TEXT_LINE_COL)
 
239
 
 
240
    def _search_by_line(self, accel_group, window, key, modifiers):
 
241
        self._search.show_for('line')
 
242
        self._search.set_target(self.annoview, LINE_NUM_COL)
 
243
 
 
244
    def line_diff(self, tv, path, tvc):
 
245
        row = path[0]
 
246
        revision = self.annotations[row]
 
247
        repository = self.branch.repository
 
248
        if revision.revision_id == CURRENT_REVISION:
 
249
            tree1 = self.tree
 
250
            tree2 = self.tree.basis_tree()
 
251
        else:
 
252
            tree1 = repository.revision_tree(revision.revision_id)
 
253
            if len(revision.parent_ids) > 0:
 
254
                tree2 = repository.revision_tree(revision.parent_ids[0])
 
255
            else:
 
256
                tree2 = repository.revision_tree(NULL_REVISION)
 
257
        from bzrlib.plugins.gtk.diff import DiffWindow
 
258
        window = DiffWindow()
 
259
        window.set_diff("Diff for line %d" % (row+1), tree1, tree2)
 
260
        window.set_file(tree1.id2path(self.file_id))
 
261
        window.show()
 
262
 
 
263
 
199
264
    def _create_annotate_view(self):
200
265
        tv = gtk.TreeView()
201
266
        tv.set_rules_hint(False)
202
 
        tv.connect("cursor-changed", self._show_log)
 
267
        tv.connect("cursor-changed", self._activate_selected_revision)
203
268
        tv.show()
 
269
        tv.connect("row-activated", self.line_diff)
204
270
 
205
271
        cell = gtk.CellRendererText()
206
272
        cell.set_property("xalign", 1.0)
247
313
        col.add_attribute(cell, "text", TEXT_LINE_COL)
248
314
        tv.append_column(col)
249
315
 
 
316
        # FIXME: Now that C-f is now used for search by text we
 
317
        # may as well disable the auto search.
250
318
        tv.set_search_column(LINE_NUM_COL)
251
 
        
 
319
 
252
320
        return tv
253
321
 
254
 
    def _create_span_selector(self):
255
 
        ss = SpanSelector()
256
 
        ss.connect("span-changed", self._span_changed_cb)
257
 
        ss.show()
258
 
 
259
 
        return ss
260
 
 
261
322
    def _create_log_view(self):
262
 
        lv = LogView()
 
323
        lv = RevisionView()
263
324
        lv.show()
264
 
 
265
325
        return lv
266
326
 
267
 
    def _create_button_box(self):
268
 
        box = gtk.HButtonBox()
269
 
        box.set_layout(gtk.BUTTONBOX_END)
270
 
        box.show()
271
 
        
272
 
        button = gtk.Button()
273
 
        button.set_use_stock(True)
274
 
        button.set_label("gtk-close")
275
 
        button.connect("clicked", lambda w: self.destroy())
276
 
        button.show()
277
 
        
278
 
        box.pack_start(button, expand=False, fill=False)
279
 
 
280
 
        return box
281
 
 
282
 
 
283
 
class NoneRevision:
 
327
    def _create_back_button(self):
 
328
        button = gtk.Button()
 
329
        button.set_use_stock(True)
 
330
        button.set_label("gtk-go-back")
 
331
        button.connect("clicked", lambda w: self.go_back())
 
332
        button.set_relief(gtk.RELIEF_NONE)
 
333
        button.show()
 
334
        return button
 
335
 
 
336
    def _create_forward_button(self):
 
337
        button = gtk.Button()
 
338
        button.set_use_stock(True)
 
339
        button.set_label("gtk-go-forward")
 
340
        button.connect("clicked", lambda w: self.go_forward())
 
341
        button.set_relief(gtk.RELIEF_NONE)
 
342
        button.show()
 
343
        button.set_sensitive(False)
 
344
        return button
 
345
 
 
346
    def go_back(self):
 
347
        last_tree = self.tree
 
348
        rev_id = self._selected_revision()
 
349
        parent_id = self.revisions[rev_id].parent_ids[0]
 
350
        target_tree = self.branch.repository.revision_tree(parent_id)
 
351
        if self._go(target_tree):
 
352
            self.history.append(last_tree)
 
353
            self.forward_button.set_sensitive(True)
 
354
        else:
 
355
            self._no_back.add(parent_id)
 
356
            self.back_button.set_sensitive(False)
 
357
 
 
358
    def go_forward(self):
 
359
        if len(self.history) == 0:
 
360
            return
 
361
        target_tree = self.history.pop()
 
362
        if len(self.history) == 0:
 
363
            self.forward_button.set_sensitive(False)
 
364
        self._go(target_tree)
 
365
 
 
366
    def _go(self, target_tree):
 
367
        rev_id = self._selected_revision()
 
368
        if self.file_id in target_tree:
 
369
            offset = self.get_scroll_offset(target_tree)
 
370
            (row,), col = self.annoview.get_cursor()
 
371
            self.annotate(target_tree, self.branch, self.file_id)
 
372
            new_row = row+offset
 
373
            if new_row < 0:
 
374
                new_row = 0
 
375
            self.annoview.set_cursor(new_row)
 
376
            return True
 
377
        else:
 
378
            return False
 
379
 
 
380
    def get_scroll_offset(self, tree):
 
381
        old = self.tree.get_file(self.file_id)
 
382
        new = tree.get_file(self.file_id)
 
383
        (row,), col = self.annoview.get_cursor()
 
384
        matcher = patiencediff.PatienceSequenceMatcher(None, old.readlines(),
 
385
                                                       new.readlines())
 
386
        for i, j, n in matcher.get_matching_blocks():
 
387
            if i + n >= row:
 
388
                return j - i
 
389
 
 
390
 
 
391
class FakeRevision:
284
392
    """ A fake revision.
285
393
 
286
394
    For when a revision is referenced but not present.
287
395
    """
288
396
 
289
 
    def __init__(self, revision_id):
 
397
    def __init__(self, revision_id, committer='?', nick=None):
290
398
        self.revision_id = revision_id
291
399
        self.parent_ids = []
292
 
        self.committer = "?"
 
400
        self.committer = committer
293
401
        self.message = "?"
294
402
        self.timestamp = 0.0
295
403
        self.timezone = 0
 
404
        self.properties = {}
 
405
 
 
406
    def get_apparent_author(self):
 
407
        return self.committer
296
408
 
297
409
 
298
410
class RevisionCache(object):
299
411
    """A caching revision source"""
300
 
    def __init__(self, real_source):
 
412
    def __init__(self, real_source, seed_cache=None):
301
413
        self.__real_source = real_source
302
 
        self.__cache = {}
 
414
        if seed_cache is None:
 
415
            self.__cache = {}
 
416
        else:
 
417
            self.__cache = dict(seed_cache)
303
418
 
304
419
    def get_revision(self, revision_id):
305
420
        if revision_id not in self.__cache:
306
421
            revision = self.__real_source.get_revision(revision_id)
307
422
            self.__cache[revision_id] = revision
308
423
        return self.__cache[revision_id]
 
424
 
 
425
class SearchBox(gtk.HBox):
 
426
    """A button box for searching in text or lines of annotations"""
 
427
    def __init__(self):
 
428
        gtk.HBox.__init__(self, False, 6)
 
429
 
 
430
        # Close button
 
431
        button = gtk.Button()
 
432
        image = gtk.Image()
 
433
        image.set_from_stock('gtk-stop', gtk.ICON_SIZE_BUTTON)
 
434
        button.set_image(image)
 
435
        button.set_relief(gtk.RELIEF_NONE)
 
436
        button.connect("clicked", lambda w: self.hide_all())
 
437
        self.pack_start(button, expand=False, fill=False)
 
438
 
 
439
        # Search entry
 
440
        label = gtk.Label()
 
441
        self._label = label
 
442
        self.pack_start(label, expand=False, fill=False)
 
443
 
 
444
        entry = gtk.Entry()
 
445
        self._entry = entry
 
446
        entry.connect("activate", lambda w, d: self._do_search(d),
 
447
                      'forward')
 
448
        self.pack_start(entry, expand=False, fill=False)
 
449
 
 
450
        # Next/previous buttons
 
451
        button = gtk.Button('_Next')
 
452
        image = gtk.Image()
 
453
        image.set_from_stock('gtk-go-forward', gtk.ICON_SIZE_BUTTON)
 
454
        button.set_image(image)
 
455
        button.connect("clicked", lambda w, d: self._do_search(d),
 
456
                       'forward')
 
457
        self.pack_start(button, expand=False, fill=False)
 
458
 
 
459
        button = gtk.Button('_Previous')
 
460
        image = gtk.Image()
 
461
        image.set_from_stock('gtk-go-back', gtk.ICON_SIZE_BUTTON)
 
462
        button.set_image(image)
 
463
        button.connect("clicked", lambda w, d: self._do_search(d),
 
464
                       'backward')
 
465
        self.pack_start(button, expand=False, fill=False)
 
466
 
 
467
        # Search options
 
468
        check = gtk.CheckButton('Match case')
 
469
        self._match_case = check
 
470
        self.pack_start(check, expand=False, fill=False)
 
471
 
 
472
        check = gtk.CheckButton('Regexp')
 
473
        check.connect("toggled", lambda w: self._set_label())
 
474
        self._regexp = check
 
475
        self.pack_start(check, expand=False, fill=False)
 
476
 
 
477
        self._view = None
 
478
        self._column = None
 
479
        # Note that we stay hidden (we do not call self.show_all())
 
480
 
 
481
 
 
482
    def show_for(self, kind):
 
483
        self._kind = kind
 
484
        self.show_all()
 
485
        self._set_label()
 
486
        # Hide unrelated buttons
 
487
        if kind == 'line':
 
488
            self._match_case.hide()
 
489
            self._regexp.hide()
 
490
        # Be ready
 
491
        self._entry.grab_focus()
 
492
 
 
493
    def _set_label(self):
 
494
        if self._kind == 'line':
 
495
            self._label.set_text('Find Line: ')
 
496
        else:
 
497
            if self._regexp.get_active():
 
498
                self._label.set_text('Find Regexp: ')
 
499
            else:
 
500
                self._label.set_text('Find Text: ')
 
501
 
 
502
    def set_target(self, view,column):
 
503
        self._view = view
 
504
        self._column = column
 
505
 
 
506
    def _match(self, model, iterator, column):
 
507
        matching_case = self._match_case.get_active()
 
508
        string, = model.get(iterator, column)
 
509
        key = self._entry.get_text()
 
510
        if self._regexp.get_active():
 
511
            if matching_case:
 
512
                match = re.compile(key).search(string, 1)
 
513
            else:
 
514
                match = re.compile(key, re.I).search(string, 1)
 
515
        else:
 
516
            if not matching_case:
 
517
                string = string.lower()
 
518
                key = key.lower()
 
519
            match = string.find(key) != -1
 
520
 
 
521
        return match
 
522
 
 
523
    def _iterate_rows_forward(self, model, start):
 
524
        model_size = len(model)
 
525
        current = start + 1
 
526
        while model_size != 0:
 
527
            if current >= model_size: current =  0
 
528
            yield model.get_iter_from_string('%d' % current)
 
529
            if current == start: raise StopIteration
 
530
            current += 1
 
531
 
 
532
    def _iterate_rows_backward(self, model, start):
 
533
        model_size = len(model)
 
534
        current = start - 1
 
535
        while model_size != 0:
 
536
            if current < 0: current = model_size - 1
 
537
            yield model.get_iter_from_string('%d' % current)
 
538
            if current == start: raise StopIteration
 
539
            current -= 1
 
540
 
 
541
    def _do_search(self, direction):
 
542
        if direction == 'forward':
 
543
            iterate = self._iterate_rows_forward
 
544
        else:
 
545
            iterate = self._iterate_rows_backward
 
546
 
 
547
        model, sel = self._view.get_selection().get_selected()
 
548
        if sel is None:
 
549
            start = 0
 
550
        else:
 
551
            path = model.get_string_from_iter(sel)
 
552
            start = int(path)
 
553
 
 
554
        for row in iterate(model, start):
 
555
            if self._match(model, row, self._column):
 
556
                path = model.get_path(row)
 
557
                self._view.set_cursor(path)
 
558
                self._view.scroll_to_cell(path, use_align=True)
 
559
                break