/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: v.ladeuil+lp at free
  • Date: 2006-12-15 13:19:22 UTC
  • mto: (66.6.5 gtk)
  • mto: This revision was merged to the branch mainline in revision 128.
  • Revision ID: v.ladeuil+lp@free.fr-20061215131922-70g30rvh17smpjij
Better fix for bug #73965.

* annotate/gannotate.py:
(GAnnotateWindow._create): Add a search box and define C-f/C-g for
text/line search.
(GAnnotateWindow._search_by_text,GAnnotateWindow._search_by_line):
Callback for showing the search box and give it the focus.
(GAnnotateWindow._create_annotate_view): Restore the LINE_NUM_COL
as the default search column.
(SearchBox): New composite widget to search in the annomodel.

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
 
25
26
from bzrlib import tsort
26
27
from bzrlib.errors import NoSuchRevision
215
216
        pane.add2(self.logview)
216
217
        pane.show()
217
218
        vbox.pack_start(pane, expand=True, fill=True)
218
 
        
 
219
 
 
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,
 
224
                             gtk.ACCEL_LOCKED,
 
225
                             self._search_by_text)
 
226
        accels.connect_group(gtk.keysyms.g, gtk.gdk.CONTROL_MASK,
 
227
                             gtk.ACCEL_LOCKED,
 
228
                             self._search_by_line)
 
229
        self.add_accel_group(accels)
 
230
 
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)
224
236
 
225
237
        self.add(vbox)
226
238
 
 
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)
 
242
 
 
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)
 
246
 
227
247
    def row_diff(self, tv, path, tvc):
228
248
        row = path[0]
229
249
        revision = self.annotations[row]
292
312
        col.add_attribute(cell, "text", TEXT_LINE_COL)
293
313
        tv.append_column(col)
294
314
 
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)
297
318
 
298
319
        return tv
299
320
 
300
 
    def _match_text(self, model, column, key, iterator):
301
 
        """Returns 0 if text entered by user matches the line."""
302
 
 
303
 
        line, = self.annomodel.get(iterator, column)
304
 
        if line == '':
305
 
            match = False
306
 
        else:
307
 
            match = (line.find(key) != -1)
308
 
        # Gtk excepts False when we match
309
 
        return not match
310
 
 
311
321
    def _create_span_selector(self):
312
322
        ss = SpanSelector()
313
323
        ss.connect("span-changed", self._span_changed_cb)
325
335
        box = gtk.HButtonBox()
326
336
        box.set_layout(gtk.BUTTONBOX_END)
327
337
        box.show()
328
 
        
 
338
 
329
339
        button = gtk.Button()
330
340
        button.set_use_stock(True)
331
341
        button.set_label("gtk-close")
332
342
        button.connect("clicked", lambda w: self.destroy())
333
343
        button.show()
334
 
        
 
344
 
335
345
        box.pack_start(button, expand=False, fill=False)
336
346
 
337
347
        return box
363
373
            revision = self.__real_source.get_revision(revision_id)
364
374
            self.__cache[revision_id] = revision
365
375
        return self.__cache[revision_id]
 
376
 
 
377
class SearchBox(gtk.HBox):
 
378
    """A button box for searching in text or lines of annotations"""
 
379
    def __init__(self):
 
380
        gtk.HBox.__init__(self, False, 6)
 
381
 
 
382
        # Close button
 
383
        button = gtk.Button()
 
384
        image = gtk.Image()
 
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)
 
390
 
 
391
        # Search entry
 
392
        label = gtk.Label()
 
393
        self._label = label
 
394
        self.pack_start(label, expand=False, fill=False)
 
395
 
 
396
        entry = gtk.Entry()
 
397
        self._entry = entry
 
398
        entry.connect("activate", lambda w, d: self._do_search(d),
 
399
                      'forward')
 
400
        self.pack_start(entry, expand=False, fill=False)
 
401
 
 
402
        # Next/previous buttons
 
403
        button = gtk.Button('_Next')
 
404
        image = gtk.Image()
 
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),
 
408
                       'forward')
 
409
        self.pack_start(button, expand=False, fill=False)
 
410
 
 
411
        button = gtk.Button('_Previous')
 
412
        image = gtk.Image()
 
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),
 
416
                       'backward')
 
417
        self.pack_start(button, expand=False, fill=False)
 
418
 
 
419
        # Search options
 
420
        check = gtk.CheckButton('Match case')
 
421
        self._match_case = check
 
422
        self.pack_start(check, expand=False, fill=False)
 
423
 
 
424
        check = gtk.CheckButton('Regexp')
 
425
        check.connect("toggled", lambda w: self._set_label())
 
426
        self._regexp = check
 
427
        self.pack_start(check, expand=False, fill=False)
 
428
 
 
429
        self._view = None
 
430
        self._column = None
 
431
        # Note that we stay hidden (we do not call self.show_all())
 
432
 
 
433
 
 
434
    def show_for(self, kind):
 
435
        self._kind = kind
 
436
        self.show_all()
 
437
        self._set_label()
 
438
        # Hide unrelated buttons
 
439
        if kind == 'line':
 
440
            self._match_case.hide()
 
441
            self._regexp.hide()
 
442
        # Be ready
 
443
        self._entry.grab_focus()
 
444
 
 
445
    def _set_label(self):
 
446
        if self._kind == 'line':
 
447
            self._label.set_text('Find Line: ')
 
448
        else:
 
449
            if self._regexp.get_active():
 
450
                self._label.set_text('Find Regexp: ')
 
451
            else:
 
452
                self._label.set_text('Find Text: ')
 
453
 
 
454
    def set_target(self, view,column):
 
455
        self._view = view
 
456
        self._column = column
 
457
 
 
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():
 
463
            if matching_case:
 
464
                match = re.compile(key).search(string, 1)
 
465
            else:
 
466
                match = re.compile(key, re.I).search(string, 1)
 
467
        else:
 
468
            if not matching_case:
 
469
                string = string.lower()
 
470
                key = key.lower()
 
471
            match = string.find(key) != -1
 
472
 
 
473
        return match
 
474
 
 
475
    def _iterate_rows_forward(self, model, start):
 
476
        model_size = len(model)
 
477
        current = start + 1
 
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
 
482
            current += 1
 
483
 
 
484
    def _iterate_rows_backward(self, model, start):
 
485
        model_size = len(model)
 
486
        current = start - 1
 
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
 
491
            current -= 1
 
492
 
 
493
    def _do_search(self, direction):
 
494
        if direction == 'forward':
 
495
            iterate = self._iterate_rows_forward
 
496
        else:
 
497
            iterate = self._iterate_rows_backward
 
498
 
 
499
        model, sel = self._view.get_selection().get_selected()
 
500
        if sel is None:
 
501
            start = 0
 
502
        else:
 
503
            path = model.get_string_from_iter(sel)
 
504
            start = int(path)
 
505
 
 
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)
 
511
                break