~ubuntu-branches/ubuntu/saucy/terminator/saucy

« back to all changes in this revision

Viewing changes to terminatorlib/searchbar.py

  • Committer: Bazaar Package Importer
  • Author(s): Nicolas Valcárcel Scerpella (Canonical)
  • Date: 2010-04-07 17:10:31 UTC
  • mfrom: (1.1.7 upstream)
  • Revision ID: james.westby@ubuntu.com-20100407171031-35nsuj0tmbub0bj5
Tags: 0.92-0ubuntu1
* New upstream release
* Remove python-xdg from Recommends. (Closes: #567967)
* Downgrade python-gnome2 to Recommends.
* Update python-gtk2 dependency to (>= 2.14.0)
* Add python-keybinder to Recommends

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
#!/usr/bin/python
 
2
# Terminator by Chris Jones <cmsj@tenshu.net>
 
3
# GPL v2 only
 
4
"""searchbar.py - classes necessary to provide a terminal search bar"""
 
5
 
 
6
import gtk
 
7
import gobject
 
8
 
 
9
from translation import _
 
10
from config import Config
 
11
 
 
12
# pylint: disable-msg=R0904
 
13
class Searchbar(gtk.HBox):
 
14
    """Class implementing the Searchbar widget"""
 
15
 
 
16
    __gsignals__ = {
 
17
        'end-search': (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, ()),
 
18
    }
 
19
 
 
20
    entry = None
 
21
    reslabel = None
 
22
    next = None
 
23
    prev = None
 
24
 
 
25
    vte = None
 
26
    config = None
 
27
 
 
28
    searchstring = None
 
29
    searchrow = None
 
30
 
 
31
    searchits = None
 
32
 
 
33
    def __init__(self):
 
34
        """Class initialiser"""
 
35
        gtk.HBox.__init__(self)
 
36
        self.__gobject_init__()
 
37
 
 
38
        self.config = Config()
 
39
 
 
40
        # Search text
 
41
        self.entry = gtk.Entry()
 
42
        self.entry.set_activates_default(True)
 
43
        self.entry.show()
 
44
        self.entry.connect('activate', self.do_search)
 
45
        self.entry.connect('key-press-event', self.search_keypress)
 
46
 
 
47
        # Label
 
48
        label = gtk.Label(_('Search:'))
 
49
        label.show()
 
50
 
 
51
        # Result label
 
52
        self.reslabel = gtk.Label('')
 
53
        self.reslabel.show()
 
54
 
 
55
        # Close Button
 
56
        close = gtk.Button()
 
57
        close.set_relief(gtk.RELIEF_NONE)
 
58
        close.set_focus_on_click(False)
 
59
        icon = gtk.Image()
 
60
        icon.set_from_stock(gtk.STOCK_CLOSE, gtk.ICON_SIZE_MENU)
 
61
        close.add(icon)
 
62
        close.set_name('terminator-search-close-button')
 
63
        if hasattr(close, 'set_tooltip_text'):
 
64
            close.set_tooltip_text(_('Close Search bar'))
 
65
        close.connect('clicked', self.end_search)
 
66
        close.show_all()
 
67
 
 
68
        # Next Button
 
69
        self.next = gtk.Button(_('Next'))
 
70
        self.next.show()
 
71
        self.next.set_sensitive(False)
 
72
        self.next.connect('clicked', self.next_search)
 
73
 
 
74
        # Previous Button
 
75
        self.prev = gtk.Button(_('Prev'))
 
76
        self.prev.show()
 
77
        self.prev.set_sensitive(False)
 
78
        self.prev.connect('clicked', self.prev_search)
 
79
 
 
80
        self.pack_start(label, False)
 
81
        self.pack_start(self.entry)
 
82
        self.pack_start(self.reslabel, False)
 
83
        self.pack_start(self.prev, False, False)
 
84
        self.pack_start(self.next, False, False)
 
85
        self.pack_end(close, False, False)
 
86
 
 
87
        self.hide()
 
88
        self.set_no_show_all(True)
 
89
 
 
90
    def get_vte(self):
 
91
        """Find our parent widget"""
 
92
        parent = self.get_parent()
 
93
        if parent:
 
94
            self.vte = parent.vte
 
95
 
 
96
    # pylint: disable-msg=W0613
 
97
    def search_keypress(self, widget, event):
 
98
        """Handle keypress events"""
 
99
        key = gtk.gdk.keyval_name(event.keyval)
 
100
        if key == 'Escape':
 
101
            self.end_search()
 
102
 
 
103
    def start_search(self):
 
104
        """Show ourselves"""
 
105
        if not self.vte:
 
106
            self.get_vte()
 
107
 
 
108
        self.show()
 
109
        self.entry.grab_focus()
 
110
 
 
111
    def do_search(self, widget):
 
112
        """Trap and re-emit the clicked signal"""
 
113
        searchtext = self.entry.get_text()
 
114
        if searchtext == '':
 
115
            return
 
116
 
 
117
        if searchtext != self.searchstring:
 
118
            self.searchrow = self.get_vte_buffer_range()[0]
 
119
            self.searchstring = searchtext
 
120
 
 
121
        self.reslabel.set_text(_("Searching scrollback"))
 
122
        self.next.set_sensitive(True)
 
123
        self.prev.set_sensitive(True)
 
124
        self.next_search(None)
 
125
 
 
126
    def next_search(self, widget):
 
127
        """Search forwards and jump to the next result, if any"""
 
128
        startrow,endrow = self.get_vte_buffer_range()
 
129
        while True:
 
130
            if self.searchrow == endrow:
 
131
                self.searchrow = startrow
 
132
                self.reslabel.set_text(_('No more results'))
 
133
                return
 
134
            buffer = self.vte.get_text_range(self.searchrow, 0, 
 
135
                                             self.searchrow, -1,
 
136
                                             self.search_character)
 
137
 
 
138
            index = buffer.find(self.searchstring)
 
139
            if index != -1:
 
140
                self.search_hit(self.searchrow)
 
141
                self.searchrow += 1
 
142
                return
 
143
            self.searchrow += 1
 
144
 
 
145
    # FIXME: There is an issue in switching search direction, probably because
 
146
    # we increment/decrement self.searchrow after each search iteration
 
147
    def prev_search(self, widget):
 
148
        """Jump back to the previous search"""
 
149
        startrow,endrow = self.get_vte_buffer_range()
 
150
        while True:
 
151
            if self.searchrow == startrow:
 
152
                self.searchrow = endrow
 
153
                self.reslabel.set_text(_('No more results'))
 
154
                return
 
155
            buffer = self.vte.get_text_range(self.searchrow, 0,
 
156
                                             self.searchrow, -1,
 
157
                                             self.search_character)
 
158
 
 
159
            index = buffer.find(self.searchstring)
 
160
            if index != -1:
 
161
                self.search_hit(self.searchrow)
 
162
                self.searchrow -= 1
 
163
                return
 
164
            self.searchrow -= 1
 
165
 
 
166
    def search_hit(self, row):
 
167
        """Update the UI for a search hit"""
 
168
        self.reslabel.set_text("%s %d" % (_('Found at row'), row))
 
169
        self.get_parent().scrollbar_jump(row)
 
170
        self.next.show()
 
171
        self.prev.show()
 
172
 
 
173
    def search_character(self, widget, col, row, junk):
 
174
        """We have to have a callback for each character"""
 
175
        return(True)
 
176
 
 
177
    def get_vte_buffer_range(self):
 
178
        """Get the range of a vte widget"""
 
179
        column, endrow = self.vte.get_cursor_position()
 
180
        startrow = max(0, endrow - self.config['scrollback_lines'])
 
181
        return(startrow, endrow)
 
182
 
 
183
    def end_search(self, widget=None):
 
184
        """Trap and re-emit the end-search signal"""
 
185
        self.searchrow = 0
 
186
        self.searchstring = None
 
187
        self.reslabel.set_text('')
 
188
        self.emit('end-search')
 
189
 
 
190
    def get_search_term(self):
 
191
        """Return the currently set search term"""
 
192
        return(self.entry.get_text())
 
193
 
 
194
gobject.type_register(Searchbar)