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