2
# Terminator by Chris Jones <cmsj@tenshu.net>
4
"""searchbar.py - classes necessary to provide a terminal search bar"""
9
from translation import _
10
from config import Config
12
# pylint: disable-msg=R0904
13
class Searchbar(gtk.HBox):
14
"""Class implementing the Searchbar widget"""
17
'end-search': (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, ()),
34
"""Class initialiser"""
35
gtk.HBox.__init__(self)
36
self.__gobject_init__()
38
self.config = Config()
41
self.entry = gtk.Entry()
42
self.entry.set_activates_default(True)
44
self.entry.connect('activate', self.do_search)
45
self.entry.connect('key-press-event', self.search_keypress)
48
label = gtk.Label(_('Search:'))
52
self.reslabel = gtk.Label('')
57
close.set_relief(gtk.RELIEF_NONE)
58
close.set_focus_on_click(False)
60
icon.set_from_stock(gtk.STOCK_CLOSE, gtk.ICON_SIZE_MENU)
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)
69
self.next = gtk.Button(_('Next'))
71
self.next.set_sensitive(False)
72
self.next.connect('clicked', self.next_search)
75
self.prev = gtk.Button(_('Prev'))
77
self.prev.set_sensitive(False)
78
self.prev.connect('clicked', self.prev_search)
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)
88
self.set_no_show_all(True)
91
"""Find our parent widget"""
92
parent = self.get_parent()
96
# pylint: disable-msg=W0613
97
def search_keypress(self, widget, event):
98
"""Handle keypress events"""
99
key = gtk.gdk.keyval_name(event.keyval)
103
def start_search(self):
109
self.entry.grab_focus()
111
def do_search(self, widget):
112
"""Trap and re-emit the clicked signal"""
113
searchtext = self.entry.get_text()
117
if searchtext != self.searchstring:
118
self.searchrow = self.get_vte_buffer_range()[0]
119
self.searchstring = searchtext
121
self.reslabel.set_text(_("Searching scrollback"))
122
self.next.set_sensitive(True)
123
self.prev.set_sensitive(True)
124
self.next_search(None)
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()
130
if self.searchrow == endrow:
131
self.searchrow = startrow
132
self.reslabel.set_text(_('No more results'))
134
buffer = self.vte.get_text_range(self.searchrow, 0,
136
self.search_character)
138
index = buffer.find(self.searchstring)
140
self.search_hit(self.searchrow)
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()
151
if self.searchrow == startrow:
152
self.searchrow = endrow
153
self.reslabel.set_text(_('No more results'))
155
buffer = self.vte.get_text_range(self.searchrow, 0,
157
self.search_character)
159
index = buffer.find(self.searchstring)
161
self.search_hit(self.searchrow)
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)
173
def search_character(self, widget, col, row, junk):
174
"""We have to have a callback for each character"""
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)
183
def end_search(self, widget=None):
184
"""Trap and re-emit the end-search signal"""
186
self.searchstring = None
187
self.reslabel.set_text('')
188
self.emit('end-search')
190
def get_search_term(self):
191
"""Return the currently set search term"""
192
return(self.entry.get_text())
194
gobject.type_register(Searchbar)