Our own interactive-search enabling customized and delayed search.
This commit provides same search capabilities as Gtk's. The only difference should be the search being delayed by 150ms after last keypress. Signed-off-by: Bastien Jacquet <bastien.jacquet_dev@m4x.org>
This commit is contained in:
parent
22ef07cdeb
commit
d426f6232e
@ -35,6 +35,7 @@ from gi.repository import Pango
|
||||
from ..managedwindow import ManagedWindow
|
||||
from ..filters import SearchBar
|
||||
from ..glade import Glade
|
||||
from ..widgets.interactivesearchbox import InteractiveSearchBox
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
#
|
||||
@ -86,6 +87,10 @@ class BaseSelector(ManagedWindow):
|
||||
self.tree.connect('row-activated', self._on_row_activated)
|
||||
self.tree.grab_focus()
|
||||
|
||||
# connect to signal for custom interactive-search
|
||||
self.searchbox = InteractiveSearchBox(self.tree)
|
||||
self.tree.connect('key-press-event', self.searchbox.treeview_keypress)
|
||||
|
||||
#add the search bar
|
||||
self.search_bar = SearchBar(dbstate, uistate, self.build_tree)
|
||||
filter_box = self.search_bar.build()
|
||||
|
@ -71,6 +71,7 @@ _ = glocale.translation.sgettext
|
||||
from ..ddtargets import DdTargets
|
||||
from ..plug.quick import create_quickreport_menu, create_web_connect_menu
|
||||
from ..utils import is_right_click
|
||||
from ..widgets.interactivesearchbox import InteractiveSearchBox
|
||||
|
||||
#----------------------------------------------------------------
|
||||
#
|
||||
@ -157,6 +158,7 @@ class ListView(NavigationView):
|
||||
self.list.set_fixed_height_mode(True)
|
||||
self.list.connect('button-press-event', self._button_press)
|
||||
self.list.connect('key-press-event', self._key_press)
|
||||
self.searchbox = InteractiveSearchBox(self.list)
|
||||
|
||||
if self.drag_info():
|
||||
self.list.connect('drag_data_get', self.drag_data_get)
|
||||
@ -888,6 +890,9 @@ class ListView(NavigationView):
|
||||
if event.keyval in (Gdk.KEY_Return, Gdk.KEY_KP_Enter):
|
||||
self.edit(obj)
|
||||
return True
|
||||
# Custom interactive search
|
||||
if event.string:
|
||||
return self.searchbox.treeview_keypress(obj, event)
|
||||
return False
|
||||
|
||||
def _key_press_tree(self, obj, event):
|
||||
@ -896,16 +901,15 @@ class ListView(NavigationView):
|
||||
ENTER --> edit selection or open group node
|
||||
SHIFT+ENTER --> open group node and all children nodes
|
||||
"""
|
||||
if event.get_state() & Gdk.ModifierType.SHIFT_MASK:
|
||||
if event.keyval in (Gdk.KEY_Return, Gdk.KEY_KP_Enter):
|
||||
store, paths = self.selection.get_selected_rows()
|
||||
if paths:
|
||||
iter_ = self.model.get_iter(paths[0])
|
||||
handle = self.model.get_handle_from_iter(iter_)
|
||||
if len(paths) == 1 and handle is None:
|
||||
return self.expand_collapse_tree_branch()
|
||||
else:
|
||||
if event.keyval in (Gdk.KEY_Return, Gdk.KEY_KP_Enter):
|
||||
if (event.get_state() & Gdk.ModifierType.SHIFT_MASK and
|
||||
event.keyval in (Gdk.KEY_Return, Gdk.KEY_KP_Enter)):
|
||||
store, paths = self.selection.get_selected_rows()
|
||||
if paths:
|
||||
iter_ = self.model.get_iter(paths[0])
|
||||
handle = self.model.get_handle_from_iter(iter_)
|
||||
if len(paths) == 1 and handle is None:
|
||||
return self.expand_collapse_tree_branch()
|
||||
elif event.keyval in (Gdk.KEY_Return, Gdk.KEY_KP_Enter):
|
||||
store, paths = self.selection.get_selected_rows()
|
||||
if paths:
|
||||
iter_ = self.model.get_iter(paths[0])
|
||||
@ -915,6 +919,9 @@ class ListView(NavigationView):
|
||||
else:
|
||||
self.edit(obj)
|
||||
return True
|
||||
elif event.string:
|
||||
# Custom interactive search
|
||||
return self.searchbox.treeview_keypress(obj, event)
|
||||
return False
|
||||
|
||||
def expand_collapse_tree(self):
|
||||
|
@ -475,6 +475,7 @@ class FlatBaseModel(GObject.GObject, Gtk.TreeModel):
|
||||
col = self.sort_map[scol][1]
|
||||
else:
|
||||
col = scol
|
||||
# get the function that maps data to sort_keys
|
||||
self.sort_func = lambda x: glocale.sort_key(self.smap[col](x))
|
||||
self.sort_col = scol
|
||||
self.skip = skip
|
||||
|
479
gramps/gui/widgets/interactivesearchbox.py
Normal file
479
gramps/gui/widgets/interactivesearchbox.py
Normal file
@ -0,0 +1,479 @@
|
||||
#
|
||||
# Gramps - a GTK+/GNOME based genealogy program
|
||||
#
|
||||
# Copyright(C) 2014 Bastien Jacquet
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 2 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program 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 General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
#
|
||||
from gi.overrides.Gtk import TreeView, Gtk
|
||||
from gramps.gen.const import GRAMPS_LOCALE as glocale
|
||||
|
||||
"""
|
||||
GtkWidget showing a box for interactive-search in Gtk.TreeView
|
||||
"""
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
#
|
||||
# Python modules
|
||||
#
|
||||
#-------------------------------------------------------------------------
|
||||
import logging
|
||||
_LOG = logging.getLogger(".widgets.interactivesearch")
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
#
|
||||
# GTK modules
|
||||
#
|
||||
#-------------------------------------------------------------------------
|
||||
from gi.repository import GObject, Gtk, Gdk
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
#
|
||||
# InteractiveSearchBox class
|
||||
#
|
||||
#-------------------------------------------------------------------------
|
||||
|
||||
|
||||
class InteractiveSearchBox():
|
||||
"""
|
||||
Mainly adapted from gtktreeview.c
|
||||
"""
|
||||
_SEARCH_DIALOG_TIMEOUT = 5000
|
||||
_SEARCH_DIALOG_LAUNCH_TIMEOUT = 150
|
||||
|
||||
def __init__(self, treeview):
|
||||
self._treeview = treeview
|
||||
self._search_window = None
|
||||
self._search_entry = None
|
||||
self._search_entry_changed_id = 0
|
||||
self.__disable_popdown = False
|
||||
self._entry_flush_timeout = None
|
||||
self._entry_launchsearch_timeout = None
|
||||
self.__selected_search_result = None
|
||||
# Disable builtin interactive search by intercepting CTRL-F instead.
|
||||
# self._treeview.connect('start-interactive-search',
|
||||
# self.start_interactive_search)
|
||||
|
||||
def treeview_keypress(self, obj, event):
|
||||
"""
|
||||
function handling keypresses from the treeview
|
||||
for the typeahead find capabilities
|
||||
"""
|
||||
if not event.string:
|
||||
return False
|
||||
if self._key_cancels_search(event.keyval):
|
||||
return False
|
||||
self.ensure_interactive_directory()
|
||||
|
||||
# Make a copy of the current text
|
||||
old_text = self._search_entry.get_text()
|
||||
|
||||
popup_menu_id = self._search_entry.connect("popup-menu",
|
||||
lambda x: True)
|
||||
|
||||
# Move the entry off screen
|
||||
screen = self._treeview.get_screen()
|
||||
self._search_window.move(screen.get_width() + 1,
|
||||
screen.get_height() + 1)
|
||||
self._search_window.show()
|
||||
|
||||
# Send the event to the window. If the preedit_changed signal is
|
||||
# emitted during this event, we will set self.__imcontext_changed
|
||||
new_event = Gdk.Event.copy(event)
|
||||
new_event.window = self._search_window.get_window()
|
||||
self._search_window.realize()
|
||||
self.__imcontext_changed = False
|
||||
retval = self._search_window.event(new_event)
|
||||
self._search_window.hide()
|
||||
|
||||
self._search_entry.disconnect(popup_menu_id)
|
||||
|
||||
# Intercept CTRL+F keybinding because Gtk do not allow to _replace_ it.
|
||||
default_accel = obj.get_modifier_mask(
|
||||
Gdk.ModifierIntent.PRIMARY_ACCELERATOR)
|
||||
if ((event.state & (default_accel | Gdk.ModifierType.CONTROL_MASK))
|
||||
== (default_accel | Gdk.ModifierType.CONTROL_MASK)
|
||||
and event.keyval in [Gdk.KEY_f, Gdk.KEY_F]):
|
||||
self.__imcontext_changed = True
|
||||
# self.real_start_interactive_search(event.get_device(), True)
|
||||
|
||||
# We check to make sure that the entry tried to handle the text,
|
||||
# and that the text has changed.
|
||||
new_text = self._search_entry.get_text()
|
||||
text_modified = (old_text != new_text)
|
||||
if (self.__imcontext_changed or # we're in a preedit
|
||||
(retval and text_modified)): # ...or the text was modified
|
||||
self.real_start_interactive_search(event.get_device(), False)
|
||||
self._treeview.grab_focus()
|
||||
return True
|
||||
else:
|
||||
self._search_entry.set_text("")
|
||||
return False
|
||||
|
||||
def _preedit_changed(self, im_context, tree_view):
|
||||
self.__imcontext_changed = 1
|
||||
if(self._entry_flush_timeout):
|
||||
GObject.source_remove(self._entry_flush_timeout)
|
||||
self._entry_flush_timeout = GObject.timeout_add(
|
||||
self._SEARCH_DIALOG_TIMEOUT, self.cb_entry_flush_timeout)
|
||||
|
||||
def ensure_interactive_directory(self):
|
||||
toplevel = self._treeview.get_toplevel()
|
||||
screen = self._treeview.get_screen()
|
||||
if self._search_window:
|
||||
if toplevel.has_group():
|
||||
toplevel.get_group().add_window(self._search_window)
|
||||
elif self._search_window.has_group():
|
||||
self._search_window.get_group().remove_window(
|
||||
self._search_window)
|
||||
self._search_window.set_screen(screen)
|
||||
return
|
||||
|
||||
self._search_window = Gtk.Window(Gtk.WindowType.POPUP)
|
||||
self._search_window.set_screen(screen)
|
||||
if toplevel.has_group():
|
||||
toplevel.get_group().add_window(self._search_window)
|
||||
self._search_window.set_type_hint(Gdk.WindowTypeHint.UTILITY)
|
||||
self._search_window.set_modal(True)
|
||||
self._search_window.connect("delete-event", self._delete_event)
|
||||
self._search_window.connect("key-press-event", self._key_press_event)
|
||||
self._search_window.connect("button-press-event",
|
||||
self._button_press_event)
|
||||
self._search_window.connect("scroll-event", self._scroll_event)
|
||||
frame = Gtk.Frame()
|
||||
frame.set_shadow_type(Gtk.ShadowType.ETCHED_IN)
|
||||
frame.show()
|
||||
self._search_window.add(frame)
|
||||
|
||||
vbox = Gtk.VBox()
|
||||
vbox.show()
|
||||
frame.add(vbox)
|
||||
vbox.set_border_width(3)
|
||||
|
||||
""" add entry """
|
||||
# To be change by Gtk 3.10 SearchEntry when agreed
|
||||
if (Gtk.get_major_version(), Gtk.get_minor_version()) >= (3, 6):
|
||||
self._search_entry = Gtk.SearchEntry()
|
||||
else:
|
||||
self._search_entry = Gtk.Entry()
|
||||
self._search_entry.show()
|
||||
self._search_entry.connect("populate-popup", self._disable_popdown)
|
||||
self._search_entry.connect("activate", self._activate)
|
||||
self._search_entry.connect("preedit-changed", self._preedit_changed)
|
||||
|
||||
vbox.add(self._search_entry)
|
||||
self._search_entry.realize()
|
||||
|
||||
def real_start_interactive_search(self, device, keybinding):
|
||||
"""
|
||||
Pops up the interactive search entry. If keybinding is TRUE then
|
||||
the user started this by typing the start_interactive_search
|
||||
keybinding. Otherwise, it came from just typing
|
||||
"""
|
||||
if (self._search_window.get_visible()):
|
||||
return True
|
||||
self.ensure_interactive_directory()
|
||||
if keybinding:
|
||||
self._search_entry.set_text("")
|
||||
self._position_func()
|
||||
self._search_window.show()
|
||||
if self._search_entry_changed_id == 0:
|
||||
self._search_entry_changed_id = \
|
||||
self._search_entry.connect("changed", self.delayed_changed)
|
||||
|
||||
# Grab focus without selecting all the text
|
||||
self._search_entry.grab_focus()
|
||||
self._search_entry.set_position(-1)
|
||||
# send focus-in event
|
||||
event = Gdk.Event(Gdk.EventType.FOCUS_CHANGE)
|
||||
event.focus_change.in_ = True
|
||||
event.focus_change.window = self._search_window.get_window()
|
||||
self._search_entry.emit('focus-in-event', event)
|
||||
# search first matching iter
|
||||
self.delayed_changed(self._search_entry)
|
||||
# uncomment when deleting delayed_changed
|
||||
# self.search_init(self._search_entry)
|
||||
return True
|
||||
|
||||
def cb_entry_flush_timeout(self):
|
||||
event = Gdk.Event(Gdk.EventType.FOCUS_CHANGE)
|
||||
event.focus_change.in_ = True
|
||||
event.focus_change.window = self._treeview.get_window()
|
||||
self._dialog_hide(event)
|
||||
self._entry_flush_timeout = 0
|
||||
return False
|
||||
|
||||
def delayed_changed(self, obj):
|
||||
"""
|
||||
This permits to start the search only a short delay after last keypress
|
||||
This becomes useless with Gtk 3.10 Gtk.SearchEntry, which has a
|
||||
'search-changed' signal.
|
||||
"""
|
||||
# renew flush timeout
|
||||
self._renew_flush_timeout()
|
||||
# renew search timeout
|
||||
if self._entry_launchsearch_timeout:
|
||||
GObject.source_remove(self._entry_launchsearch_timeout)
|
||||
self._entry_launchsearch_timeout = GObject.timeout_add(
|
||||
self._SEARCH_DIALOG_LAUNCH_TIMEOUT, self.search_init)
|
||||
|
||||
def search_init(self):
|
||||
"""
|
||||
This is the function performing the search
|
||||
"""
|
||||
self._entry_launchsearch_timeout = 0
|
||||
text = self._search_entry.get_text()
|
||||
if not text:
|
||||
return
|
||||
|
||||
model = self._treeview.get_model()
|
||||
selection = self._treeview.get_selection()
|
||||
# disable flush timeout while searching
|
||||
if self._entry_flush_timeout:
|
||||
GObject.source_remove(self._entry_flush_timeout)
|
||||
self._entry_flush_timeout = 0
|
||||
# search
|
||||
# cursor_path = self._treeview.get_cursor()[0]
|
||||
# model.get_iter(cursor_path)
|
||||
start_iter = model.get_iter_first()
|
||||
self.search_iter(selection, start_iter, text, 0, 1)
|
||||
self.__selected_search_result = 1
|
||||
# renew flush timeout
|
||||
self._renew_flush_timeout()
|
||||
|
||||
def _renew_flush_timeout(self):
|
||||
if self._entry_flush_timeout:
|
||||
GObject.source_remove(self._entry_flush_timeout)
|
||||
self._entry_flush_timeout = GObject.timeout_add(
|
||||
self._SEARCH_DIALOG_TIMEOUT, self.cb_entry_flush_timeout)
|
||||
|
||||
def _move(self, up=False):
|
||||
text = self._search_entry.get_text()
|
||||
if not text:
|
||||
return
|
||||
|
||||
if up and self.__selected_search_result == 1:
|
||||
return False
|
||||
|
||||
model = self._treeview.get_model()
|
||||
selection = self._treeview.get_selection()
|
||||
# disable flush timeout while searching
|
||||
if self._entry_flush_timeout:
|
||||
GObject.source_remove(self._entry_flush_timeout)
|
||||
self._entry_flush_timeout = 0
|
||||
# search
|
||||
start_count = self.__selected_search_result + (-1 if up else 1)
|
||||
start_iter = model.get_iter_first()
|
||||
found_iter = self.search_iter(selection, start_iter, text, 0,
|
||||
start_count)
|
||||
if found_iter:
|
||||
self.__selected_search_result += (-1 if up else 1)
|
||||
return True
|
||||
else:
|
||||
# Return to old iter
|
||||
self.search_iter(selection, start_iter, text, 0,
|
||||
self.__selected_search_result)
|
||||
return False
|
||||
# renew flush timeout
|
||||
self._renew_flush_timeout()
|
||||
return
|
||||
|
||||
def _activate(self, obj):
|
||||
self.cb_entry_flush_timeout()
|
||||
# If we have a row selected and it's the cursor row, we activate
|
||||
# the row XXX
|
||||
# if self._cursor_node and \
|
||||
# self._cursor_node.set_flag(Gtk.GTK_RBNODE_IS_SELECTED):
|
||||
# path = _gtk_tree_path_new_from_rbtree(
|
||||
# tree_view->priv->cursor_tree,
|
||||
# tree_view->priv->cursor_node)
|
||||
# gtk_tree_view_row_activated(tree_view, path,
|
||||
# tree_view->priv->focus_column)
|
||||
|
||||
def _button_press_event(self, obj, event):
|
||||
if not obj:
|
||||
return
|
||||
# keyb_device = event.device
|
||||
event = Gdk.Event(Gdk.EventType.FOCUS_CHANGE)
|
||||
event.focus_change.in_ = True
|
||||
event.focus_change.window = self._treeview.get_window()
|
||||
self._dialog_hide(event)
|
||||
|
||||
def _disable_popdown(self, obj, menu):
|
||||
self.__disable_popdown = 1
|
||||
menu.connect("hide", self._enable_popdown)
|
||||
|
||||
def _enable_popdown(self, obj):
|
||||
self._timeout_enable_popdown = GObject.timeout_add(
|
||||
self._SEARCH_DIALOG_TIMEOUT, self._real_search_enable_popdown)
|
||||
|
||||
def _real_search_enable_popdown(self):
|
||||
self.__disable_popdown = 0
|
||||
|
||||
def _delete_event(self, obj, event):
|
||||
if not obj:
|
||||
return
|
||||
self._dialog_hide(None)
|
||||
|
||||
def _scroll_event(self, obj, event):
|
||||
retval = False
|
||||
if (event.direction == Gdk.ScrollDirection.UP):
|
||||
self._move(True)
|
||||
retval = True
|
||||
elif (event.direction == Gdk.ScrollDirection.DOWN):
|
||||
self._move(False)
|
||||
retval = True
|
||||
if retval:
|
||||
self._renew_flush_timeout()
|
||||
|
||||
def _key_cancels_search(self, keyval):
|
||||
return keyval in [Gdk.KEY_Escape,
|
||||
Gdk.KEY_Tab,
|
||||
Gdk.KEY_KP_Tab,
|
||||
Gdk.KEY_ISO_Left_Tab]
|
||||
|
||||
def _key_press_event(self, widget, event):
|
||||
retval = False
|
||||
# close window and cancel the search
|
||||
if self._key_cancels_search(event.keyval):
|
||||
self.cb_entry_flush_timeout()
|
||||
return True
|
||||
# Launch search
|
||||
if (event.keyval in [Gdk.KEY_Return, Gdk.KEY_KP_Enter]):
|
||||
if self._entry_launchsearch_timeout:
|
||||
GObject.source_remove(self._entry_launchsearch_timeout)
|
||||
self._entry_launchsearch_timeout = 0
|
||||
self.search_init()
|
||||
retval = True
|
||||
|
||||
default_accel = widget.get_modifier_mask(
|
||||
Gdk.ModifierIntent.PRIMARY_ACCELERATOR)
|
||||
# select previous matching iter
|
||||
if ((event.keyval in [Gdk.KEY_Up, Gdk.KEY_KP_Up]) or
|
||||
(((event.state & (default_accel | Gdk.ModifierType.SHIFT_MASK))
|
||||
== (default_accel | Gdk.ModifierType.SHIFT_MASK))
|
||||
and (event.keyval in [Gdk.KEY_g, Gdk.KEY_G]))):
|
||||
if(not self._move(True)):
|
||||
widget.error_bell()
|
||||
retval = True
|
||||
|
||||
# select next matching iter
|
||||
if ((event.keyval in [Gdk.KEY_Down, Gdk.KEY_KP_Down]) or
|
||||
(((event.state & (default_accel | Gdk.ModifierType.SHIFT_MASK))
|
||||
== (default_accel))
|
||||
and (event.keyval in [Gdk.KEY_g, Gdk.KEY_G]))):
|
||||
if(not self._move(False)):
|
||||
widget.error_bell()
|
||||
retval = True
|
||||
|
||||
# renew the flush timeout
|
||||
if retval:
|
||||
self._renew_flush_timeout()
|
||||
return retval
|
||||
|
||||
def _dialog_hide(self, event):
|
||||
if self.__disable_popdown:
|
||||
return
|
||||
if self._search_entry_changed_id:
|
||||
self._search_entry.disconnect(self._search_entry_changed_id)
|
||||
self._search_entry_changed_id = 0
|
||||
if self._entry_flush_timeout:
|
||||
GObject.source_remove(self._entry_flush_timeout)
|
||||
self._entry_flush_timeout = 0
|
||||
if self._entry_launchsearch_timeout:
|
||||
GObject.source_remove(self._entry_launchsearch_timeout)
|
||||
self._entry_launchsearch_timeout = 0
|
||||
if self._search_window.get_visible():
|
||||
# send focus-in event
|
||||
self._search_entry.emit('focus-out-event', event)
|
||||
self._search_window.hide()
|
||||
self._search_entry.set_text("")
|
||||
self._treeview.emit('focus-in-event', event)
|
||||
self.__selected_search_result = None
|
||||
|
||||
def _position_func(self, userdata=None):
|
||||
tree_window = self._treeview.get_window()
|
||||
screen = self._treeview.get_screen()
|
||||
|
||||
monitor_num = screen.get_monitor_at_window(tree_window)
|
||||
monitor = screen.get_monitor_workarea(monitor_num)
|
||||
|
||||
self._search_window.realize()
|
||||
ret, tree_x, tree_y = tree_window.get_origin()
|
||||
tree_width = tree_window.get_width()
|
||||
tree_height = tree_window.get_height()
|
||||
_, requisition = self._search_window.get_preferred_size()
|
||||
|
||||
if tree_x + tree_width > screen.get_width():
|
||||
x = screen.get_width() - requisition.width
|
||||
elif tree_x + tree_width - requisition.width < 0:
|
||||
x = 0
|
||||
else:
|
||||
x = tree_x + tree_width - requisition.width
|
||||
|
||||
if tree_y + tree_height + requisition.height > screen.get_height():
|
||||
y = screen.get_height() - requisition.height
|
||||
elif(tree_y + tree_height < 0): # isn't really possible ...
|
||||
y = 0
|
||||
else:
|
||||
y = tree_y + tree_height
|
||||
|
||||
self._search_window.move(x, y)
|
||||
|
||||
def search_iter(self, selection, cur_iter, text, count, n):
|
||||
"""
|
||||
Standard row-by-row search through all rows
|
||||
Should work for both List/Tree models
|
||||
Both expanded and collapsed rows are searched.
|
||||
"""
|
||||
model = self._treeview.get_model()
|
||||
search_column = self._treeview.get_search_column()
|
||||
is_tree = not (model.get_flags() & Gtk.TreeModelFlags.LIST_ONLY)
|
||||
while True:
|
||||
if (self.search_equal_func(model, search_column,
|
||||
text, cur_iter)):
|
||||
count += 1
|
||||
if (count == n):
|
||||
found_path = model.get_path(cur_iter)
|
||||
self._treeview.expand_to_path(found_path)
|
||||
self._treeview.scroll_to_cell(found_path, None, 1, 0.5, 0)
|
||||
selection.select_path(found_path)
|
||||
self._treeview.set_cursor(found_path)
|
||||
return True
|
||||
|
||||
if is_tree and model.iter_has_child(cur_iter):
|
||||
cur_iter = model.iter_children(cur_iter)
|
||||
else:
|
||||
done = False
|
||||
while True: # search iter of next row
|
||||
next_iter = model.iter_next(cur_iter)
|
||||
if next_iter:
|
||||
cur_iter = next_iter
|
||||
done = True
|
||||
else:
|
||||
cur_iter = model.iter_parent(cur_iter)
|
||||
if(not cur_iter):
|
||||
# we've run out of tree, done with this func
|
||||
return False
|
||||
if done:
|
||||
break
|
||||
return False
|
||||
|
||||
@staticmethod
|
||||
def search_equal_func(model, search_column, text, cur_iter):
|
||||
value = model.get_value(cur_iter, search_column)
|
||||
key1 = value.lower()
|
||||
key2 = text.lower()
|
||||
return key1.startswith(key2)
|
Loading…
Reference in New Issue
Block a user