Source code for kiwi.ui.entrycompletion

#
# Kiwi: a Framework and Enhanced Widgets for Python
#
# Copyright (C) 2006 Async Open Source
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2.1 of the License, or (at your option) any later version.
#
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307
# USA
#
# Author(s): Ronaldo Maia <romaia@async.com.br>
#

import gobject
import gtk
from gtk import gdk
from gtk import keysyms

from kiwi.utils import gsignal, type_register

COMPLETION_TIMEOUT = 300
PAGE_INCREMENT = 14

[docs]class KiwiEntryCompletion(gtk.EntryCompletion): def __init__(self): gtk.EntryCompletion.__init__(self) self._inline_completion = False self._popup_completion = True self._entry = None self._completion_timeout = 0 self._match_function = None self._match_function_data = None self._key = None self.changed_id = 0 self._filter_model = None self._treeview = None self._popup_window = None self._selected_index = -1 gsignal('match-selected', 'override')
[docs] def do_match_selected(self, model, iter): self._entry.set_text(model[iter][0]) return True
def _visible_function(self, model, iter, data=None): if not self._entry: return False if not self._key: return False if self._match_function: return self._match_function(self, self._key, iter) value = model[iter][0] if not value: return False entry_text = self._entry.get_text() return value.lower().startswith(entry_text.lower()) def _connect_completion_signals(self): if self._popup_completion: self.changed_id = self._entry.connect('changed', self._on_completion_changed) self._entry.connect('key-press-event', self._on_completion_key_press) self._entry.connect('button-press-event', self._on_button_press_event) def _on_button_press_event(self, window, event): # If we're clicking outside of the window, close the popup if not self._popup_window: return if (event.window != self._popup_window.window or (tuple(self._popup_window.allocation.intersect( gdk.Rectangle(x=int(event.x), y=int(event.y), width=1, height=1)))) == (0, 0, 0, 0)): self.popdown() def _on_completion_timeout(self): if self._completion_timeout: gobject.source_remove(self._completion_timeout) self._completion_timeout = 0 minimum_key_length = self.get_property('minimum-key-length') if (self._filter_model and len(self._entry.get_text()) >= minimum_key_length and self._entry.is_focus()): self.complete() matches = self._filter_model.iter_n_children(None) if matches: self.popup() return False def _on_completion_changed(self, entry): if (self.get_property('minimum_key_length') > 0 and not self._entry.get_text()): self.popdown() return self._selected_index = -1 timeout = gobject.timeout_add(COMPLETION_TIMEOUT, self._on_completion_timeout) self._completion_timeout = timeout return True def _select_item(self, index): # Make the selection matches = self._filter_model.iter_n_children(None) if 0 <= index < matches: self._treeview.set_cursor((index,)) else: selection = self._treeview.get_selection() selection.unselect_all() self._selected_index = index def _on_completion_key_press(self, entry, event): window = self._popup_window if window and not window.flags() & gtk.VISIBLE: return False if not self._treeview: return False matches = self._filter_model.iter_n_children(None) keyval = event.keyval index = self._selected_index if keyval == keysyms.Up or keyval == keysyms.KP_Up: index -= 1 if index < -1: index = matches -1 self._select_item(index) return True elif keyval == keysyms.Down or keyval == keysyms.KP_Down: index += 1 if index > matches-1: index = -1 self._select_item(index) return True elif keyval == keysyms.Page_Up: if index < 0: index = matches-1 elif index > 0 and index - PAGE_INCREMENT < 0: index = 0 else: index -= PAGE_INCREMENT if index < 0: index = -1 self._select_item(index) return True elif keyval == keysyms.Page_Down: if index < 0: index = 0 elif index < matches-1 and index + PAGE_INCREMENT > matches - 1: index = matches -1 else: index += PAGE_INCREMENT if index > matches: index = -1 self._select_item(index) return True elif keyval == keysyms.Escape: self.popdown() return True elif (keyval == keysyms.Return or keyval == keysyms.KP_Enter): self.popdown() selection = self._treeview.get_selection() model, titer = selection.get_selected() if not titer: return False self._entry.handler_block(self.changed_id) self.emit('match-selected', model, titer) self._entry.handler_unblock(self.changed_id) selection.unselect_all() return True return False def _popup_grab_window(self): activate_time = 0L if gdk.pointer_grab(self._entry.window, True, (gdk.BUTTON_PRESS_MASK | gdk.BUTTON_RELEASE_MASK | gdk.POINTER_MOTION_MASK), None, None, activate_time) == 0: if gdk.keyboard_grab(self._entry.window, True, activate_time) == 0: return True else: self._entry.window.get_display().pointer_ungrab(activate_time); return False return False def _popup_ungrab_window(self): activate_time = 0L self._entry.window.get_display().pointer_ungrab(activate_time); self._entry.window.get_display().keyboard_ungrab(activate_time); # Public API
[docs] def complete(self): if not self._filter_model: return self._key = self._entry.get_text() self._filter_model.refilter() self._treeview.set_model(self._filter_model) if self._treeview.flags() & gtk.REALIZED: self._treeview.scroll_to_point(0,0)
[docs] def set_entry(self, entry): self._entry = entry self._connect_completion_signals()
[docs] def get_entry(self): return self._entry
[docs] def set_popup_window(self, window): self._popup_window = window
[docs] def set_treeview(self, treeview): self._treeview = treeview
[docs] def get_treeview(self): return self._treeview
[docs] def popup(self): if not self._popup_window: return self._popup_window.popup(text=None, filter=True) self._popup_grab_window()
[docs] def popdown(self): if not self._popup_window: return self._popup_window.popdown() self._popup_ungrab_window()
[docs] def set_model(self, model): if not model: if self._popup_window: self._popup_window.set_model(None) self.popdown() self._model = None self._filter_model = None return self._model = model self._filter_model = model.filter_new() self._filter_model.set_visible_func(self._visible_function) if self._popup_window: self._popup_window.set_model(self._filter_model)
[docs] def get_model(self): return self._model
[docs] def set_match_func(self, function, data=None): self._match_function = function self._match_function_data = data
type_register(KiwiEntryCompletion)