Changeset 499a58
- Timestamp:
- 02/23/2011 06:47:16 PM (14 years ago)
- Branches:
- 2.0.x, develop, extjs4-port, master
- Children:
- 4c2f9a, 64e38e
- Parents:
- 5f0f72
- Files:
-
- 17 edited
Legend:
- Unmodified
- Added
- Removed
-
ChangeLog
r5f0f72 r499a58 11 11 * #995: Rewrote tracker_icons 12 12 * Make the distinction between adding to the session new unmanaged torrents and torrents loaded from state. This will break backwards compatability. 13 * Pass a copy of an event instead of passing the event arguments to the event handlers. This will break backwards compatability.14 13 15 14 ==== GtkUI ==== -
deluge/core/eventmanager.py
r5f0f72 r499a58 56 56 for handler in self.handlers[event.name]: 57 57 #log.debug("Running handler %s for event %s with args: %s", event.name, handler, event.args) 58 handler( event.copy())58 handler(*event.args) 59 59 60 60 def register_event_handler(self, event, handler): -
deluge/core/rpcserver.py
r5f0f72 r499a58 487 487 for session_id, interest in self.factory.interested_events.iteritems(): 488 488 if event.name in interest: 489 log.debug("Emit Event: %s %s", event.name, zip(event.__slots__, 490 event.args)) 489 log.debug("Emit Event: %s %s", event.name, event.args) 491 490 # This session is interested so send a RPC_EVENT 492 491 self.factory.session_protocols[session_id].sendData( -
deluge/event.py
r5f0f72 r499a58 3 3 # 4 4 # Copyright (C) 2009 Andrew Resch <andrewresch@gmail.com> 5 # Copyright (C) 2010 Pedro Algarvio <pedro@algarvio.me>6 5 # 7 6 # Deluge is free software. … … 49 48 This metaclass simply keeps a list of all events classes created. 50 49 """ 51 __slots__ = ()52 53 50 def __init__(cls, name, bases, dct): 54 51 super(DelugeEventMetaClass, cls).__init__(name, bases, dct) … … 66 63 67 64 """ 68 __slots__ = ()69 65 __metaclass__ = DelugeEventMetaClass 70 66 71 67 def _get_name(self): 72 68 return self.__class__.__name__ 69 70 def _get_args(self): 71 if not hasattr(self, "_args"): 72 return [] 73 return self._args 74 73 75 name = property(fget=_get_name) 74 75 def _get_args(self):76 return [getattr(self, arg) for arg in self.__slots__]77 76 args = property(fget=_get_args) 78 77 79 def copy(self):80 return self.__class__(*self.args)81 82 78 class TorrentAddedEvent(DelugeEvent): 83 79 """ 84 80 Emitted when a new torrent is successfully added to the session. 85 81 """ 86 __slots__ = ('torrent_id', 'from_state')87 88 82 def __init__(self, torrent_id, from_state): 89 83 """ … … 93 87 :type from_state: bool 94 88 """ 95 self.torrent_id = torrent_id 96 self.from_state = from_state 89 self._args = [torrent_id, from_state] 97 90 98 91 class TorrentRemovedEvent(DelugeEvent): … … 100 93 Emitted when a torrent has been removed from the session. 101 94 """ 102 __slots__ = ('torrent_id',) 103 104 def __init__(self, torrent_id): 105 """ 106 :param torrent_id: the torrent_id 107 :type torrent_id: string 108 """ 109 self.torrent_id = torrent_id 95 def __init__(self, torrent_id): 96 """ 97 :param torrent_id: the torrent_id 98 :type torrent_id: string 99 """ 100 self._args = [torrent_id] 110 101 111 102 class PreTorrentRemovedEvent(DelugeEvent): … … 113 104 Emitted when a torrent is about to be removed from the session. 114 105 """ 115 __slots__ = ('torrent_id',) 116 117 def __init__(self, torrent_id): 118 """ 119 :param torrent_id: the torrent_id 120 :type torrent_id: string 121 """ 122 self.torrent_id = torrent_id 106 def __init__(self, torrent_id): 107 """ 108 :param torrent_id: the torrent_id 109 :type torrent_id: string 110 """ 111 self._args = [torrent_id] 123 112 124 113 class TorrentStateChangedEvent(DelugeEvent): … … 126 115 Emitted when a torrent changes state. 127 116 """ 128 __slots__ = ('torrent_id', 'state')129 130 117 def __init__(self, torrent_id, state): 131 118 """ … … 135 122 :type state: string 136 123 """ 137 self.torrent_id = torrent_id 138 self.state = state 124 self._args = [torrent_id, state] 139 125 140 126 class TorrentQueueChangedEvent(DelugeEvent): … … 142 128 Emitted when the queue order has changed. 143 129 """ 130 pass 144 131 145 132 class TorrentFolderRenamedEvent(DelugeEvent): … … 147 134 Emitted when a folder within a torrent has been renamed. 148 135 """ 149 __slots__ = ('torrent_id', 'old', 'new')150 151 136 def __init__(self, torrent_id, old, new): 152 137 """ … … 158 143 :type new: string 159 144 """ 160 self.torrent_id = torrent_id 161 self.old = old 162 self.new = new 145 self._args = [torrent_id, old, new] 163 146 164 147 class TorrentFileRenamedEvent(DelugeEvent): … … 166 149 Emitted when a file within a torrent has been renamed. 167 150 """ 168 __slots__ = ('torrent_id', 'index', 'filename') 169 170 def __init__(self, torrent_id, index, filename): 151 def __init__(self, torrent_id, index, name): 171 152 """ 172 153 :param torrent_id: the torrent_id … … 174 155 :param index: the index of the file 175 156 :type index: int 176 :param filename: the new filename 177 :type filename: string 178 """ 179 self.torrent_id = torrent_id 180 self.index = index 181 self.filename = filename 157 :param name: the new filename 158 :type name: string 159 """ 160 self._args = [torrent_id, index, name] 182 161 183 162 class TorrentFinishedEvent(DelugeEvent): … … 185 164 Emitted when a torrent finishes downloading. 186 165 """ 187 __slots__ = ('torrent_id',) 188 189 def __init__(self, torrent_id): 190 """ 191 :param torrent_id: the torrent_id 192 :type torrent_id: string 193 """ 194 self.torrent_id = torrent_id 166 def __init__(self, torrent_id): 167 """ 168 :param torrent_id: the torrent_id 169 :type torrent_id: string 170 """ 171 self._args = [torrent_id] 195 172 196 173 class TorrentResumedEvent(DelugeEvent): … … 198 175 Emitted when a torrent resumes from a paused state. 199 176 """ 200 __slots__ = ('torrent_id',) 201 202 def __init__(self, torrent_id): 203 """ 204 :param torrent_id: the torrent_id 205 :type torrent_id: string 206 """ 207 self.torrent_id = torrent_id 177 def __init__(self, torrent_id): 178 """ 179 :param torrent_id: the torrent_id 180 :type torrent_id: string 181 """ 182 self._args = [torrent_id] 208 183 209 184 class TorrentFileCompletedEvent(DelugeEvent): … … 214 189 215 190 """ 216 __slots__ = ('torrent_id', 'index')217 218 191 def __init__(self, torrent_id, index): 219 192 """ … … 223 196 :type index: int 224 197 """ 225 self.torrent_id = torrent_id 226 self.index = index 198 self._args = [torrent_id, index] 227 199 228 200 class NewVersionAvailableEvent(DelugeEvent): … … 230 202 Emitted when a more recent version of Deluge is available. 231 203 """ 232 __slots__ = ('new_release',)233 234 204 def __init__(self, new_release): 235 205 """ … … 237 207 :type new_release: string 238 208 """ 239 self. new_release = new_release209 self._args = [new_release] 240 210 241 211 class SessionStartedEvent(DelugeEvent): … … 244 214 the daemon is initially started. 245 215 """ 216 pass 246 217 247 218 class SessionPausedEvent(DelugeEvent): … … 249 220 Emitted when the session has been paused. 250 221 """ 222 pass 251 223 252 224 class SessionResumedEvent(DelugeEvent): … … 254 226 Emitted when the session has been resumed. 255 227 """ 228 pass 256 229 257 230 class ConfigValueChangedEvent(DelugeEvent): … … 259 232 Emitted when a config value changes in the Core. 260 233 """ 261 __slots__ = ('key', 'value')262 263 234 def __init__(self, key, value): 264 235 """ … … 267 238 :param value: the new value of the `:param:key` 268 239 """ 269 self.key = key 270 self.value = value 240 self._args = [key, value] 271 241 272 242 class PluginEnabledEvent(DelugeEvent): … … 274 244 Emitted when a plugin is enabled in the Core. 275 245 """ 276 __slots__ = ('plugin_name',) 277 278 def __init__(self, plugin_name): 279 """ 280 :param plugin_name: the plugin name 281 :type plugin_name: string 282 """ 283 self.plugin_name = plugin_name 246 def __init__(self, name): 247 self._args = [name] 284 248 285 249 class PluginDisabledEvent(DelugeEvent): … … 287 251 Emitted when a plugin is disabled in the Core. 288 252 """ 289 __slots__ = ('plugin_name',) 290 291 def __init__(self, plugin_name): 292 """ 293 :param plugin_name: the plugin name 294 :type plugin_name: string 295 """ 296 self.plugin_name = plugin_name 253 def __init__(self, name): 254 self._args = [name] -
deluge/ui/client.py
r5f0f72 r499a58 46 46 import deluge.common 47 47 import deluge.component as component 48 from deluge. event import known_events48 from deluge.log import LOG as log 49 49 50 50 if deluge.common.windows_check(): … … 167 167 168 168 if message_type == RPC_EVENT: 169 event _name= request[1]169 event = request[1] 170 170 #log.debug("Received RPCEvent: %s", event) 171 171 # A RPCEvent was received from the daemon so run any handlers 172 172 # associated with it. 173 if event_name in self.factory.event_handlers: 174 event = known_events[event_name](*request[2]) 175 for handler in self.factory.event_handlers[event_name]: 176 reactor.callLater(0, handler, event.copy()) 173 if event in self.factory.event_handlers: 174 for handler in self.factory.event_handlers[event]: 175 reactor.callLater(0, handler, *request[2]) 177 176 continue 178 177 -
deluge/ui/console/eventlog.py
r5f0f72 r499a58 63 63 client.register_event_handler("PluginDisabledEvent", self.on_plugin_disabled_event) 64 64 65 def on_torrent_added_event(self, event):65 def on_torrent_added_event(self, torrent_id, from_state): 66 66 def on_torrent_status(status): 67 67 self.console.write(self.prefix + "TorrentAdded(from_state=%s): {!info!}%s (%s)" % ( 68 event.from_state, status["name"], event.torrent_id)68 from_state, status["name"], torrent_id) 69 69 ) 70 client.core.get_torrent_status( event.torrent_id, ["name"]).addCallback(on_torrent_status)70 client.core.get_torrent_status(torrent_id, ["name"]).addCallback(on_torrent_status) 71 71 72 def on_torrent_removed_event(self, event):72 def on_torrent_removed_event(self, torrent_id): 73 73 self.console.write(self.prefix + "TorrentRemoved: {!info!}%s (%s)" % 74 (self.console.get_torrent_name( event.torrent_id), event.torrent_id))74 (self.console.get_torrent_name(torrent_id), torrent_id)) 75 75 76 def on_torrent_state_changed_event(self, event):76 def on_torrent_state_changed_event(self, torrent_id, state): 77 77 # Modify the state string color 78 if event.state in colors.state_color:79 state = colors.state_color[ event.state] + event.state78 if state in colors.state_color: 79 state = colors.state_color[state] + state 80 80 81 81 self.console.write(self.prefix + "TorrentStateChanged: %s {!info!}%s (%s)" % 82 (state, self.console.get_torrent_name( event.torrent_id), event.torrent_id))82 (state, self.console.get_torrent_name(torrent_id), torrent_id)) 83 83 84 def on_torrent_paused_event(self, event):84 def on_torrent_paused_event(self, torrent_id): 85 85 self.console.write(self.prefix + "TorrentPaused: {!info!}%s (%s)" % 86 (self.console.get_torrent_name( event.torrent_id), event.torrent_id))86 (self.console.get_torrent_name(torrent_id), torrent_id)) 87 87 88 def on_torrent_finished_event(self, event):88 def on_torrent_finished_event(self, torrent_id): 89 89 self.console.write(self.prefix + "TorrentFinished: {!info!}%s (%s)" % 90 (self.console.get_torrent_name( event.torrent_id), event.torrent_id))90 (self.console.get_torrent_name(torrent_id), torrent_id)) 91 91 92 def on_new_version_available_event(self, event):92 def on_new_version_available_event(self, version): 93 93 self.console.write(self.prefix + "NewVersionAvailable: {!info!}%s" % 94 ( event.new_release))94 (version)) 95 95 96 def on_session_paused_event(self , event):96 def on_session_paused_event(self): 97 97 self.console.write(self.prefix + "SessionPaused") 98 98 99 def on_session_resumed_event(self , event):99 def on_session_resumed_event(self): 100 100 self.console.write(self.prefix + "SessionResumed") 101 101 102 def on_config_value_changed_event(self, event):102 def on_config_value_changed_event(self, key, value): 103 103 color = "{!white,black,bold!}" 104 if type( event.value) in colors.type_color:105 color = colors.type_color[type( event.value)]104 if type(value) in colors.type_color: 105 color = colors.type_color[type(value)] 106 106 107 107 self.console.write(self.prefix + "ConfigValueChanged: {!input!}%s: %s%s" % 108 ( event.key, color, event.value))108 (key, color, value)) 109 109 110 def on_plugin_enabled_event(self, event):111 self.console.write(self.prefix + "PluginEnabled: {!info!}%s" % event.plugin_name)110 def on_plugin_enabled_event(self, name): 111 self.console.write(self.prefix + "PluginEnabled: {!info!}%s" % name) 112 112 113 def on_plugin_disabled_event(self, event):114 self.console.write(self.prefix + "PluginDisabled: {!info!}%s" % event.plugin_name)113 def on_plugin_disabled_event(self, name): 114 self.console.write(self.prefix + "PluginDisabled: {!info!}%s" % name) -
deluge/ui/console/main.py
r5f0f72 r499a58 35 35 # 36 36 37 import os 38 import sys 39 import logging 37 import os, sys 40 38 import optparse 41 39 import shlex … … 44 42 from twisted.internet import defer, reactor 45 43 44 from deluge.ui.console import UI_PATH 46 45 import deluge.component as component 47 46 from deluge.ui.client import client 48 47 import deluge.common 49 48 from deluge.ui.coreconfig import CoreConfig 50 from deluge.ui.sessionproxy import SessionProxy51 49 from deluge.ui.console.statusbars import StatusBars 52 50 from deluge.ui.console.eventlog import EventLog 53 #import screen51 import screen 54 52 import colors 53 from deluge.log import LOG as log 55 54 from deluge.ui.ui import _UI 56 from deluge.ui.console import UI_PATH57 58 log = logging.getLogger(__name__)59 55 60 56 class Console(_UI): … … 64 60 def __init__(self): 65 61 super(Console, self).__init__("console") 66 group = optparse.OptionGroup(self.parser, "Console Options","These options control how " 67 "the console connects to the daemon. These options will be " 68 "used if you pass a command, or if you have autoconnect " 69 "enabled for the console ui.") 70 71 group.add_option("-d","--daemon",dest="daemon_addr", 72 action="store",type="str",default="127.0.0.1", 73 help="Set the address of the daemon to connect to." 74 " [default: %default]") 75 group.add_option("-p","--port",dest="daemon_port", 76 help="Set the port to connect to the daemon on. [default: %default]", 77 action="store",type="int",default=58846) 78 group.add_option("-u","--username",dest="daemon_user", 79 help="Set the username to connect to the daemon with. [default: %default]", 80 action="store",type="string") 81 group.add_option("-P","--password",dest="daemon_pass", 82 help="Set the password to connect to the daemon with. [default: %default]", 83 action="store",type="string") 62 cmds = load_commands(os.path.join(UI_PATH, 'commands')) 63 64 group = optparse.OptionGroup(self.parser, "Console Commands", 65 "\n".join(cmds.keys())) 84 66 self.parser.add_option_group(group) 85 86 self.cmds = load_commands(os.path.join(UI_PATH, 'commands'))87 class CommandOptionGroup(optparse.OptionGroup):88 def __init__(self, parser, title, description=None, cmds = None):89 optparse.OptionGroup.__init__(self,parser,title,description)90 self.cmds = cmds91 92 def format_help(self, formatter):93 result = formatter.format_heading(self.title)94 formatter.indent()95 if self.description:96 result += "%s\n"%formatter.format_description(self.description)97 for cname in self.cmds:98 cmd = self.cmds[cname]99 if cmd.interactive_only or cname in cmd.aliases: continue100 allnames = [cname]101 allnames.extend(cmd.aliases)102 cname = "/".join(allnames)103 result += formatter.format_heading(" - ".join([cname,cmd.__doc__]))104 formatter.indent()105 result += "%*s%s\n" % (formatter.current_indent, "", cmd.usage)106 formatter.dedent()107 formatter.dedent()108 return result109 cmd_group = CommandOptionGroup(self.parser, "Console Commands",110 description="The following commands can be issued at the "111 "command line. Commands should be quoted, so, for example, "112 "to pause torrent with id 'abc' you would run: '%s "113 "\"pause abc\"'"%os.path.basename(sys.argv[0]),114 cmds=self.cmds)115 self.parser.add_option_group(cmd_group)116 67 117 68 def start(self): 118 69 super(Console, self).start() 119 ConsoleUI(self.args,self.cmds,(self.options.daemon_addr, 120 self.options.daemon_port,self.options.daemon_user, 121 self.options.daemon_pass)) 70 71 ConsoleUI(self.args) 122 72 123 73 def start(): … … 140 90 raise Exception(msg) 141 91 142 143 92 class BaseCommand(object): 144 93 145 94 usage = 'usage' 146 interactive_only = False147 95 option_list = tuple() 148 96 aliases = [] … … 171 119 epilog = self.epilog, 172 120 option_list = self.option_list) 173 174 121 175 122 def load_commands(command_dir, exclude=[]): … … 193 140 return {} 194 141 195 196 142 class ConsoleUI(component.Component): 197 def __init__(self, args=None , cmds = None, daemon = None):143 def __init__(self, args=None): 198 144 component.Component.__init__(self, "ConsoleUI", 2) 199 145 200 # keep track of events for the log view 201 self.events = [] 146 self.batch_write = False 202 147 203 148 try: … … 208 153 209 154 log.debug("Using encoding: %s", self.encoding) 210 211 212 # start up the session proxy 213 self.sessionproxy = SessionProxy() 155 # Load all the commands 156 self._commands = load_commands(os.path.join(UI_PATH, 'commands')) 214 157 215 158 client.set_disconnect_callback(self.on_client_disconnect) … … 220 163 args = args[0] 221 164 self.interactive = False 222 if not cmds: 223 print "Sorry, couldn't find any commands" 224 return 225 else: 226 self._commands = cmds 227 from commander import Commander 228 cmdr = Commander(cmds) 229 if daemon: 230 cmdr.exec_args(args,*daemon) 231 else: 232 cmdr.exec_args(args,None,None,None,None) 233 165 166 # Try to connect to the localhost daemon 167 def on_connect(result): 168 def on_started(result): 169 if not self.interactive: 170 def on_started(result): 171 deferreds = [] 172 # If we have args, lets process them and quit 173 # allow multiple commands split by ";" 174 for arg in args.split(";"): 175 deferreds.append(defer.maybeDeferred(self.do_command, arg.strip())) 176 177 def on_complete(result): 178 self.do_command("quit") 179 180 dl = defer.DeferredList(deferreds).addCallback(on_complete) 181 182 # We need to wait for the rpcs in start() to finish before processing 183 # any of the commands. 184 self.started_deferred.addCallback(on_started) 185 component.start().addCallback(on_started) 186 187 d = client.connect() 188 d.addCallback(on_connect) 234 189 235 190 self.coreconfig = CoreConfig() … … 240 195 curses.wrapper(self.run) 241 196 elif self.interactive and deluge.common.windows_check(): 242 print """\nDeluge-console does not run in interactive mode on Windows. \n 243 Please use commands from the command line, eg:\n 244 deluge-console.exe help 245 deluge-console.exe info 246 deluge-console.exe "add --help" 247 deluge-console.exe "add -p c:\\mytorrents c:\\new.torrent" 248 """ 197 print "You cannot run the deluge-console in interactive mode in Windows.\ 198 Please use commands from the command line, eg: deluge-console config;help;exit" 249 199 else: 250 200 reactor.run() … … 261 211 # pass it the function that handles commands 262 212 colors.init_colors() 213 self.screen = screen.Screen(stdscr, self.do_command, self.tab_completer, self.encoding) 263 214 self.statusbars = StatusBars() 264 from modes.connectionmanager import ConnectionManager265 self.screen = ConnectionManager(stdscr, self.encoding)266 215 self.eventlog = EventLog() 267 216 … … 277 226 reactor.run() 278 227 279 280 228 def start(self): 229 # This gets fired once we have received the torrents list from the core 230 self.started_deferred = defer.Deferred() 231 281 232 # Maintain a list of (torrent_id, name) for use in tab completion 282 233 self.torrents = [] 283 if not self.interactive: 284 self.started_deferred = defer.Deferred() 285 def on_session_state(result): 286 def on_torrents_status(torrents): 287 for torrent_id, status in torrents.items(): 288 self.torrents.append((torrent_id, status["name"])) 289 self.started_deferred.callback(True) 290 291 client.core.get_torrents_status({"id": result}, ["name"]).addCallback(on_torrents_status) 292 client.core.get_session_state().addCallback(on_session_state) 293 294 234 def on_session_state(result): 235 def on_torrents_status(torrents): 236 for torrent_id, status in torrents.items(): 237 self.torrents.append((torrent_id, status["name"])) 238 self.started_deferred.callback(True) 239 240 client.core.get_torrents_status({"id": result}, ["name"]).addCallback(on_torrents_status) 241 client.core.get_session_state().addCallback(on_session_state) 242 243 # Register some event handlers to keep the torrent list up-to-date 244 client.register_event_handler("TorrentAddedEvent", self.on_torrent_added_event) 245 client.register_event_handler("TorrentRemovedEvent", self.on_torrent_removed_event) 246 247 def update(self): 248 pass 249 250 def set_batch_write(self, batch): 251 """ 252 When this is set the screen is not refreshed after a `:meth:write` until 253 this is set to False. 254 255 :param batch: set True to prevent screen refreshes after a `:meth:write` 256 :type batch: bool 257 258 """ 259 self.batch_write = batch 260 if not batch and self.interactive: 261 self.screen.refresh() 262 263 def write(self, line): 264 """ 265 Writes a line out depending on if we're in interactive mode or not. 266 267 :param line: str, the line to print 268 269 """ 270 if self.interactive: 271 self.screen.add_line(line, not self.batch_write) 272 else: 273 print(colors.strip_colors(line)) 274 275 def do_command(self, cmd): 276 """ 277 Processes a command. 278 279 :param cmd: str, the command string 280 281 """ 282 if not cmd: 283 return 284 cmd, _, line = cmd.partition(' ') 285 try: 286 parser = self._commands[cmd].create_parser() 287 except KeyError: 288 self.write("{!error!}Unknown command: %s" % cmd) 289 return 290 args = self._commands[cmd].split(line) 291 292 # Do a little hack here to print 'command --help' properly 293 parser._print_help = parser.print_help 294 def print_help(f=None): 295 if self.interactive: 296 self.write(parser.format_help()) 297 else: 298 parser._print_help(f) 299 parser.print_help = print_help 300 301 # Only these commands can be run when not connected to a daemon 302 not_connected_cmds = ["help", "connect", "quit"] 303 aliases = [] 304 for c in not_connected_cmds: 305 aliases.extend(self._commands[c].aliases) 306 not_connected_cmds.extend(aliases) 307 308 if not client.connected() and cmd not in not_connected_cmds: 309 self.write("{!error!}Not connected to a daemon, please use the connect command first.") 310 return 311 312 try: 313 options, args = parser.parse_args(args) 314 except Exception, e: 315 self.write("{!error!}Error parsing options: %s" % e) 316 return 317 318 if not getattr(options, '_exit', False): 319 try: 320 ret = self._commands[cmd].handle(*args, **options.__dict__) 321 except Exception, e: 322 self.write("{!error!}" + str(e)) 323 log.exception(e) 324 import traceback 325 self.write("%s" % traceback.format_exc()) 326 return defer.succeed(True) 327 else: 328 return ret 329 330 def tab_completer(self, line, cursor, second_hit): 331 """ 332 Called when the user hits 'tab' and will autocomplete or show options. 333 If a command is already supplied in the line, this function will call the 334 complete method of the command. 335 336 :param line: str, the current input string 337 :param cursor: int, the cursor position in the line 338 :param second_hit: bool, if this is the second time in a row the tab key 339 has been pressed 340 341 :returns: 2-tuple (string, cursor position) 342 343 """ 344 # First check to see if there is no space, this will mean that it's a 345 # command that needs to be completed. 346 if " " not in line: 347 possible_matches = [] 348 # Iterate through the commands looking for ones that startwith the 349 # line. 350 for cmd in self._commands: 351 if cmd.startswith(line): 352 possible_matches.append(cmd + " ") 353 354 line_prefix = "" 355 else: 356 cmd = line.split(" ")[0] 357 if cmd in self._commands: 358 # Call the command's complete method to get 'er done 359 possible_matches = self._commands[cmd].complete(line.split(" ")[-1]) 360 line_prefix = " ".join(line.split(" ")[:-1]) + " " 361 else: 362 # This is a bogus command 363 return (line, cursor) 364 365 # No matches, so just return what we got passed 366 if len(possible_matches) == 0: 367 return (line, cursor) 368 # If we only have 1 possible match, then just modify the line and 369 # return it, else we need to print out the matches without modifying 370 # the line. 371 elif len(possible_matches) == 1: 372 new_line = line_prefix + possible_matches[0] 373 return (new_line, len(new_line)) 374 else: 375 if second_hit: 376 # Only print these out if it's a second_hit 377 self.write(" ") 378 for match in possible_matches: 379 self.write(match) 380 else: 381 p = " ".join(line.split(" ")[:-1]) 382 new_line = " ".join([p, os.path.commonprefix(possible_matches)]) 383 if len(new_line) > len(line): 384 line = new_line 385 cursor = len(line) 386 return (line, cursor) 387 388 def tab_complete_torrent(self, line): 389 """ 390 Completes torrent_ids or names. 391 392 :param line: str, the string to complete 393 394 :returns: list of matches 395 396 """ 397 398 possible_matches = [] 399 400 # Find all possible matches 401 for torrent_id, torrent_name in self.torrents: 402 if torrent_id.startswith(line): 403 possible_matches.append(torrent_id + " ") 404 if torrent_name.startswith(line): 405 possible_matches.append(torrent_name + " ") 406 407 return possible_matches 408 409 def get_torrent_name(self, torrent_id): 410 """ 411 Gets a torrent name from the torrents list. 412 413 :param torrent_id: str, the torrent_id 414 415 :returns: the name of the torrent or None 416 """ 417 418 for tid, name in self.torrents: 419 if torrent_id == tid: 420 return name 421 422 return None 423 295 424 def match_torrent(self, string): 296 425 """ … … 311 440 return ret 312 441 313 314 def get_torrent_name(self, torrent_id): 315 if self.interactive and hasattr(self.screen,"get_torrent_name"): 316 return self.screen.get_torrent_name(torrent_id) 317 318 for tid, name in self.torrents: 319 if torrent_id == tid: 320 return name 321 322 return None 323 324 325 def set_batch_write(self, batch): 326 # only kept for legacy reasons, don't actually do anything 327 pass 328 329 def set_mode(self, mode): 330 reactor.removeReader(self.screen) 331 self.screen = mode 332 self.statusbars.screen = self.screen 333 reactor.addReader(self.screen) 442 def on_torrent_added_event(self, event): 443 def on_torrent_status(status): 444 self.torrents.append((event.torrent_id, status["name"])) 445 client.core.get_torrent_status(event.torrent_id, ["name"]).addCallback(on_torrent_status) 446 447 def on_torrent_removed_event(self, event): 448 for index, (tid, name) in enumerate(self.torrents): 449 if event.torrent_id == tid: 450 del self.torrents[index] 334 451 335 452 def on_client_disconnect(self): 336 453 component.stop() 337 338 def write(self, s):339 if self.interactive:340 self.events.append(s)341 else:342 print colors.strip_colors(s) -
deluge/ui/coreconfig.py
r5f0f72 r499a58 46 46 component.Component.__init__(self, "CoreConfig") 47 47 self.config = {} 48 def on_configvaluechanged_event( event):49 self.config[ event.key] = event.value48 def on_configvaluechanged_event(key, value): 49 self.config[key] = value 50 50 client.register_event_handler("ConfigValueChangedEvent", on_configvaluechanged_event) 51 51 -
deluge/ui/gtkui/files_tab.py
r5f0f72 r499a58 628 628 self._editing_index = None 629 629 630 def _on_torrentfilerenamed_event(self, event):631 log.debug("index: %s name: %s", event.index, event.filename)632 633 if event.torrent_id not in self.files_list:630 def _on_torrentfilerenamed_event(self, torrent_id, index, name): 631 log.debug("index: %s name: %s", index, name) 632 633 if torrent_id not in self.files_list: 634 634 return 635 635 636 old_name = self.files_list[ event.torrent_id][event.index]["path"]637 self.files_list[ event.torrent_id][event.index]["path"] = event.filename636 old_name = self.files_list[torrent_id][index]["path"] 637 self.files_list[torrent_id][index]["path"] = name 638 638 639 639 # We need to update the filename displayed if we're currently viewing 640 640 # this torrents files. 641 if event.torrent_id == self.torrent_id:641 if torrent_id == self.torrent_id: 642 642 old_name_len = len(old_name.split("/")) 643 name_len = len( event.filename.split("/"))643 name_len = len(name.split("/")) 644 644 if old_name_len != name_len: 645 645 # The parent path list changes depending on which way the file … … 648 648 parent_path = [o for o in old_name.split("/")[:-1]] 649 649 else: 650 parent_path = [o for o in event.filename.split("/")[:-1]]650 parent_path = [o for o in name.split("/")[:-1]] 651 651 # Find the iter to the parent folder we need to add a new folder 652 652 # to. … … 655 655 if len(parent_path) == 1: 656 656 # This is the parent iter 657 to_create = event.filename.split("/")[len(old_name.split("/")[:-1]):-1]657 to_create = name.split("/")[len(old_name.split("/")[:-1]):-1] 658 658 parent_iter = itr 659 659 … … 674 674 # Find the iter for the file that needs to be moved 675 675 def get_file_iter(model, path, itr, user_data): 676 if model[itr][5] == event.index:677 model[itr][0] = event.filename.split("/")[-1]676 if model[itr][5] == index: 677 model[itr][0] = name.split("/")[-1] 678 678 t = self.treestore.append( 679 679 parent_iter, … … 694 694 self.treestore.foreach(find_parent, None) 695 695 else: 696 new_folders = event.filename.split("/")[:-1]696 new_folders = name.split("/")[:-1] 697 697 parent_iter = None 698 698 for f in new_folders: … … 708 708 # This is just changing a filename without any folder changes 709 709 def set_file_name(model, path, itr, user_data): 710 if model[itr][5] == event.index:711 model[itr][0] = os.path.split( event.filename)[-1]710 if model[itr][5] == index: 711 model[itr][0] = os.path.split(name)[-1] 712 712 return True 713 713 self.treestore.foreach(set_file_name, None) … … 755 755 itr = parent 756 756 757 def _on_torrentfolderrenamed_event(self, event):757 def _on_torrentfolderrenamed_event(self, torrent_id, old_folder, new_folder): 758 758 log.debug("on_torrent_folder_renamed_signal") 759 log.debug("old_folder: %s new_folder: %s", event.old, event.new)760 761 if event.torrent_id not in self.files_list:759 log.debug("old_folder: %s new_folder: %s", old_folder, new_folder) 760 761 if torrent_id not in self.files_list: 762 762 return 763 763 764 if event.old[-1] != "/":765 event.old+= "/"766 if event.new[-1] != "/":767 event.new+= "/"768 769 for fd in self.files_list[ event.torrent_id]:770 if fd["path"].startswith( event.old):771 fd["path"] = fd["path"].replace( event.old, event.new, 1)772 773 if event.torrent_id == self.torrent_id:774 775 old_split = event.old.split("/")764 if old_folder[-1] != "/": 765 old_folder += "/" 766 if new_folder[-1] != "/": 767 new_folder += "/" 768 769 for fd in self.files_list[torrent_id]: 770 if fd["path"].startswith(old_folder): 771 fd["path"] = fd["path"].replace(old_folder, new_folder, 1) 772 773 if torrent_id == self.torrent_id: 774 775 old_split = old_folder.split("/") 776 776 try: 777 777 old_split.remove("") … … 779 779 pass 780 780 781 new_split = event.new.split("/")781 new_split = new_folder.split("/") 782 782 try: 783 783 new_split.remove("") … … 785 785 pass 786 786 787 old_folder_iter = self.get_iter_at_path( event.old)787 old_folder_iter = self.get_iter_at_path(old_folder) 788 788 old_folder_iter_parent = self.treestore.iter_parent(old_folder_iter) 789 789 790 new_folder_iter = self.get_iter_at_path( event.new)790 new_folder_iter = self.get_iter_at_path(new_folder) 791 791 if len(new_split) == len(old_split): 792 792 # These are at the same tree depth, so it's a simple rename … … 808 808 self.remove_childless_folders(old_folder_iter_parent) 809 809 810 def _on_torrentremoved_event(self, event):811 if event.torrent_id in self.files_list:812 del self.files_list[ event.torrent_id]810 def _on_torrentremoved_event(self, torrent_id): 811 if torrent_id in self.files_list: 812 del self.files_list[torrent_id] 813 813 814 814 def _on_drag_data_get_data(self, treeview, context, selection, target_id, etime): -
deluge/ui/gtkui/mainwindow.py
r5f0f72 r499a58 248 248 self.window.set_title("Deluge") 249 249 250 def on_newversionavailable_event(self, event):250 def on_newversionavailable_event(self, new_version): 251 251 if self.config["show_new_releases"]: 252 252 from deluge.ui.gtkui.new_release_dialog import NewReleaseDialog 253 reactor.callLater(5.0, NewReleaseDialog().show, event.new_release)254 255 def on_torrentfinished_event(self, event):253 reactor.callLater(5.0, NewReleaseDialog().show, new_version) 254 255 def on_torrentfinished_event(self, torrent_id): 256 256 from deluge.ui.gtkui.notification import Notification 257 Notification().notify( event.torrent_id)257 Notification().notify(torrent_id) -
deluge/ui/gtkui/menubar.py
r5f0f72 r499a58 231 231 232 232 ### Callbacks ### 233 def on_torrentstatechanged_event(self, event):234 if event.state == "Paused":233 def on_torrentstatechanged_event(self, torrent_id, state): 234 if state == "Paused": 235 235 self.update_menu() 236 236 237 def on_torrentresumed_event(self, event):237 def on_torrentresumed_event(self, torrent_id): 238 238 self.update_menu() 239 239 -
deluge/ui/gtkui/pluginmanager.py
r5f0f72 r499a58 92 92 self.enable_plugin(plugin) 93 93 94 def _on_plugin_enabled_event(self, event):95 self.enable_plugin( event.plugin_name)94 def _on_plugin_enabled_event(self, name): 95 self.enable_plugin(name) 96 96 97 def _on_plugin_disabled_event(self, event):98 self.disable_plugin( event.plugin_name)97 def _on_plugin_disabled_event(self, name): 98 self.disable_plugin(name) 99 99 100 100 ## Hook functions -
deluge/ui/gtkui/statusbar.py
r5f0f72 r499a58 289 289 client.core.get_free_space().addCallback(self._on_get_free_space) 290 290 291 def on_configvaluechanged_event(self, event):291 def on_configvaluechanged_event(self, key, value): 292 292 """ 293 293 This is called when we receive a ConfigValueChangedEvent from … … 295 295 """ 296 296 297 if event.key in self.config_value_changed_dict.keys():298 self.config_value_changed_dict[ event.key](event.value)297 if key in self.config_value_changed_dict.keys(): 298 self.config_value_changed_dict[key](value) 299 299 300 300 def _on_max_connections_global(self, max_connections): -
deluge/ui/gtkui/systemtray.py
r5f0f72 r499a58 211 211 "payload_download_rate"]).addCallback(self._on_get_session_status) 212 212 213 def config_value_changed(self, event):213 def config_value_changed(self, key, value): 214 214 """This is called when we received a config_value_changed signal from 215 215 the core.""" 216 216 217 if event.key in self.config_value_changed_dict.keys():218 self.config_value_changed_dict[ event.key](event.value)217 if key in self.config_value_changed_dict.keys(): 218 self.config_value_changed_dict[key](value) 219 219 220 220 def _on_max_download_speed(self, max_download_speed): -
deluge/ui/gtkui/torrentview.py
r5f0f72 r499a58 522 522 widget.stop_emission("drag-drop") 523 523 524 def on_torrentadded_event(self, event):525 self.add_row( event.torrent_id)526 self.mark_dirty( event.torrent_id)527 528 def on_torrentremoved_event(self, event):529 self.remove_row( event.torrent_id)530 531 def on_torrentstatechanged_event(self, event):524 def on_torrentadded_event(self, torrent_id, from_state): 525 self.add_row(torrent_id) 526 self.mark_dirty(torrent_id) 527 528 def on_torrentremoved_event(self, torrent_id): 529 self.remove_row(torrent_id) 530 531 def on_torrentstatechanged_event(self, torrent_id, state): 532 532 # Update the torrents state 533 533 for row in self.liststore: 534 if not event.torrent_id == row[self.columns["torrent_id"].column_indices[0]]:534 if not torrent_id == row[self.columns["torrent_id"].column_indices[0]]: 535 535 continue 536 row[self.get_column_index(_("Progress"))[1]] = event.state537 538 self.mark_dirty( event.torrent_id)539 540 def on_sessionpaused_event(self , event):536 row[self.get_column_index(_("Progress"))[1]] = state 537 538 self.mark_dirty(torrent_id) 539 540 def on_sessionpaused_event(self): 541 541 self.mark_dirty() 542 542 self.update() 543 543 544 def on_sessionresumed_event(self , event):544 def on_sessionresumed_event(self): 545 545 self.mark_dirty() 546 546 self.update() 547 547 548 def on_torrentqueuechanged_event(self , event):548 def on_torrentqueuechanged_event(self): 549 549 self.mark_dirty() 550 550 self.update() -
deluge/ui/sessionproxy.py
r5f0f72 r499a58 237 237 return d.addCallback(on_status, None, keys) 238 238 239 def on_torrent_state_changed(self, event):240 if event.torrent_id in self.torrents:241 self.torrents[ event.torrent_id][1]["state"] = event.state242 self.cache_times[ event.torrent_id]["state"] = time.time()243 244 def on_torrent_added(self, event):245 self.torrents[ event.torrent_id] = [time.time() - self.cache_time - 1, {}]246 self.cache_times[ event.torrent_id] = {}239 def on_torrent_state_changed(self, torrent_id, state): 240 if torrent_id in self.torrents: 241 self.torrents[torrent_id][1]["state"] = state 242 self.cache_times[torrent_id]["state"] = time.time() 243 244 def on_torrent_added(self, torrent_id, from_state): 245 self.torrents[torrent_id] = [time.time() - self.cache_time - 1, {}] 246 self.cache_times[torrent_id] = {} 247 247 def on_status(status): 248 self.torrents[ event.torrent_id][1].update(status)248 self.torrents[torrent_id][1].update(status) 249 249 t = time.time() 250 250 for key in status: 251 self.cache_times[ event.torrent_id][key] = t252 client.core.get_torrent_status( event.torrent_id, []).addCallback(on_status)253 254 def on_torrent_removed(self, event):255 del self.torrents[ event.torrent_id]256 del self.cache_times[ event.torrent_id]251 self.cache_times[torrent_id][key] = t 252 client.core.get_torrent_status(torrent_id, []).addCallback(on_status) 253 254 def on_torrent_removed(self, torrent_id): 255 del self.torrents[torrent_id] 256 del self.cache_times[torrent_id] -
deluge/ui/web/pluginmanager.py
r5f0f72 r499a58 59 59 "script_directories": directories 60 60 } 61 61 62 62 class PluginManager(PluginManagerBase, component.Component): 63 63 def __init__(self): … … 65 65 self.config = ConfigManager("web.conf") 66 66 PluginManagerBase.__init__(self, "web.conf", "deluge.plugin.web") 67 67 68 68 client.register_event_handler("PluginEnabledEvent", self._on_plugin_enabled_event) 69 69 client.register_event_handler("PluginDisabledEvent", self._on_plugin_disabled_event) 70 70 71 71 def _on_get_enabled_plugins(self, plugins): 72 72 for plugin in plugins: 73 73 self.enable_plugin(plugin) 74 75 def _on_plugin_enabled_event(self, name): 76 self.enable_plugin(name) 74 77 75 def _on_plugin_enabled_event(self, event): 76 self.enable_plugin(event.plugin_name) 77 78 def _on_plugin_disabled_event(self, event): 79 self.disable_plugin(event.plugin_name) 80 78 def _on_plugin_disabled_event(self, name): 79 self.disable_plugin(name) 80 81 81 def disable_plugin(self, name): 82 82 # Get the plugin instance … … 86 86 log.info("Plugin has no web ui") 87 87 return 88 88 89 89 info = gather_info(plugin) 90 90 … … 92 92 for script in info["scripts"]: 93 93 scripts.remove_script("%s/%s" % (name.lower(), os.path.basename(script).lower())) 94 94 95 95 for script in info["debug_scripts"]: 96 96 scripts.remove_script("%s/%s" % (name.lower(), os.path.basename(script).lower()), "debug") 97 97 scripts.remove_script("%s/%s" % (name.lower(), os.path.basename(script).lower()), "dev") 98 98 99 99 super(PluginManager, self).disable_plugin(name) 100 100 101 101 def enable_plugin(self, name): 102 102 super(PluginManager, self).enable_plugin(name) 103 103 104 104 # Get the plugin instance 105 105 try: … … 108 108 log.info("Plugin has no web ui") 109 109 return 110 110 111 111 info = gather_info(plugin) 112 112 113 113 scripts = component.get("Scripts") 114 114 for script in info["scripts"]: … … 128 128 d = client.core.get_enabled_plugins() 129 129 d.addCallback(self._on_get_enabled_plugins) 130 130 131 131 def stop(self): 132 132 """ … … 134 134 """ 135 135 self.disable_plugins() 136 136 137 137 def update(self): 138 138 pass 139 139 140 140 def get_plugin_resources(self, name): 141 141 # Get the plugin instance
Note:
See TracChangeset
for help on using the changeset viewer.