215
216
pane.add2(self.logview)
217
218
vbox.pack_start(pane, expand=True, fill=True)
220
self._search = SearchBox()
221
vbox.pack_start(self._search, expand=False, fill=True)
222
accels = gtk.AccelGroup()
223
accels.connect_group(gtk.keysyms.f, gtk.gdk.CONTROL_MASK,
225
self._search_by_text)
226
accels.connect_group(gtk.keysyms.g, gtk.gdk.CONTROL_MASK,
228
self._search_by_line)
229
self.add_accel_group(accels)
219
231
hbox = gtk.HBox(True, 6)
220
232
hbox.pack_start(self.span_selector, expand=False, fill=True)
221
233
hbox.pack_start(self._create_button_box(), expand=False, fill=True)
239
def _search_by_text(self, accel_group, window, key, modifiers):
240
self._search.show_for('text')
241
self._search.set_target(self.annoview, self.annomodel, TEXT_LINE_COL)
243
def _search_by_line(self, accel_group, window, key, modifiers):
244
self._search.show_for('line')
245
self._search.set_target(self.annoview, self.annomodel, LINE_NUM_COL)
227
247
def row_diff(self, tv, path, tvc):
229
249
revision = self.annotations[row]
292
312
col.add_attribute(cell, "text", TEXT_LINE_COL)
293
313
tv.append_column(col)
295
tv.set_search_column(TEXT_LINE_COL)
296
tv.set_search_equal_func(self._match_text)
315
# FIXME: Now that C-f is now used for search by text we
316
# may as well disable the auto search.
317
tv.set_search_column(LINE_NUM_COL)
300
def _match_text(self, model, column, key, iterator):
301
"""Returns 0 if text entered by user matches the line."""
303
line, = self.annomodel.get(iterator, column)
307
match = (line.find(key) != -1)
308
# Gtk excepts False when we match
311
321
def _create_span_selector(self):
312
322
ss = SpanSelector()
313
323
ss.connect("span-changed", self._span_changed_cb)
363
373
revision = self.__real_source.get_revision(revision_id)
364
374
self.__cache[revision_id] = revision
365
375
return self.__cache[revision_id]
377
class SearchBox(gtk.HBox):
378
"""A button box for searching in text or lines of annotations"""
380
gtk.HBox.__init__(self, False, 6)
383
button = gtk.Button()
385
image.set_from_stock('gtk-stop', gtk.ICON_SIZE_BUTTON)
386
button.set_image(image)
387
button.set_relief(gtk.RELIEF_NONE)
388
button.connect("clicked", lambda w: self.hide_all())
389
self.pack_start(button, expand=False, fill=False)
394
self.pack_start(label, expand=False, fill=False)
398
entry.connect("activate", lambda w, d: self._do_search(d),
400
self.pack_start(entry, expand=False, fill=False)
402
# Next/previous buttons
403
button = gtk.Button('_Next')
405
image.set_from_stock('gtk-go-forward', gtk.ICON_SIZE_BUTTON)
406
button.set_image(image)
407
button.connect("clicked", lambda w, d: self._do_search(d),
409
self.pack_start(button, expand=False, fill=False)
411
button = gtk.Button('_Previous')
413
image.set_from_stock('gtk-go-back', gtk.ICON_SIZE_BUTTON)
414
button.set_image(image)
415
button.connect("clicked", lambda w, d: self._do_search(d),
417
self.pack_start(button, expand=False, fill=False)
420
check = gtk.CheckButton('Match case')
421
self._match_case = check
422
self.pack_start(check, expand=False, fill=False)
424
check = gtk.CheckButton('Regexp')
425
check.connect("toggled", lambda w: self._set_label())
427
self.pack_start(check, expand=False, fill=False)
431
# Note that we stay hidden (we do not call self.show_all())
434
def show_for(self, kind):
438
# Hide unrelated buttons
440
self._match_case.hide()
443
self._entry.grab_focus()
445
def _set_label(self):
446
if self._kind == 'line':
447
self._label.set_text('Find Line: ')
449
if self._regexp.get_active():
450
self._label.set_text('Find Regexp: ')
452
self._label.set_text('Find Text: ')
454
def set_target(self, view,column):
456
self._column = column
458
def _match(self, model, iterator, column):
459
matching_case = self._match_case.get_active()
460
string, = model.get(iterator, column)
461
key = self._entry.get_text()
462
if self._regexp.get_active():
464
match = re.compile(key).search(string, 1)
466
match = re.compile(key, re.I).search(string, 1)
468
if not matching_case:
469
string = string.lower()
471
match = string.find(key) != -1
475
def _iterate_rows_forward(self, model, start):
476
model_size = len(model)
478
while model_size != 0:
479
if current >= model_size: current = 0
480
yield model.get_iter_from_string('%d' % current)
481
if current == start: raise StopIteration
484
def _iterate_rows_backward(self, model, start):
485
model_size = len(model)
487
while model_size != 0:
488
if current < 0: current = model_size - 1
489
yield model.get_iter_from_string('%d' % current)
490
if current == start: raise StopIteration
493
def _do_search(self, direction):
494
if direction == 'forward':
495
iterate = self._iterate_rows_forward
497
iterate = self._iterate_rows_backward
499
model, sel = self._view.get_selection().get_selected()
503
path = model.get_string_from_iter(sel)
506
for row in iterate(model, start):
507
if self._match(model, row, self._column):
508
path = model.get_path(row)
509
self._view.set_cursor(path)
510
self._view.scroll_to_cell(path, use_align=True)