GTK UI search box pre-filter implementation.

Implement a pre-filter for the search-box which will filter the currently visible torrents while waiting for the filter request to sent to the demon. This will make the searches seem way faster :)
This commit is contained in:
Pedro Algarvio 2011-05-31 14:36:05 +01:00
parent ea438609bf
commit b521b3065b
2 changed files with 50 additions and 11 deletions

View File

@ -215,7 +215,7 @@
<property name="use_action_appearance">False</property> <property name="use_action_appearance">False</property>
<property name="label" translatable="yes">_Find ...</property> <property name="label" translatable="yes">_Find ...</property>
<property name="use_underline">True</property> <property name="use_underline">True</property>
<signal name="activate" handler="on_find_menuitem_activate"/> <signal name="activate" handler="on_search_filter_toggle"/>
<accelerator key="f" signal="activate" modifiers="GDK_CONTROL_MASK"/> <accelerator key="f" signal="activate" modifiers="GDK_CONTROL_MASK"/>
</widget> </widget>
</child> </child>
@ -388,7 +388,7 @@ This will filter torrents for the current selection on the sidebar.</property>
<property name="label" translatable="yes">_Filter</property> <property name="label" translatable="yes">_Filter</property>
<property name="use_underline">True</property> <property name="use_underline">True</property>
<property name="stock_id">gtk-find</property> <property name="stock_id">gtk-find</property>
<signal name="clicked" handler="on_toolbutton_filter_clicked"/> <signal name="clicked" handler="on_search_filter_toggle"/>
<accelerator key="f" signal="clicked" modifiers="GDK_CONTROL_MASK"/> <accelerator key="f" signal="clicked" modifiers="GDK_CONTROL_MASK"/>
</widget> </widget>
<packing> <packing>

View File

@ -190,7 +190,7 @@ class SearchBox(object):
self.window = torrentview.window self.window = torrentview.window
self.visible = False self.visible = False
self.search_pending = None self.search_pending = self.prefiltered = None
self.search_box = self.window.main_glade.get_widget("search_box") self.search_box = self.window.main_glade.get_widget("search_box")
self.search_torrents_entry = self.window.main_glade.get_widget("search_torrents_entry") self.search_torrents_entry = self.window.main_glade.get_widget("search_torrents_entry")
@ -206,11 +206,14 @@ class SearchBox(object):
self.visible = False self.visible = False
self.clear_search() self.clear_search()
self.search_box.hide_all() self.search_box.hide_all()
self.search_pending = self.prefiltered = None
def clear_search(self): def clear_search(self):
if self.search_pending and self.search_pending.active(): if self.search_pending and self.search_pending.active():
self.search_pending.cancel() self.search_pending.cancel()
self.prefiltered = None
self.search_torrents_entry.set_text("") self.search_torrents_entry.set_text("")
if self.torrentview.filter and 'name' in self.torrentview.filter: if self.torrentview.filter and 'name' in self.torrentview.filter:
self.torrentview.filter.pop('name', None) self.torrentview.filter.pop('name', None)
@ -233,17 +236,51 @@ class SearchBox(object):
if self.match_search_button.get_active(): if self.match_search_button.get_active():
search_string += '::match' search_string += '::match'
self.torrentview.filter['name'] = search_string self.torrentview.filter['name'] = search_string
self.prefilter_torrentview()
def prefilter_torrentview(self):
filter_column = self.torrentview.columns["filter"].column_indices[0]
torrent_id_column = self.torrentview.columns["torrent_id"].column_indices[0]
torrent_name_column = self.torrentview.columns[_("Name")].column_indices[1]
match_case = self.match_search_button.get_active()
if match_case:
search_string = self.search_torrents_entry.get_text()
else:
search_string = self.search_torrents_entry.get_text().lower()
if self.prefiltered is None:
self.prefiltered = []
for row in self.torrentview.liststore:
torrent_id = row[torrent_id_column]
if torrent_id in self.prefiltered:
# Reset to previous filter state
self.prefiltered.pop(self.prefiltered.index(torrent_id))
row[filter_column] = not row[filter_column]
if not row[filter_column]:
# Row is not visible(filtered out, but not by our filter), skip it
continue
if match_case:
torrent_name = row[torrent_name_column]
else:
torrent_name = row[torrent_name_column].lower()
if search_string in torrent_name and not row[filter_column]:
row[filter_column] = True
self.prefiltered.append(torrent_id)
elif search_string not in torrent_name and row[filter_column]:
row[filter_column] = False
self.prefiltered.append(torrent_id)
def on_close_search_button_clicked(self, widget): def on_close_search_button_clicked(self, widget):
self.hide() self.hide()
def on_find_menuitem_activate(self, widget): def on_search_filter_toggle(self, widget):
if self.visible:
self.hide()
else:
self.show()
def on_toolbutton_filter_clicked(self, widget):
if self.visible: if self.visible:
self.hide() self.hide()
else: else:
@ -252,7 +289,7 @@ class SearchBox(object):
def on_search_torrents_match_toggled(self, widget): def on_search_torrents_match_toggled(self, widget):
if self.search_torrents_entry.get_text(): if self.search_torrents_entry.get_text():
self.set_search_filter() self.set_search_filter()
self.search_pending = reactor.callLater(0.5, self.torrentview.update) self.search_pending = reactor.callLater(0.7, self.torrentview.update)
def on_search_torrents_entry_icon_press(self, entry, icon, event): def on_search_torrents_entry_icon_press(self, entry, icon, event):
if icon != gtk.ENTRY_ICON_SECONDARY: if icon != gtk.ENTRY_ICON_SECONDARY:
@ -517,6 +554,8 @@ class TorrentView(listview.ListView, component.Component):
"""Callback function for get_torrents_status(). 'status' should be a """Callback function for get_torrents_status(). 'status' should be a
dictionary of {torrent_id: {key, value}}.""" dictionary of {torrent_id: {key, value}}."""
self.status = status self.status = status
if self.search_box.prefiltered is not None:
self.search_box.prefiltered = None
if self.status == self.prev_status and self.prev_status: if self.status == self.prev_status and self.prev_status:
# We do not bother updating since the status hasn't changed # We do not bother updating since the status hasn't changed
self.prev_status = self.status self.prev_status = self.status