diff --git a/deluge/core/filtermanager.py b/deluge/core/filtermanager.py index e04cb9dbb..c52fec29b 100644 --- a/deluge/core/filtermanager.py +++ b/deluge/core/filtermanager.py @@ -78,6 +78,12 @@ def filter_one_keyword(torrent_ids, keyword): yield torrent_id break +def filter_by_name(torrent_ids, search_string): + all_torrents = component.get("TorrentManager").torrents + for torrent_id in torrent_ids: + if search_string[0].lower() in all_torrents[torrent_id].filename.lower(): + yield torrent_id + def tracker_error_filter(torrent_ids, values): filtered_torrent_ids = [] tm = component.get("TorrentManager") @@ -108,6 +114,7 @@ class FilterManager(component.Component): self.torrents = core.torrentmanager self.registered_filters = {} self.register_filter("keyword", filter_keywords) + self.register_filter("name", filter_by_name) self.tree_fields = {} self.register_tree_field("state", self._init_state_tree) diff --git a/deluge/ui/gtkui/glade/main_window.glade b/deluge/ui/gtkui/glade/main_window.glade index 4dd91c296..97dbd5509 100644 --- a/deluge/ui/gtkui/glade/main_window.glade +++ b/deluge/ui/gtkui/glade/main_window.glade @@ -384,174 +384,217 @@ - + True False - + True - False False - Add torrent - False - Add Torrent - True - gtk-add - + + + True + False + False + True + Add torrent + False + Add Torrent + True + gtk-add + + + + False + True + + + + + True + False + False + True + Remove torrent + False + Remove Torrent + gtk-remove + + + + False + True + + + + + True + False + + + False + + + + + True + False + False + True + Pause the selected torrents + False + Pause + True + gtk-media-pause + + + + False + True + + + + + True + False + False + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + True + Resume the selected torrents + False + Resume + gtk-media-play + + + + False + True + + + + + True + False + + + False + + + + + True + False + False + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + True + Queue Torrent Up + False + Queue Up + gtk-go-up + + + + False + True + + + + + True + False + False + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + True + Queue Torrent Down + False + Queue Down + gtk-go-down + + + + False + True + + + + + True + False + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + + + False + + + + + True + False + True + Preferences + False + Preferences + True + gtk-preferences + + + + False + True + + + + + True + False + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + True + Connection Manager + False + Connection Manager + gtk-network + + + + False + True + + - False - True + True + True + 0 - + True - False - False - Remove torrent - False - Remove Torrent - gtk-remove - + True + Search torrents by name + + True + False + gtk-clear + False + True + False + True + Clear the search + + False - True - - - - - True - False - - - False - - - - - True - False - False - Pause the selected torrents - False - Pause - True - gtk-media-pause - - - - False - True - - - - - True - False - False - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - Resume the selected torrents - False - Resume - gtk-media-play - - - - False - True - - - - - True - False - - - False - - - - - True - False - False - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - Queue Torrent Up - False - Queue Up - gtk-go-up - - - - False - True - - - - - True - False - False - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - Queue Torrent Down - False - Queue Down - gtk-go-down - - - - False - True - - - - - True - False - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - - - False - - - - - True - False - Preferences - False - Preferences - True - gtk-preferences - - - - False - True - - - - - True - False - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - Connection Manager - False - Connection Manager - gtk-network - - - - False - True + False + 5 + 1 False - True + False 1 @@ -641,152 +684,6 @@ - - True - False - - - gtk-open - True - False - False - True - True - - - - - - True - False - - - - - _Expand All - True - False - False - True - False - - - - True - False - gtk-zoom-fit - 1 - - - - - - - True - False - - - - - _Do Not Download - True - False - False - True - False - - - - True - False - gtk-no - 1 - - - - - - - _Normal Priority - True - False - False - True - False - - - - True - False - gtk-yes - 1 - - - - - - - _High Priority - True - False - False - True - False - - - - True - False - gtk-go-up - 1 - - - - - - - Hi_ghest Priority - True - False - False - True - False - - - - True - False - gtk-goto-top - 1 - - - - - - - True - False - - - _Add Peer - True - False - Add a peer by its IP - False - True - False - - - - True - False - gtk-add - 1 - - - - - False GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK diff --git a/deluge/ui/gtkui/torrentview.py b/deluge/ui/gtkui/torrentview.py index ab23f45ad..9221d3bf7 100644 --- a/deluge/ui/gtkui/torrentview.py +++ b/deluge/ui/gtkui/torrentview.py @@ -46,6 +46,8 @@ import logging import warnings from urlparse import urlparse +from twisted.internet import reactor + import deluge.common import deluge.component as component from deluge.ui.client import client @@ -270,6 +272,7 @@ class TorrentView(listview.ListView, component.Component): # Set filter to None for now self.filter = None + self.search_pending = None ### Connect Signals ### # Connect to the 'button-press-event' to know when to bring up the @@ -287,6 +290,15 @@ class TorrentView(listview.ListView, component.Component): self.treeview.connect("key-press-event", self.on_key_press_event) self.treeview.connect("columns-changed", self.on_columns_changed_event) + self.search_torrents_entry = self.window.main_glade.get_widget("search_torrents_entry") + self.search_torrents_entry.connect( + "icon-press", self.on_search_torrents_entry_icon_press + ) + self.search_torrents_entry.connect( + "changed", self.on_search_torrents_entry_changed + ) + + client.register_event_handler("TorrentStateChangedEvent", self.on_torrentstatechanged_event) client.register_event_handler("TorrentAddedEvent", self.on_torrentadded_event) client.register_event_handler("TorrentRemovedEvent", self.on_torrentremoved_event) @@ -319,6 +331,8 @@ class TorrentView(listview.ListView, component.Component): # We need to clear the liststore self.liststore.clear() self.prev_status = {} + self.filter = None + self.search_torrents_entry.set_text("") def shutdown(self): """Called when GtkUi is exiting""" @@ -335,7 +349,10 @@ class TorrentView(listview.ListView, component.Component): """Sets filters for the torrentview.. see: core.get_torrents_status """ + search_filter = self.filter and self.filter.get('name', None) or None self.filter = dict(filter_dict) #copied version of filter_dict. + if search_filter and 'name' not in filter_dict: + self.filter['name'] = search_filter self.update() def set_columns_to_update(self, columns=None): @@ -379,6 +396,9 @@ class TorrentView(listview.ListView, component.Component): def update(self): if self.got_state: + if self.search_pending is not None and self.search_pending.active(): + # An update request is scheduled, let's wait for that one + return # Send a status request gobject.idle_add(self.send_status_request) @@ -600,3 +620,33 @@ class TorrentView(listview.ListView, component.Component): torrentmenu = component.get("MenuBar").torrentmenu torrentmenu.popup(None, None, None, 3, event.time) return True + + def on_search_torrents_entry_icon_press(self, entry, icon, event): + if icon != gtk.ENTRY_ICON_SECONDARY: + return + + if self.search_pending and self.search_pending.active(): + self.search_pending.cancel() + + entry.set_text("") + if self.filter and 'name' in self.filter: + self.filter.pop('name', None) + self.search_pending = reactor.callLater(0.7, self.update) + + def on_search_torrents_entry_changed(self, widget): + search_string = widget.get_text().lower() + + if self.search_pending and self.search_pending.active(): + self.search_pending.cancel() + + if not search_string: + if self.filter and 'name' in self.filter: + self.filter.pop('name', None) + self.search_pending = reactor.callLater(0.7, self.update) + return + + if self.filter is None: + self.filter = {} + + self.filter['name'] = search_string + self.search_pending = reactor.callLater(0.7, self.update)