diff --git a/ChangeLog b/ChangeLog index c2cc26e48..83d3bfa1c 100644 --- a/ChangeLog +++ b/ChangeLog @@ -9,6 +9,8 @@ * #1112: Fix renaming files in add torrent dialog * #1247: Fix deluge-gtk from hanging on shutdown * #995: Rewrote tracker_icons + * Make the distinction between adding to the session new unmanaged torrents and torrents loaded from state. This will break backwards compatability. + * Pass a copy of an event instead of passing the event arguments to the event handlers. This will break backwards compatability. ==== GtkUI ==== * Fix uncaught exception when closing deluge in classic mode diff --git a/deluge/config.py b/deluge/config.py index 4f5571209..5dbb68197 100644 --- a/deluge/config.py +++ b/deluge/config.py @@ -261,7 +261,10 @@ what is currently in the config and it could not convert the value """ if isinstance(self.__config[key], str): - return self.__config[key].decode("utf8") + try: + return self.__config[key].decode("utf8") + except UnicodeDecodeError: + return self.__config[key] else: return self.__config[key] diff --git a/deluge/core/eventmanager.py b/deluge/core/eventmanager.py index 198507007..1199813d8 100644 --- a/deluge/core/eventmanager.py +++ b/deluge/core/eventmanager.py @@ -55,7 +55,7 @@ class EventManager(component.Component): if event.name in self.handlers: for handler in self.handlers[event.name]: #log.debug("Running handler %s for event %s with args: %s", event.name, handler, event.args) - handler(*event.args) + handler(event.copy()) def register_event_handler(self, event, handler): """ diff --git a/deluge/core/rpcserver.py b/deluge/core/rpcserver.py index ef2e3342f..2858b3b30 100644 --- a/deluge/core/rpcserver.py +++ b/deluge/core/rpcserver.py @@ -486,7 +486,8 @@ class RPCServer(component.Component): # Find sessions interested in this event for session_id, interest in self.factory.interested_events.iteritems(): if event.name in interest: - log.debug("Emit Event: %s %s", event.name, event.args) + log.debug("Emit Event: %s %s", event.name, zip(event.__slots__, + event.args)) # This session is interested so send a RPC_EVENT self.factory.session_protocols[session_id].sendData( (RPC_EVENT, event.name, event.args) diff --git a/deluge/core/torrentmanager.py b/deluge/core/torrentmanager.py index 22e139343..b02443cb6 100644 --- a/deluge/core/torrentmanager.py +++ b/deluge/core/torrentmanager.py @@ -477,10 +477,17 @@ class TorrentManager(component.Component): # Save the session state self.save_state() - # Emit the torrent_added signal - component.get("EventManager").emit(TorrentAddedEvent(torrent.torrent_id)) - - log.info("Torrent %s added by user: %s", torrent.get_status(["name"])["name"], component.get("RPCServer").get_session_user()) + # Emit torrent_added signal + from_state = False + if torrent_info and state is None: + from_state = True + component.get("EventManager").emit( + TorrentAddedEvent(torrent.torrent_id, from_state) + ) + log.info("Torrent %s %s by user: %s", + torrent.get_status(["name"])["name"], + (from_state and "added" or "loaded"), + component.get("RPCServer").get_session_user()) return torrent.torrent_id def load_torrent(self, torrent_id): diff --git a/deluge/event.py b/deluge/event.py index 62aa011d0..a4fc8b4a3 100644 --- a/deluge/event.py +++ b/deluge/event.py @@ -2,6 +2,7 @@ # event.py # # Copyright (C) 2009 Andrew Resch +# Copyright (C) 2010 Pedro Algarvio # # Deluge is free software. # @@ -47,6 +48,8 @@ class DelugeEventMetaClass(type): """ This metaclass simply keeps a list of all events classes created. """ + __slots__ = () + def __init__(cls, name, bases, dct): super(DelugeEventMetaClass, cls).__init__(name, bases, dct) if name != "DelugeEvent": @@ -62,56 +65,68 @@ class DelugeEvent(object): :type args: list """ + __slots__ = () __metaclass__ = DelugeEventMetaClass def _get_name(self): return self.__class__.__name__ + name = property(fget=_get_name) def _get_args(self): - if not hasattr(self, "_args"): - return [] - return self._args - - name = property(fget=_get_name) + return [getattr(self, arg) for arg in self.__slots__] args = property(fget=_get_args) + def copy(self): + return self.__class__(*self.args) + class TorrentAddedEvent(DelugeEvent): """ Emitted when a new torrent is successfully added to the session. """ - def __init__(self, torrent_id): + __slots__ = ('torrent_id', 'from_state') + + def __init__(self, torrent_id, from_state): """ :param torrent_id: the torrent_id of the torrent that was added :type torrent_id: string + :param from_state: was the torrent loaded from state? Or is it a new torrent. + :type from_state: bool """ - self._args = [torrent_id] + self.torrent_id = torrent_id + self.from_state = from_state class TorrentRemovedEvent(DelugeEvent): """ Emitted when a torrent has been removed from the session. """ + __slots__ = ('torrent_id',) + def __init__(self, torrent_id): """ :param torrent_id: the torrent_id :type torrent_id: string """ - self._args = [torrent_id] + self.torrent_id = torrent_id class PreTorrentRemovedEvent(DelugeEvent): """ Emitted when a torrent is about to be removed from the session. """ + __slots__ = ('torrent_id',) + def __init__(self, torrent_id): """ :param torrent_id: the torrent_id :type torrent_id: string """ - self._args = [torrent_id] + self.torrent_id = torrent_id class TorrentStateChangedEvent(DelugeEvent): """ Emitted when a torrent changes state. """ + __slots__ = ('torrent_id', 'state') + def __init__(self, torrent_id, state): """ :param torrent_id: the torrent_id @@ -119,18 +134,20 @@ class TorrentStateChangedEvent(DelugeEvent): :param state: the new state :type state: string """ - self._args = [torrent_id, state] + self.torrent_id = torrent_id + self.state = state class TorrentQueueChangedEvent(DelugeEvent): """ Emitted when the queue order has changed. """ - pass class TorrentFolderRenamedEvent(DelugeEvent): """ Emitted when a folder within a torrent has been renamed. """ + __slots__ = ('torrent_id', 'old', 'new') + def __init__(self, torrent_id, old, new): """ :param torrent_id: the torrent_id @@ -140,44 +157,54 @@ class TorrentFolderRenamedEvent(DelugeEvent): :param new: the new folder name :type new: string """ - self._args = [torrent_id, old, new] + self.torrent_id = torrent_id + self.old = old + self.new = new class TorrentFileRenamedEvent(DelugeEvent): """ Emitted when a file within a torrent has been renamed. """ - def __init__(self, torrent_id, index, name): + __slots__ = ('torrent_id', 'index', 'filename') + + def __init__(self, torrent_id, index, filename): """ :param torrent_id: the torrent_id :type torrent_id: string :param index: the index of the file :type index: int - :param name: the new filename - :type name: string + :param filename: the new filename + :type filename: string """ - self._args = [torrent_id, index, name] + self.torrent_id = torrent_id + self.index = index + self.filename = filename class TorrentFinishedEvent(DelugeEvent): """ Emitted when a torrent finishes downloading. """ + __slots__ = ('torrent_id',) + def __init__(self, torrent_id): """ :param torrent_id: the torrent_id :type torrent_id: string """ - self._args = [torrent_id] + self.torrent_id = torrent_id class TorrentResumedEvent(DelugeEvent): """ Emitted when a torrent resumes from a paused state. """ + __slots__ = ('torrent_id',) + def __init__(self, torrent_id): """ :param torrent_id: the torrent_id :type torrent_id: string """ - self._args = [torrent_id] + self.torrent_id = torrent_id class TorrentFileCompletedEvent(DelugeEvent): """ @@ -186,6 +213,8 @@ class TorrentFileCompletedEvent(DelugeEvent): This will only work with libtorrent 0.15 or greater. """ + __slots__ = ('torrent_id', 'index') + def __init__(self, torrent_id, index): """ :param torrent_id: the torrent_id @@ -193,68 +222,75 @@ class TorrentFileCompletedEvent(DelugeEvent): :param index: the file index :type index: int """ - self._args = [torrent_id, index] + self.torrent_id = torrent_id + self.index = index class NewVersionAvailableEvent(DelugeEvent): """ Emitted when a more recent version of Deluge is available. """ + __slots__ = ('new_release',) + def __init__(self, new_release): """ :param new_release: the new version that is available :type new_release: string """ - self._args = [new_release] + self.new_release = new_release class SessionStartedEvent(DelugeEvent): """ Emitted when a session has started. This typically only happens once when the daemon is initially started. """ - pass class SessionPausedEvent(DelugeEvent): """ Emitted when the session has been paused. """ - pass class SessionResumedEvent(DelugeEvent): """ Emitted when the session has been resumed. """ - pass class ConfigValueChangedEvent(DelugeEvent): """ Emitted when a config value changes in the Core. """ + __slots__ = ('key', 'value') + def __init__(self, key, value): """ :param key: the key that changed :type key: string :param value: the new value of the `:param:key` """ - self._args = [key, value] + self.key = key + self.value = value class PluginEnabledEvent(DelugeEvent): """ Emitted when a plugin is enabled in the Core. """ - def __init__(self, name): + __slots__ = ('plugin_name',) + + def __init__(self, plugin_name): """ - :param name: the plugin name - :type name: string + :param plugin_name: the plugin name + :type plugin_name: string """ - self._args = [name] + self.plugin_name = plugin_name class PluginDisabledEvent(DelugeEvent): """ Emitted when a plugin is disabled in the Core. """ - def __init__(self, name): + __slots__ = ('plugin_name',) + + def __init__(self, plugin_name): """ - :param name: the plugin name - :type name: string + :param plugin_name: the plugin name + :type plugin_name: string """ - self._args = [name] + self.plugin_name = plugin_name diff --git a/deluge/plugins/autoadd/autoadd/core.py b/deluge/plugins/autoadd/autoadd/core.py index 67d3cc409..4f48a9799 100644 --- a/deluge/plugins/autoadd/autoadd/core.py +++ b/deluge/plugins/autoadd/autoadd/core.py @@ -81,8 +81,6 @@ MAX_NUM_ATTEMPTS = 10 class AutoaddOptionsChangedEvent(DelugeEvent): """Emitted when the options for the plugin are changed.""" - def __init__(self): - pass def CheckInput(cond, message): if not cond: diff --git a/deluge/plugins/autoadd/autoadd/gtkui.py b/deluge/plugins/autoadd/autoadd/gtkui.py index 98d3b7c62..9ad27cb9f 100644 --- a/deluge/plugins/autoadd/autoadd/gtkui.py +++ b/deluge/plugins/autoadd/autoadd/gtkui.py @@ -334,7 +334,7 @@ class GtkUI(GtkPluginBase): def on_show_prefs(self): client.autoadd.get_config().addCallback(self.cb_get_config) - def on_options_changed_event(self): + def on_options_changed_event(self, event): client.autoadd.get_config().addCallback(self.cb_get_config) def cb_get_config(self, config): diff --git a/deluge/plugins/execute/execute/core.py b/deluge/plugins/execute/execute/core.py index 54362b1c7..1dda1c802 100644 --- a/deluge/plugins/execute/execute/core.py +++ b/deluge/plugins/execute/execute/core.py @@ -64,15 +64,19 @@ class ExecuteCommandAddedEvent(DelugeEvent): """ Emitted when a new command is added. """ + __slots__ = ('command_id', 'event', 'command') def __init__(self, command_id, event, command): - self._args = [command_id, event, command] + self.command_id = command_id + self.event = event + self.command = command class ExecuteCommandRemovedEvent(DelugeEvent): """ Emitted when a command is removed. """ + __slots__ = ('command_id',) def __init__(self, command_id): - self._args = [command_id] + self.command_id = command_id class Core(CorePluginBase): def enable(self): @@ -82,17 +86,17 @@ class Core(CorePluginBase): # Go through the commands list and register event handlers for command in self.config["commands"]: - event = command[EXECUTE_EVENT] - if event in self.registered_events: + event_name = command[EXECUTE_EVENT] + if event_name in self.registered_events: continue - def create_event_handler(event): - def event_handler(torrent_id): - self.execute_commands(torrent_id, event) + def create_event_handler(event_name): + def event_handler(event): + self.execute_commands(event.torrent_id, event_name) return event_handler - event_handler = create_event_handler(event) - event_manager.register_event_handler(EVENT_MAP[event], event_handler) - self.registered_events[event] = event_handler + event_handler = create_event_handler(event_name) + event_manager.register_event_handler(EVENT_MAP[event_name], event_handler) + self.registered_events[event_name] = event_handler log.debug("Execute core plugin enabled!") diff --git a/deluge/plugins/execute/execute/gtkui.py b/deluge/plugins/execute/execute/gtkui.py index 3cd148a55..c1102a76e 100644 --- a/deluge/plugins/execute/execute/gtkui.py +++ b/deluge/plugins/execute/execute/gtkui.py @@ -161,13 +161,13 @@ class ExecutePreferences(object): command = widget.get_text() client.execute.save_command(command_id, event, command) - def on_command_added_event(self, command_id, event, command): - log.debug("Adding command %s: %s", event, command) - self.add_command(command_id, event, command) + def on_command_added_event(self, event): + log.debug("Adding command %s: %s", event.event, event.command) + self.add_command(event.command_id, event.event, event.command) - def on_command_removed_event(self, command_id): - log.debug("Removing command %s", command_id) - self.remove_command(command_id) + def on_command_removed_event(self, event): + log.debug("Removing command %s", event.command_id) + self.remove_command(event.command_id) class GtkUI(GtkPluginBase): diff --git a/deluge/plugins/extractor/extractor/core.py b/deluge/plugins/extractor/extractor/core.py index e84534533..d8d5d8fd7 100644 --- a/deluge/plugins/extractor/extractor/core.py +++ b/deluge/plugins/extractor/extractor/core.py @@ -77,14 +77,14 @@ class Core(CorePluginBase): def update(self): pass - def _on_torrent_finished(self, torrent_id): + def _on_torrent_finished(self, event): """ This is called when a torrent finishes. We need to check to see if there are any files to extract. """ # Get the save path - save_path = component.get("TorrentManager")[torrent_id].get_status(["save_path"])["save_path"] - files = component.get("TorrentManager")[torrent_id].get_files() + save_path = component.get("TorrentManager")[event.torrent_id].get_status(["save_path"])["save_path"] + files = component.get("TorrentManager")[event.torrent_id].get_files() for f in files: ext = os.path.splitext(f["path"]) if ext[1] in (".gz", ".bz2", ".lzma"): @@ -104,7 +104,7 @@ class Core(CorePluginBase): # Get the destination path dest = self.config["extract_path"] if self.config["use_name_folder"]: - name = component.get("TorrentManager")[torrent_id].get_status(["name"])["name"] + name = component.get("TorrentManager")[event.torrent_id].get_status(["name"])["name"] dest = os.path.join(dest, name) # Create the destination folder if it doesn't exist @@ -126,8 +126,8 @@ class Core(CorePluginBase): # Run the command and add some callbacks d = getProcessValue(cmd[0], cmd[1].split() + [str(fp)], {}, str(dest)) - d.addCallback(on_extract_success, torrent_id) - d.addErrback(on_extract_failed, torrent_id) + d.addCallback(on_extract_success, event.torrent_id) + d.addErrback(on_extract_failed, event.torrent_id) @export def set_config(self, config): diff --git a/deluge/plugins/freespace/freespace/core.py b/deluge/plugins/freespace/freespace/core.py index eb90ecb68..0e4846a3d 100644 --- a/deluge/plugins/freespace/freespace/core.py +++ b/deluge/plugins/freespace/freespace/core.py @@ -55,12 +55,14 @@ class LowDiskSpaceEvent(DelugeEvent): """Triggered when the available space for a specific path is getting too low. """ + __slots__ = ('percents_dict',) + def __init__(self, percents_dict): """ :param percents: dictionary of path keys with their respecive occupation percentages. """ - self._args = [percents_dict] + self.percents_dict = percents_dict DEFAULT_PREFS = { "enabled": False, @@ -172,25 +174,25 @@ class Core(CorePluginBase): free_percent = free_blocks * 100 / total_blocks return free_percent - def __custom_email_notification(self, ocupied_percents): + def __custom_email_notification(self, event): subject = _("Low Disk Space Warning") message = _("You're running low on disk space:\n") - for path, ocupied_percent in ocupied_percents.iteritems(): + for path, ocupied_percent in event.percents_dict.iteritems(): message += _(' %s%% ocupation in %s\n') % (ocupied_percent, path) # "\"%s\"%% space occupation on %s") % (ocupied_percent, path) return subject, message - def __on_plugin_enabled(self, plugin_name): - if plugin_name == 'Notifications': + def __on_plugin_enabled(self, event): + if event.plugin_name == 'Notifications': component.get("CorePlugin.Notifications"). \ register_custom_email_notification( "LowDiskSpaceEvent", self.__custom_email_notification ) - def __on_plugin_disabled(self, plugin_name): - if plugin_name == 'Notifications': + def __on_plugin_disabled(self, event): + if event.plugin_name == 'Notifications': component.get("CorePlugin.Notifications"). \ deregister_custom_email_notification("LowDiskSpaceEvent") diff --git a/deluge/plugins/freespace/freespace/gtkui.py b/deluge/plugins/freespace/freespace/gtkui.py index 21405ccda..83d94b3b2 100644 --- a/deluge/plugins/freespace/freespace/gtkui.py +++ b/deluge/plugins/freespace/freespace/gtkui.py @@ -134,22 +134,22 @@ class GtkUI(GtkPluginBase): self.glade.get_widget('enabled').set_active(config['enabled']) self.glade.get_widget('percent').set_value(config['percent']) - def __custom_popup_notification(self, ocupied_percents): + def __custom_popup_notification(self, event): title = _("Low Free Space") message = '' - for path, percent in ocupied_percents.iteritems(): + for path, percent in event.percents_dict.iteritems(): message += '%s%% %s\n' % (percent, path) message += '\n' return title, message - def __custom_blink_notification(self, ocupied_percents): + def __custom_blink_notification(self, event): return True # Yes, do blink - def __custom_sound_notification(self, ocupied_percents): + def __custom_sound_notification(self, event): return '' # Use default sound - def __on_plugin_enabled(self, plugin_name): - if plugin_name == 'Notifications': + def __on_plugin_enabled(self, event): + if event.plugin_name == 'Notifications': notifications = component.get("GtkPlugin.Notifications") notifications.register_custom_popup_notification( "LowDiskSpaceEvent", self.__custom_popup_notification @@ -161,7 +161,7 @@ class GtkUI(GtkPluginBase): "LowDiskSpaceEvent", self.__custom_sound_notification ) - def __on_plugin_disabled(self, plugin_name): + def __on_plugin_disabled(self, event): pass # if plugin_name == 'Notifications': # notifications = component.get("GtkPlugin.Notifications") diff --git a/deluge/plugins/label/label/core.py b/deluge/plugins/label/label/core.py index b5613d698..cf6c7b970 100644 --- a/deluge/plugins/label/label/core.py +++ b/deluge/plugins/label/label/core.py @@ -123,6 +123,8 @@ class Core(CorePluginBase): def disable(self): self.plugin.deregister_status_field("label") component.get("FilterManager").deregister_tree_field("label") + component.get("EventManager").deregister_event_handler("TorrentAddedEvent", self.post_torrent_add) + component.get("EventManager").deregister_event_handler("TorrentRemovedEvent", self.post_torrent_remove) def update(self): pass @@ -131,20 +133,20 @@ class Core(CorePluginBase): return dict( [(label, 0) for label in self.labels.keys()]) ## Plugin hooks ## - def post_torrent_add(self, torrent_id): + def post_torrent_add(self, event): log.debug("post_torrent_add") - torrent = self.torrents[torrent_id] + torrent = self.torrents[event.torrent_id] for label_id, options in self.labels.iteritems(): if options["auto_add"]: if self._has_auto_match(torrent, options): - self.set_torrent(torrent_id, label_id) + self.set_torrent(event.torrent_id, label_id) return - def post_torrent_remove(self, torrent_id): + def post_torrent_remove(self, event): log.debug("post_torrent_remove") - if torrent_id in self.torrent_labels: - del self.torrent_labels[torrent_id] + if event.torrent_id in self.torrent_labels: + del self.torrent_labels[event.torrent_id] ## Utils ## def clean_config(self): diff --git a/deluge/plugins/notifications/notifications/core.py b/deluge/plugins/notifications/notifications/core.py index 2139de257..747f2d104 100644 --- a/deluge/plugins/notifications/notifications/core.py +++ b/deluge/plugins/notifications/notifications/core.py @@ -188,9 +188,9 @@ Subject: %(subject)s return _("Notification email sent.") - def _on_torrent_finished_event(self, torrent_id): + def _on_torrent_finished_event(self, event): log.debug("Handler for TorrentFinishedEvent called for CORE") - torrent = component.get("TorrentManager")[torrent_id] + torrent = component.get("TorrentManager")[event.torrent_id] torrent_status = torrent.get_status({}) # Email subject = _("Finished Torrent \"%(name)s\"") % torrent_status diff --git a/deluge/plugins/scheduler/scheduler/core.py b/deluge/plugins/scheduler/scheduler/core.py index e33ef94dc..f810fff71 100644 --- a/deluge/plugins/scheduler/scheduler/core.py +++ b/deluge/plugins/scheduler/scheduler/core.py @@ -76,11 +76,12 @@ class SchedulerEvent(DelugeEvent): """ Emitted when a schedule state changes. """ + __slots__ = ('colour',) def __init__(self, colour): """ :param colour: str, the current scheduler state """ - self._args = [colour] + self.colour = colour class Core(CorePluginBase): def enable(self): @@ -119,8 +120,8 @@ class Core(CorePluginBase): pass - def on_config_value_changed(self, key, value): - if key in CONTROLLED_SETTINGS: + def on_config_value_changed(self, event): + if event.key in CONTROLLED_SETTINGS: self.do_schedule(False) def __apply_set_functions(self): diff --git a/deluge/plugins/scheduler/scheduler/gtkui.py b/deluge/plugins/scheduler/scheduler/gtkui.py index 739f29ab5..2bf73cbd3 100644 --- a/deluge/plugins/scheduler/scheduler/gtkui.py +++ b/deluge/plugins/scheduler/scheduler/gtkui.py @@ -203,9 +203,9 @@ class GtkUI(GtkPluginBase): client.scheduler.get_config().addCallback(on_get_config) - def on_scheduler_event(self, state): + def on_scheduler_event(self, event): def on_state_deferred(s): - self.status_item.set_image_from_file(get_resource(state.lower() + ".png")) + self.status_item.set_image_from_file(get_resource(event.colour.lower() + ".png")) self.state_deferred.addCallback(on_state_deferred) diff --git a/deluge/ui/client.py b/deluge/ui/client.py index f7d808018..9852b2998 100644 --- a/deluge/ui/client.py +++ b/deluge/ui/client.py @@ -45,6 +45,7 @@ import zlib import deluge.common import deluge.component as component +from deluge.event import known_events if deluge.common.windows_check(): import win32api @@ -165,13 +166,14 @@ class DelugeRPCProtocol(Protocol): message_type = request[0] if message_type == RPC_EVENT: - event = request[1] + event_name = request[1] #log.debug("Received RPCEvent: %s", event) # A RPCEvent was received from the daemon so run any handlers # associated with it. - if event in self.factory.event_handlers: - for handler in self.factory.event_handlers[event]: - reactor.callLater(0, handler, *request[2]) + if event_name in self.factory.event_handlers: + event = known_events[event_name](*request[2]) + for handler in self.factory.event_handlers[event_name]: + reactor.callLater(0, handler, event.copy()) continue request_id = request[1] diff --git a/deluge/ui/console/eventlog.py b/deluge/ui/console/eventlog.py index df1447bae..351186dd8 100644 --- a/deluge/ui/console/eventlog.py +++ b/deluge/ui/console/eventlog.py @@ -62,51 +62,53 @@ class EventLog(component.Component): client.register_event_handler("PluginEnabledEvent", self.on_plugin_enabled_event) client.register_event_handler("PluginDisabledEvent", self.on_plugin_disabled_event) - def on_torrent_added_event(self, torrent_id): + def on_torrent_added_event(self, event): def on_torrent_status(status): - self.console.write(self.prefix + "TorrentAdded: {!info!}%s (%s)" % (status["name"], torrent_id)) - client.core.get_torrent_status(torrent_id, ["name"]).addCallback(on_torrent_status) + self.console.write(self.prefix + "TorrentAdded(from_state=%s): {!info!}%s (%s)" % ( + event.from_state, status["name"], event.torrent_id) + ) + client.core.get_torrent_status(event.torrent_id, ["name"]).addCallback(on_torrent_status) - def on_torrent_removed_event(self, torrent_id): + def on_torrent_removed_event(self, event): self.console.write(self.prefix + "TorrentRemoved: {!info!}%s (%s)" % - (self.console.get_torrent_name(torrent_id), torrent_id)) + (self.console.get_torrent_name(event.torrent_id), event.torrent_id)) - def on_torrent_state_changed_event(self, torrent_id, state): + def on_torrent_state_changed_event(self, event): # Modify the state string color - if state in colors.state_color: - state = colors.state_color[state] + state + if event.state in colors.state_color: + state = colors.state_color[event.state] + event.state self.console.write(self.prefix + "TorrentStateChanged: %s {!info!}%s (%s)" % - (state, self.console.get_torrent_name(torrent_id), torrent_id)) + (state, self.console.get_torrent_name(event.torrent_id), event.torrent_id)) - def on_torrent_paused_event(self, torrent_id): + def on_torrent_paused_event(self, event): self.console.write(self.prefix + "TorrentPaused: {!info!}%s (%s)" % - (self.console.get_torrent_name(torrent_id), torrent_id)) + (self.console.get_torrent_name(event.torrent_id), event.torrent_id)) - def on_torrent_finished_event(self, torrent_id): + def on_torrent_finished_event(self, event): self.console.write(self.prefix + "TorrentFinished: {!info!}%s (%s)" % - (self.console.get_torrent_name(torrent_id), torrent_id)) + (self.console.get_torrent_name(event.torrent_id), event.torrent_id)) - def on_new_version_available_event(self, version): + def on_new_version_available_event(self, event): self.console.write(self.prefix + "NewVersionAvailable: {!info!}%s" % - (version)) + (event.new_release)) - def on_session_paused_event(self): + def on_session_paused_event(self, event): self.console.write(self.prefix + "SessionPaused") - def on_session_resumed_event(self): + def on_session_resumed_event(self, event): self.console.write(self.prefix + "SessionResumed") - def on_config_value_changed_event(self, key, value): + def on_config_value_changed_event(self, event): color = "{!white,black,bold!}" - if type(value) in colors.type_color: - color = colors.type_color[type(value)] + if type(event.value) in colors.type_color: + color = colors.type_color[type(event.value)] self.console.write(self.prefix + "ConfigValueChanged: {!input!}%s: %s%s" % - (key, color, value)) + (event.key, color, event.value)) - def on_plugin_enabled_event(self, name): - self.console.write(self.prefix + "PluginEnabled: {!info!}%s" % name) + def on_plugin_enabled_event(self, event): + self.console.write(self.prefix + "PluginEnabled: {!info!}%s" % event.plugin_name) - def on_plugin_disabled_event(self, name): - self.console.write(self.prefix + "PluginDisabled: {!info!}%s" % name) + def on_plugin_disabled_event(self, event): + self.console.write(self.prefix + "PluginDisabled: {!info!}%s" % event.plugin_name) diff --git a/deluge/ui/console/main.py b/deluge/ui/console/main.py index 09f534482..6ea3adb79 100644 --- a/deluge/ui/console/main.py +++ b/deluge/ui/console/main.py @@ -442,14 +442,14 @@ class ConsoleUI(component.Component): return ret - def on_torrent_added_event(self, torrent_id): + def on_torrent_added_event(self, event): def on_torrent_status(status): - self.torrents.append((torrent_id, status["name"])) - client.core.get_torrent_status(torrent_id, ["name"]).addCallback(on_torrent_status) + self.torrents.append((event.torrent_id, status["name"])) + client.core.get_torrent_status(event.torrent_id, ["name"]).addCallback(on_torrent_status) - def on_torrent_removed_event(self, torrent_id): + def on_torrent_removed_event(self, event): for index, (tid, name) in enumerate(self.torrents): - if torrent_id == tid: + if event.torrent_id == tid: del self.torrents[index] def on_client_disconnect(self): diff --git a/deluge/ui/coreconfig.py b/deluge/ui/coreconfig.py index 6120dcfa8..fe002e64a 100644 --- a/deluge/ui/coreconfig.py +++ b/deluge/ui/coreconfig.py @@ -45,8 +45,8 @@ class CoreConfig(component.Component): log.debug("CoreConfig init..") component.Component.__init__(self, "CoreConfig") self.config = {} - def on_configvaluechanged_event(key, value): - self.config[key] = value + def on_configvaluechanged_event(event): + self.config[event.key] = event.value client.register_event_handler("ConfigValueChangedEvent", on_configvaluechanged_event) def start(self): diff --git a/deluge/ui/gtkui/files_tab.py b/deluge/ui/gtkui/files_tab.py index 6feeab7ea..1fc0ccba8 100644 --- a/deluge/ui/gtkui/files_tab.py +++ b/deluge/ui/gtkui/files_tab.py @@ -605,34 +605,34 @@ class FilesTab(Tab): def _on_filename_editing_canceled(self, renderer): self._editing_index = None - def _on_torrentfilerenamed_event(self, torrent_id, index, name): - log.debug("index: %s name: %s", index, name) + def _on_torrentfilerenamed_event(self, event): + log.debug("index: %s name: %s", event.index, event.filename) - if torrent_id not in self.files_list: + if event.torrent_id not in self.files_list: return - old_name = self.files_list[torrent_id][index]["path"] - self.files_list[torrent_id][index]["path"] = name + old_name = self.files_list[event.torrent_id][event.index]["path"] + self.files_list[event.torrent_id][event.index]["path"] = event.filename # We need to update the filename displayed if we're currently viewing # this torrents files. - if torrent_id == self.torrent_id: + if event.torrent_id == self.torrent_id: old_name_len = len(old_name.split("/")) - name_len = len(name.split("/")) + name_len = len(event.filename.split("/")) if old_name_len != name_len: # The parent path list changes depending on which way the file # is moving in the tree if old_name_len < name_len: parent_path = [o for o in old_name.split("/")[:-1]] else: - parent_path = [o for o in name.split("/")[:-1]] + parent_path = [o for o in event.filename.split("/")[:-1]] # Find the iter to the parent folder we need to add a new folder # to. def find_parent(model, path, itr, user_data): if model[itr][0] == parent_path[0] + "/": if len(parent_path) == 1: # This is the parent iter - to_create = name.split("/")[len(old_name.split("/")[:-1]):-1] + to_create = event.filename.split("/")[len(old_name.split("/")[:-1]):-1] parent_iter = itr for tc in to_create: @@ -651,8 +651,8 @@ class FilesTab(Tab): # Find the iter for the file that needs to be moved def get_file_iter(model, path, itr, user_data): - if model[itr][5] == index: - model[itr][0] = name.split("/")[-1] + if model[itr][5] == event.index: + model[itr][0] = event.filename.split("/")[-1] t = self.treestore.append( parent_iter, self.treestore.get(itr, @@ -671,7 +671,7 @@ class FilesTab(Tab): if parent_path: self.treestore.foreach(find_parent, None) else: - new_folders = name.split("/")[:-1] + new_folders = event.filename.split("/")[:-1] parent_iter = None for f in new_folders: parent_iter = self.treestore.append(parent_iter, @@ -685,8 +685,8 @@ class FilesTab(Tab): else: # This is just changing a filename without any folder changes def set_file_name(model, path, itr, user_data): - if model[itr][5] == index: - model[itr][0] = os.path.split(name)[-1] + if model[itr][5] == event.index: + model[itr][0] = os.path.split(event.filename)[-1] return True self.treestore.foreach(set_file_name, None) @@ -732,40 +732,40 @@ class FilesTab(Tab): self.treestore.remove(itr) itr = parent - def _on_torrentfolderrenamed_event(self, torrent_id, old_folder, new_folder): + def _on_torrentfolderrenamed_event(self, event): log.debug("on_torrent_folder_renamed_signal") - log.debug("old_folder: %s new_folder: %s", old_folder, new_folder) + log.debug("old_folder: %s new_folder: %s", event.old, event.new) - if torrent_id not in self.files_list: + if event.torrent_id not in self.files_list: return - if old_folder[-1] != "/": - old_folder += "/" - if new_folder[-1] != "/": - new_folder += "/" + if event.old[-1] != "/": + event.old += "/" + if event.new[-1] != "/": + event.new += "/" - for fd in self.files_list[torrent_id]: - if fd["path"].startswith(old_folder): - fd["path"] = fd["path"].replace(old_folder, new_folder, 1) + for fd in self.files_list[event.torrent_id]: + if fd["path"].startswith(event.old): + fd["path"] = fd["path"].replace(event.old, event.new, 1) - if torrent_id == self.torrent_id: + if event.torrent_id == self.torrent_id: - old_split = old_folder.split("/") + old_split = event.old.split("/") try: old_split.remove("") except: pass - new_split = new_folder.split("/") + new_split = event.new.split("/") try: new_split.remove("") except: pass - old_folder_iter = self.get_iter_at_path(old_folder) + old_folder_iter = self.get_iter_at_path(event.old) old_folder_iter_parent = self.treestore.iter_parent(old_folder_iter) - new_folder_iter = self.get_iter_at_path(new_folder) + new_folder_iter = self.get_iter_at_path(event.new) if len(new_split) == len(old_split): # These are at the same tree depth, so it's a simple rename self.treestore[old_folder_iter][0] = new_split[-1] + "/" @@ -785,9 +785,9 @@ class FilesTab(Tab): # and if so, we delete it self.remove_childless_folders(old_folder_iter_parent) - def _on_torrentremoved_event(self, torrent_id): - if torrent_id in self.files_list: - del self.files_list[torrent_id] + def _on_torrentremoved_event(self, event): + if event.torrent_id in self.files_list: + del self.files_list[event.torrent_id] def _on_drag_data_get_data(self, treeview, context, selection, target_id, etime): paths = self.listview.get_selection().get_selected_rows()[1] diff --git a/deluge/ui/gtkui/mainwindow.py b/deluge/ui/gtkui/mainwindow.py index 12fa5a96d..bc582c439 100644 --- a/deluge/ui/gtkui/mainwindow.py +++ b/deluge/ui/gtkui/mainwindow.py @@ -247,11 +247,11 @@ class MainWindow(component.Component): else: self.window.set_title("Deluge") - def on_newversionavailable_event(self, new_version): + def on_newversionavailable_event(self, event): if self.config["show_new_releases"]: from deluge.ui.gtkui.new_release_dialog import NewReleaseDialog - reactor.callLater(5.0, NewReleaseDialog().show, new_version) + reactor.callLater(5.0, NewReleaseDialog().show, event.new_release) - def on_torrentfinished_event(self, torrent_id): + def on_torrentfinished_event(self, event): from deluge.ui.gtkui.notification import Notification - Notification().notify(torrent_id) + Notification().notify(event.torrent_id) diff --git a/deluge/ui/gtkui/menubar.py b/deluge/ui/gtkui/menubar.py index 901e6b3c6..ce80e5463 100644 --- a/deluge/ui/gtkui/menubar.py +++ b/deluge/ui/gtkui/menubar.py @@ -230,11 +230,11 @@ class MenuBar(component.Component): return sep ### Callbacks ### - def on_torrentstatechanged_event(self, torrent_id, state): - if state == "Paused": + def on_torrentstatechanged_event(self, event): + if event.state == "Paused": self.update_menu() - def on_torrentresumed_event(self, torrent_id): + def on_torrentresumed_event(self, event): self.update_menu() def on_sessionpaused_event(self): diff --git a/deluge/ui/gtkui/pluginmanager.py b/deluge/ui/gtkui/pluginmanager.py index b5169977d..8c4ffdc88 100644 --- a/deluge/ui/gtkui/pluginmanager.py +++ b/deluge/ui/gtkui/pluginmanager.py @@ -91,11 +91,11 @@ class PluginManager(deluge.pluginmanagerbase.PluginManagerBase, for plugin in enabled_plugins: self.enable_plugin(plugin) - def _on_plugin_enabled_event(self, name): - self.enable_plugin(name) + def _on_plugin_enabled_event(self, event): + self.enable_plugin(event.plugin_name) - def _on_plugin_disabled_event(self, name): - self.disable_plugin(name) + def _on_plugin_disabled_event(self, event): + self.disable_plugin(event.plugin_name) ## Hook functions def run_on_show_prefs(self): diff --git a/deluge/ui/gtkui/statusbar.py b/deluge/ui/gtkui/statusbar.py index 60202a213..52f8c7fb5 100644 --- a/deluge/ui/gtkui/statusbar.py +++ b/deluge/ui/gtkui/statusbar.py @@ -288,14 +288,14 @@ class StatusBar(component.Component): client.core.get_session_status(keys).addCallback(self._on_get_session_status) client.core.get_free_space().addCallback(self._on_get_free_space) - def on_configvaluechanged_event(self, key, value): + def on_configvaluechanged_event(self, event): """ This is called when we receive a ConfigValueChangedEvent from the core. """ - if key in self.config_value_changed_dict.keys(): - self.config_value_changed_dict[key](value) + if event.key in self.config_value_changed_dict.keys(): + self.config_value_changed_dict[event.key](event.value) def _on_max_connections_global(self, max_connections): self.max_connections = max_connections diff --git a/deluge/ui/gtkui/systemtray.py b/deluge/ui/gtkui/systemtray.py index 95beafac6..5a193358e 100644 --- a/deluge/ui/gtkui/systemtray.py +++ b/deluge/ui/gtkui/systemtray.py @@ -175,12 +175,12 @@ class SystemTray(component.Component): "payload_upload_rate", "payload_download_rate"]).addCallback(self._on_get_session_status) - def config_value_changed(self, key, value): + def config_value_changed(self, event): """This is called when we received a config_value_changed signal from the core.""" - if key in self.config_value_changed_dict.keys(): - self.config_value_changed_dict[key](value) + if event.key in self.config_value_changed_dict.keys(): + self.config_value_changed_dict[event.key](event.value) def _on_max_download_speed(self, max_download_speed): if self.max_download_speed != max_download_speed: diff --git a/deluge/ui/gtkui/torrentview.py b/deluge/ui/gtkui/torrentview.py index 3753fa105..52590afae 100644 --- a/deluge/ui/gtkui/torrentview.py +++ b/deluge/ui/gtkui/torrentview.py @@ -515,31 +515,31 @@ class TorrentView(listview.ListView, component.Component): def on_drag_drop(self, widget, drag_context, x, y, timestamp): widget.stop_emission("drag-drop") - def on_torrentadded_event(self, torrent_id): - self.add_row(torrent_id) - self.mark_dirty(torrent_id) + def on_torrentadded_event(self, event): + self.add_row(event.torrent_id) + self.mark_dirty(event.torrent_id) - def on_torrentremoved_event(self, torrent_id): - self.remove_row(torrent_id) + def on_torrentremoved_event(self, event): + self.remove_row(event.torrent_id) - def on_torrentstatechanged_event(self, torrent_id, state): + def on_torrentstatechanged_event(self, event): # Update the torrents state for row in self.liststore: - if not torrent_id == row[self.columns["torrent_id"].column_indices[0]]: + if not event.torrent_id == row[self.columns["torrent_id"].column_indices[0]]: continue - row[self.get_column_index(_("Progress"))[1]] = state + row[self.get_column_index(_("Progress"))[1]] = event.state - self.mark_dirty(torrent_id) + self.mark_dirty(event.torrent_id) - def on_sessionpaused_event(self): + def on_sessionpaused_event(self, event): self.mark_dirty() self.update() - def on_sessionresumed_event(self): + def on_sessionresumed_event(self, event): self.mark_dirty() self.update() - def on_torrentqueuechanged_event(self): + def on_torrentqueuechanged_event(self, event): self.mark_dirty() self.update() diff --git a/deluge/ui/sessionproxy.py b/deluge/ui/sessionproxy.py index f1e5d3e3c..4fc53d85b 100644 --- a/deluge/ui/sessionproxy.py +++ b/deluge/ui/sessionproxy.py @@ -236,21 +236,21 @@ class SessionProxy(component.Component): d = client.core.get_torrents_status(filter_dict, keys, True) return d.addCallback(on_status, None, keys) - def on_torrent_state_changed(self, torrent_id, state): - if torrent_id in self.torrents: - self.torrents[torrent_id][1]["state"] = state - self.cache_times[torrent_id]["state"] = time.time() + def on_torrent_state_changed(self, event): + if event.torrent_id in self.torrents: + self.torrents[event.torrent_id][1]["state"] = event.state + self.cache_times[event.torrent_id]["state"] = time.time() - def on_torrent_added(self, torrent_id): - self.torrents[torrent_id] = [time.time() - self.cache_time - 1, {}] - self.cache_times[torrent_id] = {} + def on_torrent_added(self, event): + self.torrents[event.torrent_id] = [time.time() - self.cache_time - 1, {}] + self.cache_times[event.torrent_id] = {} def on_status(status): - self.torrents[torrent_id][1].update(status) + self.torrents[event.torrent_id][1].update(status) t = time.time() for key in status: - self.cache_times[torrent_id][key] = t - client.core.get_torrent_status(torrent_id, []).addCallback(on_status) + self.cache_times[event.torrent_id][key] = t + client.core.get_torrent_status(event.torrent_id, []).addCallback(on_status) - def on_torrent_removed(self, torrent_id): - del self.torrents[torrent_id] - del self.cache_times[torrent_id] + def on_torrent_removed(self, event): + del self.torrents[event.torrent_id] + del self.cache_times[event.torrent_id] diff --git a/deluge/ui/web/js/deluge-all/Deluge.js b/deluge/ui/web/js/deluge-all/Deluge.js index de82dd7af..382b611dd 100644 --- a/deluge/ui/web/js/deluge-all/Deluge.js +++ b/deluge/ui/web/js/deluge-all/Deluge.js @@ -46,7 +46,7 @@ Ext.apply(Ext, { return true; }, - isObjectsEqual: function(obj1, obj2) { + areObjectsEqual: function(obj1, obj2) { var equal = true; if (!obj1 || !obj2) return false; for (var i in obj1) { diff --git a/deluge/ui/web/js/deluge-all/TorrentGrid.js b/deluge/ui/web/js/deluge-all/TorrentGrid.js index 04a020432..0455113c5 100644 --- a/deluge/ui/web/js/deluge-all/TorrentGrid.js +++ b/deluge/ui/web/js/deluge-all/TorrentGrid.js @@ -284,8 +284,15 @@ return ids; }, - update: function(torrents) { + update: function(torrents, wipe) { var store = this.getStore(); + + // Need to perform a complete reload of the torrent grid. + if (wipe) { + store.removeAll(); + this.torrents = {}; + } + var newTorrents = []; // Update and add any new torrents. diff --git a/deluge/ui/web/js/deluge-all/UI.js b/deluge/ui/web/js/deluge-all/UI.js index e8e86a593..4a1b96278 100644 --- a/deluge/ui/web/js/deluge-all/UI.js +++ b/deluge/ui/web/js/deluge-all/UI.js @@ -114,6 +114,9 @@ deluge.ui = { update: function() { var filters = deluge.sidebar.getFilterStates(); + this.oldFilters = this.filters; + this.filters = filters; + deluge.client.web.update_ui(Deluge.Keys.Grid, filters, { success: this.onUpdate, failure: this.onUpdateError, @@ -170,7 +173,11 @@ deluge.ui = { ' (Down: ' + fspeed(data['stats'].download_rate, true) + ' Up: ' + fspeed(data['stats'].upload_rate, true) + ')'; } - deluge.torrents.update(data['torrents']); + if (Ext.areObjectsEqual(this.filters, this.oldFilters)) { + deluge.torrents.update(data['torrents']); + } else { + deluge.torrents.update(data['torrents'], true); + } deluge.statusbar.update(data['stats']); deluge.sidebar.update(data['filters']); this.errorCount = 0; diff --git a/deluge/ui/web/pluginmanager.py b/deluge/ui/web/pluginmanager.py index d247e0729..ec4c61c58 100644 --- a/deluge/ui/web/pluginmanager.py +++ b/deluge/ui/web/pluginmanager.py @@ -58,26 +58,26 @@ def gather_info(plugin): "debug_scripts": debug_scripts, "script_directories": directories } - + class PluginManager(PluginManagerBase, component.Component): def __init__(self): component.Component.__init__(self, "Web.PluginManager") self.config = ConfigManager("web.conf") PluginManagerBase.__init__(self, "web.conf", "deluge.plugin.web") - + client.register_event_handler("PluginEnabledEvent", self._on_plugin_enabled_event) client.register_event_handler("PluginDisabledEvent", self._on_plugin_disabled_event) - + def _on_get_enabled_plugins(self, plugins): for plugin in plugins: self.enable_plugin(plugin) - - def _on_plugin_enabled_event(self, name): - self.enable_plugin(name) - def _on_plugin_disabled_event(self, name): - self.disable_plugin(name) - + def _on_plugin_enabled_event(self, event): + self.enable_plugin(event.plugin_name) + + def _on_plugin_disabled_event(self, event): + self.disable_plugin(event.plugin_name) + def disable_plugin(self, name): # Get the plugin instance try: @@ -85,31 +85,31 @@ class PluginManager(PluginManagerBase, component.Component): except KeyError: log.info("Plugin has no web ui") return - + info = gather_info(plugin) scripts = component.get("Scripts") for script in info["scripts"]: scripts.remove_script("%s/%s" % (name.lower(), os.path.basename(script).lower())) - + for script in info["debug_scripts"]: scripts.remove_script("%s/%s" % (name.lower(), os.path.basename(script).lower()), "debug") scripts.remove_script("%s/%s" % (name.lower(), os.path.basename(script).lower()), "dev") - + super(PluginManager, self).disable_plugin(name) - + def enable_plugin(self, name): super(PluginManager, self).enable_plugin(name) - + # Get the plugin instance try: plugin = component.get("WebPlugin." + name) except KeyError: log.info("Plugin has no web ui") return - + info = gather_info(plugin) - + scripts = component.get("Scripts") for script in info["scripts"]: log.debug("adding script %s for %s", name, os.path.basename(script)) @@ -127,16 +127,16 @@ class PluginManager(PluginManagerBase, component.Component): # Update the enabled plugins from the core d = client.core.get_enabled_plugins() d.addCallback(self._on_get_enabled_plugins) - + def stop(self): """ Stop the plugin manager """ self.disable_plugins() - + def update(self): pass - + def get_plugin_resources(self, name): # Get the plugin instance try: