From d27137b4e24597ed5208a630c9860495457fb524 Mon Sep 17 00:00:00 2001 From: Marcos Pinto Date: Wed, 11 Jul 2007 04:22:44 +0000 Subject: [PATCH] fixing imports and indents to comply with python style guide - first attempt, this might break things --- src/__init__.py | 1 + src/common.py | 120 +- src/core.py | 1423 +++++++++++------------ src/deluge_core.cpp | 200 ++-- src/deluge_stats.py | 74 +- src/dgtk.py | 160 +-- src/dialogs.py | 522 ++++----- src/interface.py | 2628 ++++++++++++++++++++++--------------------- src/ipc_manager.py | 73 +- src/plugins.py | 156 +-- src/pref.py | 276 ++--- 11 files changed, 2829 insertions(+), 2804 deletions(-) diff --git a/src/__init__.py b/src/__init__.py index e69de29bb..8b1378917 100644 --- a/src/__init__.py +++ b/src/__init__.py @@ -0,0 +1 @@ + diff --git a/src/common.py b/src/common.py index 9173e8595..359be15dc 100644 --- a/src/common.py +++ b/src/common.py @@ -14,9 +14,9 @@ # # You should have received a copy of the GNU General Public License # along with this program. If not, write to: -# The Free Software Foundation, Inc., -# 51 Franklin Street, Fifth Floor -# Boston, MA 02110-1301, USA. +# The Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor +# Boston, MA 02110-1301, USA. # # In addition, as a special exception, the copyright holders give # permission to link the code of portions of this program with the OpenSSL @@ -28,8 +28,12 @@ # this exception statement from your version. If you delete this exception # statement from all source files in the program, then also delete it here. -import sys, os, os.path, webbrowser -import xdg, xdg.BaseDirectory +import sys +import os +import os.path +import webbrowser +import xdg +import xdg.BaseDirectory import gettext @@ -48,83 +52,83 @@ PIXMAP_DIR = os.path.join(INSTALL_PREFIX, 'share', 'deluge', 'pixmaps') PLUGIN_DIR = os.path.join(INSTALL_PREFIX, 'share', 'deluge', 'plugins') def estimate_eta(state): - try: - return ftime(get_eta(state["total_size"], state["total_done"], state["download_rate"])) - except ZeroDivisionError: - return _("Infinity") - + try: + return ftime(get_eta(state["total_size"], state["total_done"], state["download_rate"])) + except ZeroDivisionError: + return _("Infinity") + def get_eta(size, done, speed): - if (size - done) == 0: - raise ZeroDivisionError - return (size - done) / speed + if (size - done) == 0: + raise ZeroDivisionError + return (size - done) / speed # Returns formatted string describing filesize # fsize_b should be in bytes # Returned value will be in either KB, MB, or GB def fsize(fsize_b): - fsize_kb = float (fsize_b / 1024.0) - if fsize_kb < 1000: - return _("%.1f KiB")%fsize_kb - fsize_mb = float (fsize_kb / 1024.0) - if fsize_mb < 1000: - return _("%.1f MiB")%fsize_mb - fsize_gb = float (fsize_mb / 1024.0) - return _("%.1f GiB")%fsize_gb + fsize_kb = float (fsize_b / 1024.0) + if fsize_kb < 1000: + return _("%.1f KiB")%fsize_kb + fsize_mb = float (fsize_kb / 1024.0) + if fsize_mb < 1000: + return _("%.1f MiB")%fsize_mb + fsize_gb = float (fsize_mb / 1024.0) + return _("%.1f GiB")%fsize_gb # Returns a formatted string representing a percentage def fpcnt(dec): - return '%.2f%%'%(dec * 100) + return '%.2f%%'%(dec * 100) # Returns a formatted string representing transfer speed def fspeed(bps): - return '%s/s'%(fsize(bps)) + return '%s/s'%(fsize(bps)) def fseed(state): - return str(str(state['num_seeds']) + " (" + str(state['total_seeds']) + ")") - + return str(str(state['num_seeds']) + " (" + str(state['total_seeds']) + ")") + def fpeer(state): - return str(str(state['num_peers']) + " (" + str(state['total_peers']) + ")") - + return str(str(state['num_peers']) + " (" + str(state['total_peers']) + ")") + def ftime(seconds): - if seconds < 60: - return '%ds'%(seconds) - minutes = int(seconds/60) - seconds = seconds % 60 - if minutes < 60: - return '%dm %ds'%(minutes, seconds) - hours = int(minutes/60) - minutes = minutes % 60 - if hours < 24: - return '%dh %dm'%(hours, minutes) - days = int(hours/24) - hours = hours % 24 - if days < 7: - return '%dd %dh'%(days, hours) - weeks = int(days/7) - days = days % 7 - if weeks < 10: - return '%dw %dd'%(weeks, days) - return 'unknown' + if seconds < 60: + return '%ds'%(seconds) + minutes = int(seconds/60) + seconds = seconds % 60 + if minutes < 60: + return '%dm %ds'%(minutes, seconds) + hours = int(minutes/60) + minutes = minutes % 60 + if hours < 24: + return '%dh %dm'%(hours, minutes) + days = int(hours/24) + hours = hours % 24 + if days < 7: + return '%dd %dh'%(days, hours) + weeks = int(days/7) + days = days % 7 + if weeks < 10: + return '%dw %dd'%(weeks, days) + return 'unknown' def get_glade_file(fname): - return os.path.join(GLADE_DIR, fname) + return os.path.join(GLADE_DIR, fname) def get_pixmap(fname): - return os.path.join(PIXMAP_DIR, fname) - + return os.path.join(PIXMAP_DIR, fname) + def open_url_in_browser(dialog, link): - try: - webbrowser.open(link) - except webbrowser.Error: - print _("Error: no webbrowser found") - + try: + webbrowser.open(link) + except webbrowser.Error: + print _("Error: no webbrowser found") + # Encryption States class EncState: - forced, enabled, disabled = range(3) - + forced, enabled, disabled = range(3) + class EncLevel: - plaintext, rc4, both = range(3) + plaintext, rc4, both = range(3) class ProxyType: - none, socks4, socks5, socks5_pw, http, http_pw = range(6) + none, socks4, socks5, socks5_pw, http, http_pw = range(6) diff --git a/src/core.py b/src/core.py index 04e5a2629..b6a9c28fa 100644 --- a/src/core.py +++ b/src/core.py @@ -1,4 +1,5 @@ -# +# core.py +# # Copyright (C) 2006 Alon Zakai ('Kripken') # # This program is free software; you can redistribute it and/or modify @@ -13,9 +14,9 @@ # # You should have received a copy of the GNU General Public License # along with this program. If not, write to: -# The Free Software Foundation, Inc., -# 51 Franklin Street, Fifth Floor -# Boston, MA 02110-1301, USA. +# The Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor +# Boston, MA 02110-1301, USA. # # In addition, as a special exception, the copyright holders give # permission to link the code of portions of this program with the OpenSSL @@ -40,15 +41,21 @@ # # Documentation: -# Torrents have 3 structures: -# 1. torrent_info - persistent data, like name, upload speed cap, etc. -# 2. core_torrent_state - transient state data from the core. This may take -# time to calculate, so we do if efficiently -# 3. supp_torrent_state - supplementary torrent data, from Deluge +# Torrents have 3 structures: +# 1. torrent_info - persistent data, like name, upload speed cap, etc. +# 2. core_torrent_state - transient state data from the core. This may take +# time to calculate, so we do if efficiently +# 3. supp_torrent_state - supplementary torrent data, from Deluge import deluge_core -import os, os.path, shutil, statvfs -import pickle, time, gettext, pref +import os +import os.path +import shutil +import statvfs +import pickle +import time +import gettext +import pref # Constants @@ -61,774 +68,772 @@ DHT_FILENAME = "dht.state" CACHED_DATA_EXPIRATION = 1 # seconds, like the output of time.time() PREF_FUNCTIONS = { - "max_uploads" : deluge_core.set_max_uploads, - "listen_on" : deluge_core.set_listen_on, - "max_connections" : deluge_core.set_max_connections, - "max_active_torrents" : None, # no need for a function, applied constantly - "auto_seed_ratio" : None, # no need for a function, applied constantly - "max_download_speed_bps" : deluge_core.set_download_rate_limit, - "max_upload_speed_bps" : deluge_core.set_upload_rate_limit, - "enable_dht" : None, # not a normal pref in that is is applied only on start - "use_upnp" : deluge_core.use_upnp, - "use_natpmp" : deluge_core.use_natpmp, - "use_utpex" : deluge_core.use_utpex, + "max_uploads" : deluge_core.set_max_uploads, + "listen_on" : deluge_core.set_listen_on, + "max_connections" : deluge_core.set_max_connections, + "max_active_torrents" : None, # no need for a function, applied constantly + "auto_seed_ratio" : None, # no need for a function, applied constantly + "max_download_speed_bps" : deluge_core.set_download_rate_limit, + "max_upload_speed_bps" : deluge_core.set_upload_rate_limit, + "enable_dht" : None, # not a normal pref in that is is applied only on start + "use_upnp" : deluge_core.use_upnp, + "use_natpmp" : deluge_core.use_natpmp, + "use_utpex" : deluge_core.use_utpex, } def N_(self): return self -STATE_MESSAGES = ( N_("Queued"), - N_("Checking"), - N_("Connecting"), - N_("Downloading Metadata"), - N_("Downloading"), - N_("Finished"), - N_("Seeding"), - N_("Allocating") - ) +STATE_MESSAGES = ( N_("Queued"), + N_("Checking"), + N_("Connecting"), + N_("Downloading Metadata"), + N_("Downloading"), + N_("Finished"), + N_("Seeding"), + N_("Allocating") + ) # Exceptions class DelugeError(Exception): - def __init__(self, value): - self.value = value - def __str__(self): - return repr(self.value) + def __init__(self, value): + self.value = value + def __str__(self): + return repr(self.value) class InvalidEncodingError(DelugeError): - pass + pass class FilesystemError(DelugeError): - pass + pass # Note: this may be raised both from deluge-core.cpp and deluge.py, for # different reasons, both related to duplicate torrents class DuplicateTorrentError(DelugeError): - pass + pass class InvalidTorrentError(DelugeError): - pass + pass class InvalidUniqueIDError(DelugeError): - pass + pass class InsufficientFreeSpaceError(DelugeError): - def __init__(self, free_space, needed_space): - self.free_space = free_space - self.needed_space = needed_space - def __str__(self): - return _("%d %d bytes needed")%(self.free_space, self.needed_space) + def __init__(self, free_space, needed_space): + self.free_space = free_space + self.needed_space = needed_space + def __str__(self): + return _("%d %d bytes needed")%(self.free_space, self.needed_space) # A cached data item class cached_data: - def __init__(self, get_method, key): - self.get_method = get_method - self.key = key + def __init__(self, get_method, key): + self.get_method = get_method + self.key = key - self.timestamp = -1 + self.timestamp = -1 - def get(self, efficiently=True): - if self.timestamp == -1 or time.time() > self.timestamp + CACHED_DATA_EXPIRATION or \ - not efficiently: - self.data = self.get_method(self.key) - self.timestamp = time.time() + def get(self, efficiently=True): + if self.timestamp == -1 or time.time() > self.timestamp + CACHED_DATA_EXPIRATION or \ + not efficiently: + self.data = self.get_method(self.key) + self.timestamp = time.time() - return self.data + return self.data - + # Persistent information for a single torrent class torrent_info: - def __init__(self, filename, save_dir, compact): - self.filename = filename - self.save_dir = save_dir - self.compact = compact + def __init__(self, filename, save_dir, compact): + self.filename = filename + self.save_dir = save_dir + self.compact = compact - self.user_paused = False # start out unpaused - self.uploaded_memory = 0 + self.user_paused = False # start out unpaused + self.uploaded_memory = 0 - self.delete_me = False # set this to true, to delete it on next sync + self.delete_me = False # set this to true, to delete it on next sync # The persistent state of the torrent system. Everything in this will be pickled class persistent_state: - def __init__(self): - # Torrents - self.torrents = [] + def __init__(self): + # Torrents + self.torrents = [] - # Prepare queue (queue is pickled, just like everything else) - self.queue = [] # queue[x] is the unique_ID of the x-th queue position. Simple. + # Prepare queue (queue is pickled, just like everything else) + self.queue = [] # queue[x] is the unique_ID of the x-th queue position. Simple. # The manager for the torrent system class Manager: - # blank_slate mode ignores the two pickle files and DHT state file, i.e. you start - # completely fresh. When quitting, the old files will be overwritten - def __init__(self, client_ID, version, user_agent, base_dir, blank_slate=False): - self.base_dir = base_dir + # blank_slate mode ignores the two pickle files and DHT state file, i.e. you start + # completely fresh. When quitting, the old files will be overwritten + def __init__(self, client_ID, version, user_agent, base_dir, blank_slate=False): + self.base_dir = base_dir - # Ensure directories exist - if not TORRENTS_SUBDIR in os.listdir(self.base_dir): - os.mkdir(os.path.join(self.base_dir, TORRENTS_SUBDIR)) + # Ensure directories exist + if not TORRENTS_SUBDIR in os.listdir(self.base_dir): + os.mkdir(os.path.join(self.base_dir, TORRENTS_SUBDIR)) - # Pre-initialize the core's data structures - deluge_core.pre_init(DelugeError, + # Pre-initialize the core's data structures + deluge_core.pre_init(DelugeError, InvalidEncodingError, FilesystemError, DuplicateTorrentError, InvalidTorrentError) - # Start up the core - assert(len(version) == 4) - deluge_core.init(client_ID, - int(version[0]), - int(version[1]), - int(version[2]), - int(version[3]), - user_agent) - - self.constants = deluge_core.constants() - - # Unique IDs are NOT in the state, since they are temporary for each session - self.unique_IDs = {} # unique_ID -> a torrent_info object, i.e. persistent data - - # Saved torrent core_states. We do not poll the core in a costly manner, necessarily - self.saved_core_torrent_states = {} # unique_ID -> torrent_state - - # supplementary torrent states - self.supp_torrent_states = {} # unique_ID->dict of data - - # Saved torrent core_states. We do not poll the core in a costly manner, necessarily - self.saved_core_torrent_peer_infos = {} # unique_ID -> torrent_state - - # Saved torrent core_states. We do not poll the core in a costly manner, necessarily - self.saved_core_torrent_file_infos = {} # unique_ID -> torrent_state - - # Keeps track of DHT running state - self.dht_running = False - - # Load the preferences - self.config = pref.Preferences(os.path.join(self.base_dir, PREFS_FILENAME)) - - # Apply preferences. Note that this is before any torrents are added - self.apply_prefs() - - PREF_FUNCTIONS["enable_dht"] = self.set_DHT - - # Unpickle the state, or create a new one - if not blank_slate: - try: - pkl_file = open(os.path.join(self.base_dir, STATE_FILENAME), 'rb') - self.state = pickle.load(pkl_file) - pkl_file.close() - - # Sync with the core: tell core about torrents, and get unique_IDs - self.sync() - - # Apply all the file filters, right after adding the torrents - self.apply_all_file_filters() - - # Apply the queue at this time, after all is loaded and ready - self.apply_queue() - except IOError: - self.state = persistent_state() - else: - self.state = persistent_state() - - - - def quit(self): - # Analyze data needed for pickling, etc. - self.pre_quitting() - - # Pickle the prefs - print "Saving prefs..." - self.config.save() - - # Pickle the state - print "Pickling state..." - output = open(os.path.join(self.base_dir, STATE_FILENAME), 'wb') - pickle.dump(self.state, output) - output.close() - - # Stop DHT, if needed - self.set_DHT(False) - - # Save fastresume data - print "Saving fastresume data..." - self.save_fastresume_data() - - # Shutdown torrent core - print "Quitting the core..." - deluge_core.quit() - - def pre_quitting(self): - # Save the uploaded data from this session to the existing upload memory - for unique_ID in self.unique_IDs.keys(): - self.unique_IDs[unique_ID].uploaded_memory = \ - self.unique_IDs[unique_ID].uploaded_memory + \ - self.get_core_torrent_state(unique_ID, False)['total_upload'] # Purposefully ineffi. - - # Preference management functions - - def get_config(self): - # This returns the preference object - return self.config - - def get_pref(self, key): - # Get the value from the preferences object - return self.config.get(key) - - def set_pref(self, key, value): - # Make sure this is a valid key - if key not in pref.DEFAULT_PREFS.keys(): - raise DelugeError("Asked to change a pref that isn't valid: " + key) - - self.config.set(key, value) - - # Apply the pref, if applicable - if PREF_FUNCTIONS[key] is not None: - PREF_FUNCTIONS[key](value) - - # Torrent addition and removal functions - - def add_torrent(self, filename, save_dir, compact): - self.add_torrent_ns(filename, save_dir, compact) - return self.sync() # Syncing will create a new torrent in the core, and return it's ID - - def remove_torrent(self, unique_ID, data_also, torrent_also): - temp = self.unique_IDs[unique_ID] - temp_fileinfo = deluge_core.get_file_info(unique_ID) - - self.remove_torrent_ns(unique_ID) - self.sync() - - # Remove .torrent file if asked to do so - if torrent_also: - os.remove(temp.filename) - - # Remove data, if asked to do so - if data_also: - # Must be done AFTER the torrent is removed - # Note: can this be to the trash? - for filedata in temp_fileinfo: - filename = filedata['path'] - if filename.find(os.sep) != -1: - # This is a file inside a directory inside the torrent. We can delete the - # directory itself, save time - try: - shutil.rmtree(os.path.dirname(os.path.join(temp.save_dir, filename))) - except OSError: # Perhaps it wasn't downloaded - pass - # Perhaps this is just a file, try to remove it - try: - os.remove(os.path.join(temp.save_dir, filename)) - except OSError: - pass # No file just means it wasn't downloaded, we can continue - - # A function to try and reload a torrent from a previous session. This is - # used in the event that Deluge crashes and a blank state is loaded. - def add_old_torrent(self, filename, save_dir, compact): - if not filename in os.listdir(os.path.join(self.base_dir, TORRENTS_SUBDIR)): - raise InvalidTorrentError(_("File was not found") + ": " + filename) - - full_new_name = os.path.join(self.base_dir, TORRENTS_SUBDIR, filename) - - # Create torrent object - new_torrent = torrent_info(full_new_name, save_dir, compact) - self.state.torrents.append(new_torrent) - - return self.sync() - - # A separate function, because people may want to call it from time to time - def save_fastresume_data(self, uid=None): - if uid == None: - for unique_ID in self.unique_IDs: - deluge_core.save_fastresume(unique_ID, self.unique_IDs[unique_ID].filename) - else: - deluge_core.save_fastresume(uid, self.unique_IDs[uid].filename) - - # Load all NEW torrents in a directory. The GUI can call this every minute or so, - # if one wants a directory to be 'watched' (personally, I think it should only be - # done on user command).os.path.join( - def autoload_directory(self, directory, save_dir, compact): - for filename in os.listdir(directory): - if filename[-len(".torrent"):].lower() == ".torrent": - try: - self.add_torrent_ns(self, filename, save_dir, compact) - except DuplicateTorrentError: - pass - - self.sync() - - # State retrieval functions - - def get_state(self): - ret = deluge_core.get_session_info() - - # Get additional data from our level - ret['is_listening'] = deluge_core.is_listening() - ret['port'] = deluge_core.listening_port() - if self.dht_running == True: - ret['DHT_nodes'] = deluge_core.get_DHT_info() - - return ret - - # This is the EXTERNAL function, for the GUI. It returns the core_state + supp_state - def get_torrent_state(self, unique_ID): - # Check to see if unique_ID exists: - if self.state.queue.count(unique_ID) == 0: - raise InvalidUniqueIDError("Asked for a torrent that doesn't exist") - - ret = self.get_core_torrent_state(unique_ID, True).copy() - - # Add the deluge-level things to the deluge_core data - if self.get_supp_torrent_state(unique_ID) is not None: - ret.update(self.get_supp_torrent_state(unique_ID)) - - # Get queue position - ret['queue_pos'] = self.state.queue.index(unique_ID) - - return ret - - def get_torrent_peer_info(self, unique_ID): - # Perhaps at some time we may add info here - return self.get_core_torrent_peer_info(unique_ID) - - def get_torrent_file_info(self, unique_ID): - return self.get_core_torrent_file_info(unique_ID) - - # Queueing functions - - def queue_top(self, unique_ID, enforce_queue=True): - self.state.queue.insert(0,self.state.queue.pop(self.get_queue_index(unique_ID))) - - def queue_up(self, unique_ID, enforce_queue=True): - curr_index = self.get_queue_index(unique_ID) - if curr_index > 0: - temp = self.state.queue[curr_index - 1] - self.state.queue[curr_index - 1] = unique_ID - self.state.queue[curr_index] = temp - if enforce_queue: - self.apply_queue() - - def queue_down(self, unique_ID, enforce_queue=True): - curr_index = self.get_queue_index(unique_ID) - if curr_index < (len(self.state.queue) - 1): - temp = self.state.queue[curr_index + 1] - self.state.queue[curr_index + 1] = unique_ID - self.state.queue[curr_index] = temp - if enforce_queue: - self.apply_queue() - - def queue_bottom(self, unique_ID, enforce_queue=True): - curr_index = self.get_queue_index(unique_ID) - if curr_index < (len(self.state.queue) - 1): - self.state.queue.remove(unique_ID) - self.state.queue.append(unique_ID) - if enforce_queue: - self.apply_queue() - - def clear_completed(self): - for unique_ID in self.unique_IDs: - torrent_state = self.get_core_torrent_state(unique_ID) - if torrent_state['progress'] == 1.0: - self.remove_torrent_ns(unique_ID) - - self.sync() - self.apply_queue() - - # Enforce the queue: pause/unpause as needed, based on queue and user_pausing - # This should be called after changes to relevant parameters (user_pausing, or - # altering max_active_torrents), or just from time to time - # ___ALL queuing code should be in this function, and ONLY here___ - def apply_queue(self, efficient = True): - # Handle autoseeding - downqueue as needed - if self.get_pref('auto_seed_ratio') > 0 and self.get_pref('auto_end_seeding'): - for unique_ID in self.unique_IDs: - if self.get_core_torrent_state(unique_ID, efficient)['is_seed']: - torrent_state = self.get_core_torrent_state(unique_ID, efficient) - ratio = self.calc_ratio(unique_ID, torrent_state) - if ratio >= self.get_pref('auto_seed_ratio'): - self.queue_bottom(unique_ID, enforce_queue=False) # don't recurse! - self.set_user_pause(unique_ID, True, enforce_queue=False) - - # Pause and resume torrents - for index in range(len(self.state.queue)): - unique_ID = self.state.queue[index] - if (index < self.get_pref('max_active_torrents') or self.get_pref('max_active_torrents') == -1) \ - and self.get_core_torrent_state(unique_ID, efficient)['is_paused'] \ - and not self.is_user_paused(unique_ID): - - # This torrent is a seed so skip all the free space checking - if self.get_core_torrent_state(unique_ID, efficient)['is_seed']: - deluge_core.resume(unique_ID) - continue - - # Before we resume, we should check if the torrent is using Full Allocation - # and if there is enough space on to finish this file. - if self.unique_IDs[unique_ID].compact == False: - torrent_state = self.get_core_torrent_state(unique_ID, efficient) - avail = self.calc_free_space(self.unique_IDs[unique_ID].save_dir) - total_needed = torrent_state["total_size"] - torrent_state["total_done"] - if total_needed < avail: - # We have enough free space, so lets resume this torrent - deluge_core.resume(unique_ID) - else: - print "Not enough free space to resume this torrent!" - else: #We're using compact allocation so lets just resume - deluge_core.resume(unique_ID) - - elif (not self.get_core_torrent_state(unique_ID, efficient)['is_paused']) and \ - ( (index >= self.get_pref('max_active_torrents') and \ - self.get_pref('max_active_torrents') != -1 ) or \ - self.is_user_paused(unique_ID)): - deluge_core.pause(unique_ID) - - # Event handling - - def handle_events(self): - # Handle them for the backend's purposes, but still send them up in case the client - # wants to do something - show messages, for example - def pop_event(): - try: - return deluge_core.pop_event() - except: - pass - else: - return deluge_core.pop_event() - - ret = [] - try: - event = deluge_core.pop_event() - except: - pass - else: - while event is not None: - # print "EVENT: ", event - - ret.append(event) - try: - if event['unique_ID'] not in self.unique_IDs: - event = pop_event() - continue - except KeyError: - event = pop_event() - continue - - if event['event_type'] is self.constants['EVENT_FINISHED']: - # Queue seeding torrent to bottom if needed - if self.get_pref('queue_seeds_to_bottom'): - self.queue_bottom(event['unique_ID']) - # If we are autoseeding, then we need to apply the queue - if self.get_pref('auto_seed_ratio') == -1: - self.apply_queue(efficient = False) # To work on current data - #save fast resume once torrent finshes so as to not recheck seed if client crashes - self.save_fastresume_data(event['unique_ID']) - elif event['event_type'] is self.constants['EVENT_TRACKER']: - unique_ID = event['unique_ID'] - status = event['tracker_status'] - message = event['message'] - tracker = message[message.find('"')+1:message.rfind('"')] - - self.set_supp_torrent_state_val(unique_ID, - "tracker_status", - (tracker, status)) - - old_state = self.get_supp_torrent_state(unique_ID) - try: - new = old_state['tracker_messages'] - except KeyError: - new = {} - - new[tracker] = message - - self.set_supp_torrent_state_val(unique_ID, - "tracker_messages", - new) - - event = pop_event() - - return ret - - # Filtering functions - - def set_file_filter(self, unique_ID, file_filter): - assert(len(file_filter) == self.get_core_torrent_state(unique_ID, True)['num_files']) - - self.unique_IDs[unique_ID].file_filter = file_filter[:] - - deluge_core.set_filter_out(unique_ID, file_filter) - - def get_file_filter(self, unique_ID): - try: - return self.unique_IDs[unique_ID].file_filter[:] - except AttributeError: - return None - - # Called when a session starts, to apply existing filters - def apply_all_file_filters(self): - for unique_ID in self.unique_IDs.keys(): - try: - self.set_file_filter(unique_ID, self.unique_IDs[unique_ID].file_filter) - except AttributeError: - pass - - # Advanced statistics - these may be SLOW. The client should call these only - # when needed, and perhaps only once in a long while (they are mostly just - # approximations anyhow - - def calc_availability(self, unique_ID): - return deluge_stats.calc_availability(self.get_core_torrent_peer_info(unique_ID)) - - def calc_swarm_speed(self, unique_ID): - pieces_per_sec = deluge_stats.calc_swarm_speed(self.get_core_torrent_peer_info(unique_ID)) - piece_length = self.get_core_torrent_state(unique_ID, efficiently=True) - - return pieces_per_sec * piece_length - - # Miscellaneous minor functions - - def set_user_pause(self, unique_ID, new_value, enforce_queue=True): - self.unique_IDs[unique_ID].user_paused = new_value - if enforce_queue: - self.apply_queue() - - def set_ratio(self, unique_ID, num): - deluge_core.set_ratio(unique_ID, float(num)) - - def is_user_paused(self, unique_ID): - return self.unique_IDs[unique_ID].user_paused - - def get_num_torrents(self): - return deluge_core.get_num_torrents() - - def get_unique_IDs(self): - return self.unique_IDs.keys() - - def update_tracker(self, unique_ID): - deluge_core.reannounce(unique_ID) - - - #################### - # Internal functions - #################### - - # Efficient: use a saved state, if it hasn't expired yet - def get_core_torrent_state(self, unique_ID, efficiently=True): - if unique_ID not in self.saved_core_torrent_states.keys(): - self.saved_core_torrent_states[unique_ID] = cached_data(deluge_core.get_torrent_state, - unique_ID) - - return self.saved_core_torrent_states[unique_ID].get(efficiently) - - def get_supp_torrent_state(self, unique_ID): - try: - return self.supp_torrent_states[unique_ID] - except KeyError: - return None - - def set_supp_torrent_state_val(self, unique_ID, key, val): - try: - if self.supp_torrent_states[unique_ID] is None: - self.supp_torrent_states[unique_ID] = {} - except KeyError: - self.supp_torrent_states[unique_ID] = {} - - self.supp_torrent_states[unique_ID][key] = val - - def get_core_torrent_peer_info(self, unique_ID, efficiently=True): - if unique_ID not in self.saved_core_torrent_peer_infos.keys(): - self.saved_core_torrent_peer_infos[unique_ID] = cached_data(deluge_core.get_peer_info, unique_ID) - - return self.saved_core_torrent_peer_infos[unique_ID].get(efficiently) - - def get_core_torrent_file_info(self, unique_ID, efficiently=True): - if unique_ID not in self.saved_core_torrent_file_infos.keys(): - self.saved_core_torrent_file_infos[unique_ID] = cached_data(deluge_core.get_file_info, unique_ID) - - return self.saved_core_torrent_file_infos[unique_ID].get(efficiently) - - # Functions for checking if enough space is available - - def calc_free_space(self, directory): - dir_stats = os.statvfs(directory) - block_size = dir_stats[statvfs.F_BSIZE] - avail_blocks = dir_stats[statvfs.F_BAVAIL] - return long(block_size * avail_blocks) - - # Non-syncing functions. Used when we loop over such events, and sync manually at the end - - def add_torrent_ns(self, filename, save_dir, compact): - # Cache torrent file - (temp, filename_short) = os.path.split(filename) - - # if filename_short in os.listdir(self.base_dir + "/" + TORRENTS_SUBDIR): - # raise DuplicateTorrentError("Duplicate Torrent, it appears: " + filename_short) - - full_new_name = os.path.join(self.base_dir, TORRENTS_SUBDIR, filename_short) - - try: - shutil.copy(filename, full_new_name) - except Exception, e: - if str(e).find('are the same file'): - pass - else: - raise - - # Create torrent object - new_torrent = torrent_info(full_new_name, save_dir, compact) - self.state.torrents.append(new_torrent) - - def remove_torrent_ns(self, unique_ID): - self.unique_IDs[unique_ID].delete_me = True - - - # Sync the state.torrents and unique_IDs lists with the core - # ___ALL syncing code with the core is here, and ONLY here___ - # Also all self-syncing is done here (various lists) - - ## - ## I had to make some changes here to get things to work properly - ## Some of these changes may be hack-ish, so look at them and make - ## sure nothing is wrong. - ## - def sync(self): - ret = None # We return new added unique ID(s), or None - no_space = False - - # Add torrents to core and unique_IDs - torrents_with_unique_ID = self.unique_IDs.values() - - for torrent in self.state.torrents: - if not os.path.exists(torrent.filename): - print "Missing file: %s" % torrent.filename - self.state.torrents.remove(torrent) - continue - if torrent not in torrents_with_unique_ID: -# print "Adding torrent to core:", torrent.filename, torrent.save_dir, torrent.compact - try: - unique_ID = deluge_core.add_torrent(torrent.filename, - torrent.save_dir, - torrent.compact) - except DelugeError, e: - print "Error:", e - self.state.torrents.remove(torrent) - raise e -# print "Got unique ID:", unique_ID - - ret = unique_ID - self.unique_IDs[unique_ID] = torrent - - -# print torrents_with_unique_ID - # Remove torrents from core, unique_IDs and queue - to_delete = [] - for unique_ID in self.unique_IDs.keys(): -# print torrent - if self.unique_IDs[unique_ID].delete_me: - deluge_core.remove_torrent(unique_ID) - to_delete.append(unique_ID) - - for unique_ID in to_delete: - self.state.torrents.remove(self.unique_IDs[unique_ID]) - self.state.queue.remove(unique_ID) - # Remove .fastresume - try: - # Must be after removal of the torrent, because that saves a new .fastresume - os.remove(self.unique_IDs[unique_ID].filename + ".fastresume") - except OSError: - pass # Perhaps there never was one to begin with - del self.unique_IDs[unique_ID] - - # Add torrents to queue - at the end, of course - for unique_ID in self.unique_IDs.keys(): - if unique_ID not in self.state.queue: - self.state.queue.append(unique_ID) + # Start up the core + assert(len(version) == 4) + deluge_core.init(client_ID, + int(version[0]), + int(version[1]), + int(version[2]), + int(version[3]), + user_agent) + + self.constants = deluge_core.constants() + + # Unique IDs are NOT in the state, since they are temporary for each session + self.unique_IDs = {} # unique_ID -> a torrent_info object, i.e. persistent data + + # Saved torrent core_states. We do not poll the core in a costly manner, necessarily + self.saved_core_torrent_states = {} # unique_ID -> torrent_state + + # supplementary torrent states + self.supp_torrent_states = {} # unique_ID->dict of data + + # Saved torrent core_states. We do not poll the core in a costly manner, necessarily + self.saved_core_torrent_peer_infos = {} # unique_ID -> torrent_state + + # Saved torrent core_states. We do not poll the core in a costly manner, necessarily + self.saved_core_torrent_file_infos = {} # unique_ID -> torrent_state + + # Keeps track of DHT running state + self.dht_running = False + + # Load the preferences + self.config = pref.Preferences(os.path.join(self.base_dir, PREFS_FILENAME)) + + # Apply preferences. Note that this is before any torrents are added + self.apply_prefs() + + PREF_FUNCTIONS["enable_dht"] = self.set_DHT + + # Unpickle the state, or create a new one + if not blank_slate: + try: + pkl_file = open(os.path.join(self.base_dir, STATE_FILENAME), 'rb') + self.state = pickle.load(pkl_file) + pkl_file.close() + + # Sync with the core: tell core about torrents, and get unique_IDs + self.sync() + + # Apply all the file filters, right after adding the torrents + self.apply_all_file_filters() + + # Apply the queue at this time, after all is loaded and ready + self.apply_queue() + except IOError: + self.state = persistent_state() + else: + self.state = persistent_state() + + + + def quit(self): + # Analyze data needed for pickling, etc. + self.pre_quitting() + + # Pickle the prefs + print "Saving prefs..." + self.config.save() + + # Pickle the state + print "Pickling state..." + output = open(os.path.join(self.base_dir, STATE_FILENAME), 'wb') + pickle.dump(self.state, output) + output.close() + + # Stop DHT, if needed + self.set_DHT(False) + + # Save fastresume data + print "Saving fastresume data..." + self.save_fastresume_data() + + # Shutdown torrent core + print "Quitting the core..." + deluge_core.quit() + + def pre_quitting(self): + # Save the uploaded data from this session to the existing upload memory + for unique_ID in self.unique_IDs.keys(): + self.unique_IDs[unique_ID].uploaded_memory = \ + self.unique_IDs[unique_ID].uploaded_memory + \ + self.get_core_torrent_state(unique_ID, False)['total_upload'] # Purposefully ineffi. + + # Preference management functions + + def get_config(self): + # This returns the preference object + return self.config + + def get_pref(self, key): + # Get the value from the preferences object + return self.config.get(key) + + def set_pref(self, key, value): + # Make sure this is a valid key + if key not in pref.DEFAULT_PREFS.keys(): + raise DelugeError("Asked to change a pref that isn't valid: " + key) + + self.config.set(key, value) + + # Apply the pref, if applicable + if PREF_FUNCTIONS[key] is not None: + PREF_FUNCTIONS[key](value) + + # Torrent addition and removal functions + + def add_torrent(self, filename, save_dir, compact): + self.add_torrent_ns(filename, save_dir, compact) + return self.sync() # Syncing will create a new torrent in the core, and return it's ID + + def remove_torrent(self, unique_ID, data_also, torrent_also): + temp = self.unique_IDs[unique_ID] + temp_fileinfo = deluge_core.get_file_info(unique_ID) + + self.remove_torrent_ns(unique_ID) + self.sync() + + # Remove .torrent file if asked to do so + if torrent_also: + os.remove(temp.filename) + + # Remove data, if asked to do so + if data_also: + # Must be done AFTER the torrent is removed + # Note: can this be to the trash? + for filedata in temp_fileinfo: + filename = filedata['path'] + if filename.find(os.sep) != -1: + # This is a file inside a directory inside the torrent. We can delete the + # directory itself, save time + try: + shutil.rmtree(os.path.dirname(os.path.join(temp.save_dir, filename))) + except OSError: # Perhaps it wasn't downloaded + pass + # Perhaps this is just a file, try to remove it + try: + os.remove(os.path.join(temp.save_dir, filename)) + except OSError: + pass # No file just means it wasn't downloaded, we can continue + + # A function to try and reload a torrent from a previous session. This is + # used in the event that Deluge crashes and a blank state is loaded. + def add_old_torrent(self, filename, save_dir, compact): + if not filename in os.listdir(os.path.join(self.base_dir, TORRENTS_SUBDIR)): + raise InvalidTorrentError(_("File was not found") + ": " + filename) + + full_new_name = os.path.join(self.base_dir, TORRENTS_SUBDIR, filename) + + # Create torrent object + new_torrent = torrent_info(full_new_name, save_dir, compact) + self.state.torrents.append(new_torrent) + + return self.sync() + + # A separate function, because people may want to call it from time to time + def save_fastresume_data(self, uid=None): + if uid == None: + for unique_ID in self.unique_IDs: + deluge_core.save_fastresume(unique_ID, self.unique_IDs[unique_ID].filename) + else: + deluge_core.save_fastresume(uid, self.unique_IDs[uid].filename) + + # Load all NEW torrents in a directory. The GUI can call this every minute or so, + # if one wants a directory to be 'watched' (personally, I think it should only be + # done on user command).os.path.join( + def autoload_directory(self, directory, save_dir, compact): + for filename in os.listdir(directory): + if filename[-len(".torrent"):].lower() == ".torrent": + try: + self.add_torrent_ns(self, filename, save_dir, compact) + except DuplicateTorrentError: + pass + + self.sync() + + # State retrieval functions + + def get_state(self): + ret = deluge_core.get_session_info() + + # Get additional data from our level + ret['is_listening'] = deluge_core.is_listening() + ret['port'] = deluge_core.listening_port() + if self.dht_running == True: + ret['DHT_nodes'] = deluge_core.get_DHT_info() + + return ret + + # This is the EXTERNAL function, for the GUI. It returns the core_state + supp_state + def get_torrent_state(self, unique_ID): + # Check to see if unique_ID exists: + if self.state.queue.count(unique_ID) == 0: + raise InvalidUniqueIDError("Asked for a torrent that doesn't exist") + + ret = self.get_core_torrent_state(unique_ID, True).copy() + + # Add the deluge-level things to the deluge_core data + if self.get_supp_torrent_state(unique_ID) is not None: + ret.update(self.get_supp_torrent_state(unique_ID)) + + # Get queue position + ret['queue_pos'] = self.state.queue.index(unique_ID) + + return ret + + def get_torrent_peer_info(self, unique_ID): + # Perhaps at some time we may add info here + return self.get_core_torrent_peer_info(unique_ID) + + def get_torrent_file_info(self, unique_ID): + return self.get_core_torrent_file_info(unique_ID) + + # Queueing functions + + def queue_top(self, unique_ID, enforce_queue=True): + self.state.queue.insert(0,self.state.queue.pop(self.get_queue_index(unique_ID))) + + def queue_up(self, unique_ID, enforce_queue=True): + curr_index = self.get_queue_index(unique_ID) + if curr_index > 0: + temp = self.state.queue[curr_index - 1] + self.state.queue[curr_index - 1] = unique_ID + self.state.queue[curr_index] = temp + if enforce_queue: + self.apply_queue() + + def queue_down(self, unique_ID, enforce_queue=True): + curr_index = self.get_queue_index(unique_ID) + if curr_index < (len(self.state.queue) - 1): + temp = self.state.queue[curr_index + 1] + self.state.queue[curr_index + 1] = unique_ID + self.state.queue[curr_index] = temp + if enforce_queue: + self.apply_queue() + + def queue_bottom(self, unique_ID, enforce_queue=True): + curr_index = self.get_queue_index(unique_ID) + if curr_index < (len(self.state.queue) - 1): + self.state.queue.remove(unique_ID) + self.state.queue.append(unique_ID) + if enforce_queue: + self.apply_queue() + + def clear_completed(self): + for unique_ID in self.unique_IDs: + torrent_state = self.get_core_torrent_state(unique_ID) + if torrent_state['progress'] == 1.0: + self.remove_torrent_ns(unique_ID) + + self.sync() + self.apply_queue() + + # Enforce the queue: pause/unpause as needed, based on queue and user_pausing + # This should be called after changes to relevant parameters (user_pausing, or + # altering max_active_torrents), or just from time to time + # ___ALL queuing code should be in this function, and ONLY here___ + def apply_queue(self, efficient = True): + # Handle autoseeding - downqueue as needed + if self.get_pref('auto_seed_ratio') > 0 and self.get_pref('auto_end_seeding'): + for unique_ID in self.unique_IDs: + if self.get_core_torrent_state(unique_ID, efficient)['is_seed']: + torrent_state = self.get_core_torrent_state(unique_ID, efficient) + ratio = self.calc_ratio(unique_ID, torrent_state) + if ratio >= self.get_pref('auto_seed_ratio'): + self.queue_bottom(unique_ID, enforce_queue=False) # don't recurse! + self.set_user_pause(unique_ID, True, enforce_queue=False) + + # Pause and resume torrents + for index in range(len(self.state.queue)): + unique_ID = self.state.queue[index] + if (index < self.get_pref('max_active_torrents') or self.get_pref('max_active_torrents') == -1) \ + and self.get_core_torrent_state(unique_ID, efficient)['is_paused'] \ + and not self.is_user_paused(unique_ID): + + # This torrent is a seed so skip all the free space checking + if self.get_core_torrent_state(unique_ID, efficient)['is_seed']: + deluge_core.resume(unique_ID) + continue + + # Before we resume, we should check if the torrent is using Full Allocation + # and if there is enough space on to finish this file. + if self.unique_IDs[unique_ID].compact == False: + torrent_state = self.get_core_torrent_state(unique_ID, efficient) + avail = self.calc_free_space(self.unique_IDs[unique_ID].save_dir) + total_needed = torrent_state["total_size"] - torrent_state["total_done"] + if total_needed < avail: + # We have enough free space, so lets resume this torrent + deluge_core.resume(unique_ID) + else: + print "Not enough free space to resume this torrent!" + else: #We're using compact allocation so lets just resume + deluge_core.resume(unique_ID) + + elif (not self.get_core_torrent_state(unique_ID, efficient)['is_paused']) and \ + ( (index >= self.get_pref('max_active_torrents') and \ + self.get_pref('max_active_torrents') != -1 ) or \ + self.is_user_paused(unique_ID)): + deluge_core.pause(unique_ID) + + # Event handling + + def handle_events(self): + # Handle them for the backend's purposes, but still send them up in case the client + # wants to do something - show messages, for example + def pop_event(): + try: + return deluge_core.pop_event() + except: + pass + else: + return deluge_core.pop_event() + + ret = [] + try: + event = deluge_core.pop_event() + except: + pass + else: + while event is not None: + # print "EVENT: ", event + + ret.append(event) + try: + if event['unique_ID'] not in self.unique_IDs: + event = pop_event() + continue + except KeyError: + event = pop_event() + continue + + if event['event_type'] is self.constants['EVENT_FINISHED']: + # Queue seeding torrent to bottom if needed + if self.get_pref('queue_seeds_to_bottom'): + self.queue_bottom(event['unique_ID']) + # If we are autoseeding, then we need to apply the queue + if self.get_pref('auto_seed_ratio') == -1: + self.apply_queue(efficient = False) # To work on current data + #save fast resume once torrent finshes so as to not recheck seed if client crashes + self.save_fastresume_data(event['unique_ID']) + elif event['event_type'] is self.constants['EVENT_TRACKER']: + unique_ID = event['unique_ID'] + status = event['tracker_status'] + message = event['message'] + tracker = message[message.find('"')+1:message.rfind('"')] + + self.set_supp_torrent_state_val(unique_ID, + "tracker_status", + (tracker, status)) + + old_state = self.get_supp_torrent_state(unique_ID) + try: + new = old_state['tracker_messages'] + except KeyError: + new = {} + + new[tracker] = message + + self.set_supp_torrent_state_val(unique_ID, + "tracker_messages", + new) + + event = pop_event() + + return ret + + # Filtering functions + + def set_file_filter(self, unique_ID, file_filter): + assert(len(file_filter) == self.get_core_torrent_state(unique_ID, True)['num_files']) + + self.unique_IDs[unique_ID].file_filter = file_filter[:] + + deluge_core.set_filter_out(unique_ID, file_filter) + + def get_file_filter(self, unique_ID): + try: + return self.unique_IDs[unique_ID].file_filter[:] + except AttributeError: + return None + + # Called when a session starts, to apply existing filters + def apply_all_file_filters(self): + for unique_ID in self.unique_IDs.keys(): + try: + self.set_file_filter(unique_ID, self.unique_IDs[unique_ID].file_filter) + except AttributeError: + pass + + # Advanced statistics - these may be SLOW. The client should call these only + # when needed, and perhaps only once in a long while (they are mostly just + # approximations anyhow + + def calc_availability(self, unique_ID): + return deluge_stats.calc_availability(self.get_core_torrent_peer_info(unique_ID)) + + def calc_swarm_speed(self, unique_ID): + pieces_per_sec = deluge_stats.calc_swarm_speed(self.get_core_torrent_peer_info(unique_ID)) + piece_length = self.get_core_torrent_state(unique_ID, efficiently=True) + + return pieces_per_sec * piece_length + + # Miscellaneous minor functions + + def set_user_pause(self, unique_ID, new_value, enforce_queue=True): + self.unique_IDs[unique_ID].user_paused = new_value + if enforce_queue: + self.apply_queue() + + def set_ratio(self, unique_ID, num): + deluge_core.set_ratio(unique_ID, float(num)) + + def is_user_paused(self, unique_ID): + return self.unique_IDs[unique_ID].user_paused + + def get_num_torrents(self): + return deluge_core.get_num_torrents() + + def get_unique_IDs(self): + return self.unique_IDs.keys() + + def update_tracker(self, unique_ID): + deluge_core.reannounce(unique_ID) + + + #################### + # Internal functions + #################### + + # Efficient: use a saved state, if it hasn't expired yet + def get_core_torrent_state(self, unique_ID, efficiently=True): + if unique_ID not in self.saved_core_torrent_states.keys(): + self.saved_core_torrent_states[unique_ID] = cached_data(deluge_core.get_torrent_state, + unique_ID) + + return self.saved_core_torrent_states[unique_ID].get(efficiently) + + def get_supp_torrent_state(self, unique_ID): + try: + return self.supp_torrent_states[unique_ID] + except KeyError: + return None + + def set_supp_torrent_state_val(self, unique_ID, key, val): + try: + if self.supp_torrent_states[unique_ID] is None: + self.supp_torrent_states[unique_ID] = {} + except KeyError: + self.supp_torrent_states[unique_ID] = {} + + self.supp_torrent_states[unique_ID][key] = val + + def get_core_torrent_peer_info(self, unique_ID, efficiently=True): + if unique_ID not in self.saved_core_torrent_peer_infos.keys(): + self.saved_core_torrent_peer_infos[unique_ID] = cached_data(deluge_core.get_peer_info, unique_ID) + + return self.saved_core_torrent_peer_infos[unique_ID].get(efficiently) + + def get_core_torrent_file_info(self, unique_ID, efficiently=True): + if unique_ID not in self.saved_core_torrent_file_infos.keys(): + self.saved_core_torrent_file_infos[unique_ID] = cached_data(deluge_core.get_file_info, unique_ID) + + return self.saved_core_torrent_file_infos[unique_ID].get(efficiently) + + # Functions for checking if enough space is available + + def calc_free_space(self, directory): + dir_stats = os.statvfs(directory) + block_size = dir_stats[statvfs.F_BSIZE] + avail_blocks = dir_stats[statvfs.F_BAVAIL] + return long(block_size * avail_blocks) + + # Non-syncing functions. Used when we loop over such events, and sync manually at the end + + def add_torrent_ns(self, filename, save_dir, compact): + # Cache torrent file + (temp, filename_short) = os.path.split(filename) + + # if filename_short in os.listdir(self.base_dir + "/" + TORRENTS_SUBDIR): + # raise DuplicateTorrentError("Duplicate Torrent, it appears: " + filename_short) + + full_new_name = os.path.join(self.base_dir, TORRENTS_SUBDIR, filename_short) + + try: + shutil.copy(filename, full_new_name) + except Exception, e: + if str(e).find('are the same file'): + pass + else: + raise + + # Create torrent object + new_torrent = torrent_info(full_new_name, save_dir, compact) + self.state.torrents.append(new_torrent) + + def remove_torrent_ns(self, unique_ID): + self.unique_IDs[unique_ID].delete_me = True + + + # Sync the state.torrents and unique_IDs lists with the core + # ___ALL syncing code with the core is here, and ONLY here___ + # Also all self-syncing is done here (various lists) + + ## + ## I had to make some changes here to get things to work properly + ## Some of these changes may be hack-ish, so look at them and make + ## sure nothing is wrong. + ## + def sync(self): + ret = None # We return new added unique ID(s), or None + no_space = False + + # Add torrents to core and unique_IDs + torrents_with_unique_ID = self.unique_IDs.values() + + for torrent in self.state.torrents: + if not os.path.exists(torrent.filename): + print "Missing file: %s" % torrent.filename + self.state.torrents.remove(torrent) + continue + if torrent not in torrents_with_unique_ID: +# print "Adding torrent to core:", torrent.filename, torrent.save_dir, torrent.compact + try: + unique_ID = deluge_core.add_torrent(torrent.filename, + torrent.save_dir, + torrent.compact) + except DelugeError, e: + print "Error:", e + self.state.torrents.remove(torrent) + raise e +# print "Got unique ID:", unique_ID + + ret = unique_ID + self.unique_IDs[unique_ID] = torrent + + +# print torrents_with_unique_ID + # Remove torrents from core, unique_IDs and queue + to_delete = [] + for unique_ID in self.unique_IDs.keys(): +# print torrent + if self.unique_IDs[unique_ID].delete_me: + deluge_core.remove_torrent(unique_ID) + to_delete.append(unique_ID) + + for unique_ID in to_delete: + self.state.torrents.remove(self.unique_IDs[unique_ID]) + self.state.queue.remove(unique_ID) + # Remove .fastresume + try: + # Must be after removal of the torrent, because that saves a new .fastresume + os.remove(self.unique_IDs[unique_ID].filename + ".fastresume") + except OSError: + pass # Perhaps there never was one to begin with + del self.unique_IDs[unique_ID] + + # Add torrents to queue - at the end, of course + for unique_ID in self.unique_IDs.keys(): + if unique_ID not in self.state.queue: + self.state.queue.append(unique_ID) # run through queue, remove those that no longer exists - to_delete = [] - for queue_item in self.state.queue: - if queue_item not in self.unique_IDs.keys(): - to_delete.append(queue_item) - for del_item in to_delete: - self.state.queue.remove(del_item) + to_delete = [] + for queue_item in self.state.queue: + if queue_item not in self.unique_IDs.keys(): + to_delete.append(queue_item) + for del_item in to_delete: + self.state.queue.remove(del_item) - assert(len(self.unique_IDs) == len(self.state.torrents)) + assert(len(self.unique_IDs) == len(self.state.torrents)) - assert(len(self.unique_IDs) == len(self.state.queue)) - assert(len(self.unique_IDs) == deluge_core.get_num_torrents()) - - #if no_space: - #self.apply_queue() - # Pickle the state so if we experience a crash, the latest state is available - print "Pickling state..." - output = open(os.path.join(self.base_dir, STATE_FILENAME), 'wb') - pickle.dump(self.state, output) - output.close() + assert(len(self.unique_IDs) == len(self.state.queue)) + assert(len(self.unique_IDs) == deluge_core.get_num_torrents()) + + #if no_space: + #self.apply_queue() + # Pickle the state so if we experience a crash, the latest state is available + print "Pickling state..." + output = open(os.path.join(self.base_dir, STATE_FILENAME), 'wb') + pickle.dump(self.state, output) + output.close() - return ret + return ret - def get_queue_index(self, unique_ID): - return self.state.queue.index(unique_ID) + def get_queue_index(self, unique_ID): + return self.state.queue.index(unique_ID) - def apply_prefs(self): - print "Applying preferences" + def apply_prefs(self): + print "Applying preferences" - for pref in PREF_FUNCTIONS.keys(): - if PREF_FUNCTIONS[pref] is not None: - PREF_FUNCTIONS[pref](self.get_pref(pref)) + for pref in PREF_FUNCTIONS.keys(): + if PREF_FUNCTIONS[pref] is not None: + PREF_FUNCTIONS[pref](self.get_pref(pref)) - def set_DHT(self, start=False): - if start == True and self.dht_running != True: - print "Starting DHT..." - deluge_core.start_DHT(os.path.join(self.base_dir, DHT_FILENAME)) - self.dht_running = True - elif start == False and self.dht_running == True: - print "Stopping DHT..." - deluge_core.stop_DHT(os.path.join(self.base_dir, DHT_FILENAME)) - self.dht_running = False + def set_DHT(self, start=False): + if start == True and self.dht_running != True: + print "Starting DHT..." + deluge_core.start_DHT(os.path.join(self.base_dir, DHT_FILENAME)) + self.dht_running = True + elif start == False and self.dht_running == True: + print "Stopping DHT..." + deluge_core.stop_DHT(os.path.join(self.base_dir, DHT_FILENAME)) + self.dht_running = False - # Calculations + # Calculations - def calc_ratio(self, unique_ID, torrent_state): - up = float((torrent_state['total_payload_upload'] / 1024) + (self.unique_IDs[unique_ID].uploaded_memory / 1024)) - down = float(torrent_state["total_done"] / 1024) - - try: - ret = float(up/down) - except: - ret = 0 + def calc_ratio(self, unique_ID, torrent_state): + up = float((torrent_state['total_payload_upload'] / 1024) + (self.unique_IDs[unique_ID].uploaded_memory / 1024)) + down = float(torrent_state["total_done"] / 1024) + try: + ret = float(up/down) + except: + ret = 0 + return ret + - return ret - + def create_torrent(self, filename, source_directory, trackers, comments=None, + piece_size=32, author="Deluge"): + return deluge_core.create_torrent(filename, source_directory, trackers, comments, piece_size, author) - def create_torrent(self, filename, source_directory, trackers, comments=None, - piece_size=32, author="Deluge"): - return deluge_core.create_torrent(filename, source_directory, trackers, comments, piece_size, author) + # Creates/resets the IP filter list + def reset_ip_filter(self): + return deluge_core.reset_IP_filter() - # Creates/resets the IP filter list - def reset_ip_filter(self): - return deluge_core.reset_IP_filter() + # Adds an IP range (as two dotted quad strings) to the filter + def add_range_to_ip_filter(self, start, end): + return deluge_core.add_range_to_IP_filter(start, end) - # Adds an IP range (as two dotted quad strings) to the filter - def add_range_to_ip_filter(self, start, end): - return deluge_core.add_range_to_IP_filter(start, end) + def proxy_settings(self, server, login, paswd, portnum, proxytype, peerproxy, trackerproxy, dhtproxy): + if self.dht_running == False: + dhtproxy = False + return deluge_core.proxy_settings(server, login, paswd, portnum, proxytype, peerproxy, trackerproxy, dhtproxy) - def proxy_settings(self, server, login, paswd, portnum, proxytype, peerproxy, trackerproxy, dhtproxy): - if self.dht_running == False: - dhtproxy = False - return deluge_core.proxy_settings(server, login, paswd, portnum, proxytype, peerproxy, trackerproxy, dhtproxy) + def pe_settings(self, out_enc_policy, in_enc_policy, allowed_enc_level, prefer_rc4): + return deluge_core.pe_settings(out_enc_policy, in_enc_policy, allowed_enc_level, prefer_rc4) - def pe_settings(self, out_enc_policy, in_enc_policy, allowed_enc_level, prefer_rc4): - return deluge_core.pe_settings(out_enc_policy, in_enc_policy, allowed_enc_level, prefer_rc4) + def get_trackers(self, unique_ID): + return deluge_core.get_trackers(unique_ID) - def get_trackers(self, unique_ID): - return deluge_core.get_trackers(unique_ID) - - def replace_trackers(self, unique_ID, trackers): - return deluge_core.replace_trackers(unique_ID, trackers) + def replace_trackers(self, unique_ID, trackers): + return deluge_core.replace_trackers(unique_ID, trackers) diff --git a/src/deluge_core.cpp b/src/deluge_core.cpp index c65eb7691..fcee72e07 100644 --- a/src/deluge_core.cpp +++ b/src/deluge_core.cpp @@ -113,8 +113,8 @@ typedef torrents_t::iterator torrents_t_iterator; long M_unique_counter = 0; session_settings *M_settings = NULL; -pe_settings *M_pe_settings = NULL; -proxy_settings *M_proxy_settings = NULL; +pe_settings *M_pe_settings = NULL; +proxy_settings *M_proxy_settings = NULL; session *M_ses = NULL; PyObject *M_constants = NULL; ip_filter *M_the_filter = NULL; @@ -158,7 +158,7 @@ long get_torrent_index(torrent_handle &handle) for (unsigned long i = 0; i < M_torrents->size(); i++) if ((*M_torrents)[i].handle == handle) { - // printf("Found: %li\r\n", i); + // printf("Found: %li\r\n", i); return i; } @@ -210,7 +210,7 @@ boost::filesystem::path const& save_path) torrent_t new_torrent; torrent_handle h = M_ses->add_torrent(t, save_path, resume_data, compact_mode, 16 * 1024); - // h.set_max_connections(60); // at some point we should use this + // h.set_max_connections(60); // at some point we should use this h.set_max_uploads(-1); h.set_ratio(preferred_ratio); new_torrent.handle = h; @@ -436,7 +436,7 @@ static PyObject *torrent_set_download_rate_limit(PyObject *self, PyObject *args) if (!PyArg_ParseTuple(args, "i", &arg)) return NULL; - // printf("Capping download to %d bytes per second\r\n", (int)arg); + // printf("Capping download to %d bytes per second\r\n", (int)arg); M_ses->set_download_rate_limit(arg); Py_INCREF(Py_None); return Py_None; @@ -449,7 +449,7 @@ static PyObject *torrent_set_upload_rate_limit(PyObject *self, PyObject *args) if (!PyArg_ParseTuple(args, "i", &arg)) return NULL; - // printf("Capping upload to %d bytes per second\r\n", (int)arg); + // printf("Capping upload to %d bytes per second\r\n", (int)arg); M_ses->set_upload_rate_limit(arg); Py_INCREF(Py_None); return Py_None; @@ -501,7 +501,7 @@ static PyObject *torrent_set_max_connections(PyObject *self, PyObject *args) if (!PyArg_ParseTuple(args, "i", &max_conn)) return NULL; - // printf("Setting max connections: %d\r\n", max_conn); + // printf("Setting max connections: %d\r\n", max_conn); M_ses->set_max_connections(max_conn); Py_INCREF(Py_None); return Py_None; @@ -629,14 +629,14 @@ static PyObject *torrent_get_torrent_state(PyObject *self, PyObject *args) for (unsigned long i = 0; i < peers.size(); i++) { - connected_peers = s.num_peers - s.num_seeds; + connected_peers = s.num_peers - s.num_seeds; - connected_seeds = s.num_seeds; + connected_seeds = s.num_seeds; - total_seeds = s.num_complete != -1? s.num_complete : connected_seeds; - - total_peers = s.num_incomplete != -1? s.num_incomplete : connected_peers; - } + total_seeds = s.num_complete != -1? s.num_complete : connected_seeds; + + total_peers = s.num_incomplete != -1? s.num_incomplete : connected_peers; + } return Py_BuildValue("{s:s,s:i,s:i,s:l,s:l,s:f,s:f,s:f,s:L,s:L,s:b,s:s,s:s,s:f,s:L,s:L,s:l,s:i,s:i,s:L,s:L,s:i,s:l,s:l,s:b,s:b,s:L,s:L,s:L}", "name", t.handle.get_torrent_info().name().c_str(), @@ -661,11 +661,11 @@ static PyObject *torrent_get_torrent_state(PyObject *self, PyObject *args) "total_size", i.total_size(), "piece_length", i.piece_length(), "num_pieces", i.num_pieces(), - "total_peers", total_peers, - "total_seeds", total_seeds, + "total_peers", total_peers, + "total_seeds", total_seeds, "is_paused", t.handle.is_paused(), "is_seed", t.handle.is_seed(), - "total_done", s.total_done, + "total_done", s.total_done, "total_wanted", s.total_wanted, "total_wanted_done", s.total_wanted_done); }; @@ -1033,7 +1033,7 @@ static PyObject *torrent_start_DHT(PyObject *self, PyObject *args) if (!PyArg_ParseTuple(args, "s", &DHT_path)) return NULL; - // printf("Loading DHT state from %s\r\n", DHT_path); + // printf("Loading DHT state from %s\r\n", DHT_path); boost::filesystem::path tempPath(DHT_path, empty_name_check); boost::filesystem::ifstream DHT_state_file(tempPath, std::ios_base::binary); @@ -1045,10 +1045,10 @@ static PyObject *torrent_start_DHT(PyObject *self, PyObject *args) DHT_state = bdecode(std::istream_iterator(DHT_state_file), std::istream_iterator()); M_ses->start_dht(DHT_state); - // printf("DHT state recovered.\r\n"); + // printf("DHT state recovered.\r\n"); - // // Print out the state data from the FILE (not the session!) - // printf("Number of DHT peers in recovered state: %ld\r\n", count_DHT_peers(DHT_state)); + // // Print out the state data from the FILE (not the session!) + // printf("Number of DHT peers in recovered state: %ld\r\n", count_DHT_peers(DHT_state)); } catch (std::exception&) @@ -1074,7 +1074,7 @@ static PyObject *torrent_stop_DHT(PyObject *self, PyObject *args) if (!PyArg_ParseTuple(args, "s", &DHT_path)) return NULL; - // printf("Saving DHT state to %s\r\n", DHT_path); + // printf("Saving DHT state to %s\r\n", DHT_path); boost::filesystem::path tempPath = boost::filesystem::path(DHT_path, empty_name_check); @@ -1082,7 +1082,7 @@ static PyObject *torrent_stop_DHT(PyObject *self, PyObject *args) { entry DHT_state = M_ses->dht_state(); - // printf("Number of DHT peers in state, saving: %ld\r\n", count_DHT_peers(DHT_state)); + // printf("Number of DHT peers in state, saving: %ld\r\n", count_DHT_peers(DHT_state)); boost::filesystem::ofstream out(tempPath, std::ios_base::binary); out.unsetf(std::ios_base::skipws); @@ -1105,7 +1105,7 @@ static PyObject *torrent_get_DHT_info(PyObject *self, PyObject *args) return Py_BuildValue("l", python_long(count_DHT_peers(DHT_state))); /* - // DHT_state.print(cout); + // DHT_state.print(cout); entry *nodes = DHT_state.find_key("nodes"); if (!nodes) return Py_BuildValue("l", -1); // No nodes - we are just starting up... @@ -1190,8 +1190,8 @@ static PyObject *torrent_create_torrent(PyObject *self, PyObject *args) return Py_BuildValue("l", 1); } catch (std::exception& e) { - // std::cerr << e.what() << "\n"; - // return Py_BuildValue("l", 0); + // std::cerr << e.what() << "\n"; + // return Py_BuildValue("l", 0); RAISE_PTR(DelugeError, e.what()); return Py_BuildValue("l", 0); } @@ -1231,15 +1231,15 @@ static PyObject *torrent_add_range_to_IP_filter(PyObject *self, PyObject *args) static PyObject *torrent_use_upnp(PyObject *self, PyObject *args) { - python_long action; - PyArg_ParseTuple(args, "i", &action); + python_long action; + PyArg_ParseTuple(args, "i", &action); - if (action){ - M_ses->start_upnp(); - } - else{ - M_ses->stop_upnp(); - } + if (action){ + M_ses->start_upnp(); + } + else{ + M_ses->stop_upnp(); + } Py_INCREF(Py_None); return Py_None; @@ -1247,49 +1247,49 @@ static PyObject *torrent_use_upnp(PyObject *self, PyObject *args) static PyObject *torrent_use_natpmp(PyObject *self, PyObject *args) { - python_long action; + python_long action; - PyArg_ParseTuple(args, "i", &action); + PyArg_ParseTuple(args, "i", &action); - if (action){ - M_ses->start_natpmp(); - } - else{ - M_ses->stop_natpmp(); - } + if (action){ + M_ses->start_natpmp(); + } + else{ + M_ses->stop_natpmp(); + } Py_INCREF(Py_None); return Py_None; } static PyObject *torrent_use_utpex(PyObject *self, PyObject *args) { - python_long action; + python_long action; - PyArg_ParseTuple(args, "i", &action); + PyArg_ParseTuple(args, "i", &action); - if (action){ - M_ses->add_extension(&libtorrent::create_ut_pex_plugin); - } + if (action){ + M_ses->add_extension(&libtorrent::create_ut_pex_plugin); + } Py_INCREF(Py_None); return Py_None; } static PyObject *torrent_pe_settings(PyObject *self, PyObject *args) { - M_pe_settings = new pe_settings(); - libtorrent::pe_settings::enc_policy out, in, prefer; - libtorrent::pe_settings::enc_level level; - - PyArg_ParseTuple(args, "iiii", &out, &in, &level, &prefer); - - M_pe_settings->out_enc_policy = out; - M_pe_settings->in_enc_policy = in; - M_pe_settings->allowed_enc_level = level; - M_pe_settings->prefer_rc4 = prefer; + M_pe_settings = new pe_settings(); + libtorrent::pe_settings::enc_policy out, in, prefer; + libtorrent::pe_settings::enc_level level; + + PyArg_ParseTuple(args, "iiii", &out, &in, &level, &prefer); + + M_pe_settings->out_enc_policy = out; + M_pe_settings->in_enc_policy = in; + M_pe_settings->allowed_enc_level = level; + M_pe_settings->prefer_rc4 = prefer; - M_ses->set_pe_settings(*M_pe_settings); - - return Py_None; + M_ses->set_pe_settings(*M_pe_settings); + + return Py_None; } static PyObject *torrent_set_ratio(PyObject *self, PyObject *args) @@ -1310,57 +1310,57 @@ static PyObject *torrent_set_ratio(PyObject *self, PyObject *args) static PyObject *torrent_proxy_settings(PyObject *self, PyObject *args) { - M_proxy_settings = new proxy_settings(); + M_proxy_settings = new proxy_settings(); - char *server, *login, *pasw; - int portnum; - libtorrent::proxy_settings::proxy_type proxytype; - bool peerproxy, trackerproxy, dhtproxy; + char *server, *login, *pasw; + int portnum; + libtorrent::proxy_settings::proxy_type proxytype; + bool peerproxy, trackerproxy, dhtproxy; - PyArg_ParseTuple(args, "sssiibbb", &server, &login, &pasw, &portnum, &proxytype, &peerproxy, &trackerproxy, &dhtproxy); + PyArg_ParseTuple(args, "sssiibbb", &server, &login, &pasw, &portnum, &proxytype, &peerproxy, &trackerproxy, &dhtproxy); - M_proxy_settings->type = proxytype; - M_proxy_settings->username = login; - M_proxy_settings->password = pasw; - M_proxy_settings->hostname = server; - M_proxy_settings->port = portnum; - - if (peerproxy) { - M_ses->set_peer_proxy(*M_proxy_settings); - } + M_proxy_settings->type = proxytype; + M_proxy_settings->username = login; + M_proxy_settings->password = pasw; + M_proxy_settings->hostname = server; + M_proxy_settings->port = portnum; + + if (peerproxy) { + M_ses->set_peer_proxy(*M_proxy_settings); + } - if (trackerproxy) { - M_ses->set_tracker_proxy(*M_proxy_settings); - } + if (trackerproxy) { + M_ses->set_tracker_proxy(*M_proxy_settings); + } - if (dhtproxy) { - M_ses->set_dht_proxy(*M_proxy_settings); - } + if (dhtproxy) { + M_ses->set_dht_proxy(*M_proxy_settings); + } - return Py_None; + return Py_None; } static PyObject *torrent_get_trackers(PyObject *self, PyObject *args) { - python_long unique_ID; - if (!PyArg_ParseTuple(args, "i", &unique_ID)) - return NULL; + python_long unique_ID; + if (!PyArg_ParseTuple(args, "i", &unique_ID)) + return NULL; - long index = get_index_from_unique_ID(unique_ID); - if (PyErr_Occurred()) - return NULL; + long index = get_index_from_unique_ID(unique_ID); + if (PyErr_Occurred()) + return NULL; - torrent_handle& h = M_torrents->at(index).handle; - std::string trackerslist; - if (h.is_valid() && h.has_metadata()) - { - for (std::vector::const_iterator i = h.trackers().begin(); - i != h.trackers().end(); ++i) - { - trackerslist = trackerslist + i->url +"\n"; - } - } - return Py_BuildValue("s",trackerslist.c_str()); + torrent_handle& h = M_torrents->at(index).handle; + std::string trackerslist; + if (h.is_valid() && h.has_metadata()) + { + for (std::vector::const_iterator i = h.trackers().begin(); + i != h.trackers().end(); ++i) + { + trackerslist = trackerslist + i->url +"\n"; + } + } + return Py_BuildValue("s",trackerslist.c_str()); } static PyObject *torrent_replace_trackers(PyObject *self, PyObject *args) @@ -1376,10 +1376,10 @@ static PyObject *torrent_replace_trackers(PyObject *self, PyObject *args) torrent_handle& h = M_torrents->at(index).handle; std::vector trackerlist; - + std::istringstream trackers(tracker); std::string line; - + while (std::getline(trackers, line)) { libtorrent::announce_entry a_entry(line); trackerlist.push_back(a_entry); diff --git a/src/deluge_stats.py b/src/deluge_stats.py index f9b356cb8..3bdd176e4 100644 --- a/src/deluge_stats.py +++ b/src/deluge_stats.py @@ -13,9 +13,9 @@ # # You should have received a copy of the GNU General Public License # along with this program. If not, write to: -# The Free Software Foundation, Inc., -# 51 Franklin Street, Fifth Floor -# Boston, MA 02110-1301, USA. +# The Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor +# Boston, MA 02110-1301, USA. # # In addition, as a special exception, the copyright holders give # permission to link the code of portions of this program with the OpenSSL @@ -36,54 +36,54 @@ old_peer_info_timestamp = None # Availability - how many complete copies are among our peers def calc_availability(peer_info): - if len(peer_info) == 0: - return 0 + if len(peer_info) == 0: + return 0 - num_pieces = len(peer_info[0].pieces) + num_pieces = len(peer_info[0].pieces) - freqs = [0]*num_pieces + freqs = [0]*num_pieces - for peer in peer_info: - for piece in num_pieces: - freqs[piece] = freqs[piece] + peer['pieces'][piece] + for peer in peer_info: + for piece in num_pieces: + freqs[piece] = freqs[piece] + peer['pieces'][piece] - minimum = min(freqs) -# frac = freqs.count(minimum + 1) # Does this mean something? + minimum = min(freqs) +# frac = freqs.count(minimum + 1) # Does this mean something? - return minimum + return minimum # Swarm speed - try to guess the speed of the entire swarm # We return #pieces / second. The calling function should convert pieces to KB, if it wants # Note that we return the delta from the last call. If the client calls too soon, this may # be too unreliable. But the client can smooth things out, if desired def calc_swarm_speed(peer_info): - if old_peer_info is not None: - new_pieces = 0 - peers_known = 0 + if old_peer_info is not None: + new_pieces = 0 + peers_known = 0 - # List new peers - new_peer_IPs = {} # ip->peerinfo dict (from the core) - for peer in peer_info: - new_peer_IPs[peer['ip']] = peer + # List new peers + new_peer_IPs = {} # ip->peerinfo dict (from the core) + for peer in peer_info: + new_peer_IPs[peer['ip']] = peer - for new_IP in new_peer_IPs.keys(): - if new_IP in old_peer_IPs.keys(): - # We know this peer from before, see what changed - peers_known = peers_known + 1 - delta = sum(new_peer_IPs[new_IP].pieces) - sum(old_peer_IPs[new_IP].pieces) + for new_IP in new_peer_IPs.keys(): + if new_IP in old_peer_IPs.keys(): + # We know this peer from before, see what changed + peers_known = peers_known + 1 + delta = sum(new_peer_IPs[new_IP].pieces) - sum(old_peer_IPs[new_IP].pieces) - if delta >= 0: - new_pieces = new_pieces + delta - else: - print "Deluge.stat.calc_swarm_speed: Bad Delta: ", delta, old_peer_IPs[new_IP].pieces, new_peer_IPs[new_IP].pieces + if delta >= 0: + new_pieces = new_pieces + delta + else: + print "Deluge.stat.calc_swarm_speed: Bad Delta: ", delta, old_peer_IPs[new_IP].pieces, new_peer_IPs[new_IP].pieces - # Calculate final value - time_delta = time.time() - old_peer_info_timestamp - ret = float(new_pieces)/( float(peers_known) * time_delta ) + # Calculate final value + time_delta = time.time() - old_peer_info_timestamp + ret = float(new_pieces)/( float(peers_known) * time_delta ) - # Save info - old_peer_info = peer_info - old_peer_info_timestamp = time.time() - old_peer_IPs = new_peer_IPs + # Save info + old_peer_info = peer_info + old_peer_info_timestamp = time.time() + old_peer_IPs = new_peer_IPs - return ret + return ret diff --git a/src/dgtk.py b/src/dgtk.py index df4762212..4344c78c8 100644 --- a/src/dgtk.py +++ b/src/dgtk.py @@ -14,9 +14,9 @@ # # You should have received a copy of the GNU General Public License # along with this program. If not, write to: -# The Free Software Foundation, Inc., -# 51 Franklin Street, Fifth Floor -# Boston, MA 02110-1301, USA. +# The Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor +# Boston, MA 02110-1301, USA. # # In addition, as a special exception, the copyright holders give # permission to link the code of portions of this program with the OpenSSL @@ -40,96 +40,96 @@ import gtk.glade # This is a dummy tray object to allow Deluge to run on PyGTK < 2.9 class StupidTray: - def __init__(self): - pass - def set_visible(self, value): - pass - def set_tooltip(self, value): - pass + def __init__(self): + pass + def set_visible(self, value): + pass + def set_tooltip(self, value): + pass ## Cell data functions to pass to add_func_column() def cell_data_speed(column, cell, model, iter, data): - speed = int(model.get_value(iter, data)) - speed_str = common.fspeed(speed) - cell.set_property('text', speed_str) + speed = int(model.get_value(iter, data)) + speed_str = common.fspeed(speed) + cell.set_property('text', speed_str) ## Functions to create columns def add_func_column(view, header, func, data, sortid=None): - column = gtk.TreeViewColumn(header) - render = gtk.CellRendererText() - column.pack_start(render, True) - column.set_cell_data_func(render, func, data) - if sortid is not None: - column.set_clickable(True) - column.set_sort_column_id(sortid) - else: - try: - if len(data) == 1: - column.set_clickable(True) - column.set_sort_column_id(data[0]) - except TypeError: - column.set_clickable(True) - column.set_sort_column_id(data) - column.set_resizable(True) - column.set_expand(False) - column.set_min_width(10) - column.set_reorderable(True) - view.append_column(column) - return column - + column = gtk.TreeViewColumn(header) + render = gtk.CellRendererText() + column.pack_start(render, True) + column.set_cell_data_func(render, func, data) + if sortid is not None: + column.set_clickable(True) + column.set_sort_column_id(sortid) + else: + try: + if len(data) == 1: + column.set_clickable(True) + column.set_sort_column_id(data[0]) + except TypeError: + column.set_clickable(True) + column.set_sort_column_id(data) + column.set_resizable(True) + column.set_expand(False) + column.set_min_width(10) + column.set_reorderable(True) + view.append_column(column) + return column + def add_text_column(view, header, cid): - render = gtk.CellRendererText() - column = gtk.TreeViewColumn(header, render, text=cid) - column.set_clickable(True) - column.set_sort_column_id(cid) - column.set_resizable(True) - column.set_expand(False) - column.set_min_width(10) - column.set_reorderable(True) - view.append_column(column) - return column + render = gtk.CellRendererText() + column = gtk.TreeViewColumn(header, render, text=cid) + column.set_clickable(True) + column.set_sort_column_id(cid) + column.set_resizable(True) + column.set_expand(False) + column.set_min_width(10) + column.set_reorderable(True) + view.append_column(column) + return column def add_progress_column(view, header, pid, mid): - render = gtk.CellRendererProgress() - column = gtk.TreeViewColumn(header, render, value=pid, text=mid) - column.set_clickable(True) - column.set_sort_column_id(pid) - column.set_resizable(True) - column.set_expand(False) - column.set_min_width(10) - column.set_reorderable(True) - view.append_column(column) - return column + render = gtk.CellRendererProgress() + column = gtk.TreeViewColumn(header, render, value=pid, text=mid) + column.set_clickable(True) + column.set_sort_column_id(pid) + column.set_resizable(True) + column.set_expand(False) + column.set_min_width(10) + column.set_reorderable(True) + view.append_column(column) + return column def add_toggle_column(view, header, cid, toggled_signal=None): - render = gtk.CellRendererToggle() - render.set_property('activatable', True) - column = gtk.TreeViewColumn(header, render, active=cid) - column.set_clickable(True) - column.set_resizable(True) - column.set_expand(False) - column.set_min_width(10) - column.set_reorderable(True) - view.append_column(column) - if toggled_signal is not None: - render.connect("toggled", toggled_signal) - return column + render = gtk.CellRendererToggle() + render.set_property('activatable', True) + column = gtk.TreeViewColumn(header, render, active=cid) + column.set_clickable(True) + column.set_resizable(True) + column.set_expand(False) + column.set_min_width(10) + column.set_reorderable(True) + view.append_column(column) + if toggled_signal is not None: + render.connect("toggled", toggled_signal) + return column def add_texticon_column(view, header, icon_col, text_col): - column = gtk.TreeViewColumn(header) - column.set_clickable(True) - column.set_resizable(True) - column.set_expand(False) - column.set_min_width(10) - column.set_reorderable(True) - render = gtk.CellRendererPixbuf() - column.pack_start(render, expand=False) - column.add_attribute(render, 'pixbuf', icon_col) - render = gtk.CellRendererText() - column.pack_start(render, expand=True) - column.add_attribute(render, 'text', text_col) - view.append_column(column) - return column + column = gtk.TreeViewColumn(header) + column.set_clickable(True) + column.set_resizable(True) + column.set_expand(False) + column.set_min_width(10) + column.set_reorderable(True) + render = gtk.CellRendererPixbuf() + column.pack_start(render, expand=False) + column.add_attribute(render, 'pixbuf', icon_col) + render = gtk.CellRendererText() + column.pack_start(render, expand=True) + column.add_attribute(render, 'text', text_col) + view.append_column(column) + return column diff --git a/src/dialogs.py b/src/dialogs.py index d62e37c7c..779aeb6f4 100644 --- a/src/dialogs.py +++ b/src/dialogs.py @@ -14,9 +14,9 @@ # # You should have received a copy of the GNU General Public License # along with this program. If not, write to: -# The Free Software Foundation, Inc., -# 51 Franklin Street, Fifth Floor -# Boston, MA 02110-1301, USA. +# The Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor +# Boston, MA 02110-1301, USA. # # In addition, as a special exception, the copyright holders give # permission to link the code of portions of this program with the OpenSSL @@ -28,285 +28,289 @@ # this exception statement from your version. If you delete this exception # statement from all source files in the program, then also delete it here. -import common, dgtk, pref -import gtk, gtk.glade -import os, os.path +import common +import dgtk +import pref +import gtk +import gtk.glade +import os +import os.path PREFS_FILENAME = "prefs.state" class PreferencesDlg: - def __init__(self, parent, preferences): - self.glade = gtk.glade.XML(common.get_glade_file("preferences_dialog.glade"), domain='deluge') - self.dialog = self.glade.get_widget("pref_dialog") - self.dialog.set_icon_from_file(common.get_pixmap("deluge32.png")) - self.glade.signal_autoconnect({ - 'on_chk_use_tray_toggled': self.tray_toggle, - 'on_btn_testport_clicked': self.TestPort, - }) - self.parent = parent - self.preferences = preferences - - def show(self): - # Load settings into dialog - try: - self.glade.get_widget("combo_encin").set_active(self.preferences.get("encin_state")) - self.glade.get_widget("combo_encout").set_active(self.preferences.get("encout_state")) - self.glade.get_widget("combo_enclevel").set_active(self.preferences.get("enclevel_type")) - self.glade.get_widget("combo_proxy_type").set_active(self.preferences.get("proxy_type")) - self.glade.get_widget("chk_pref_rc4").set_active(self.preferences.get("pref_rc4")) - self.glade.get_widget("chk_peer_proxy").set_active(self.preferences.get("peer_proxy")) - self.glade.get_widget("chk_tracker_proxy").set_active(self.preferences.get("tracker_proxy")) - self.glade.get_widget("chk_dht_proxy").set_active(self.preferences.get("dht_proxy")) - self.glade.get_widget("chk_upnp").set_active(self.preferences.get("use_upnp")) - self.glade.get_widget("chk_natpmp").set_active(self.preferences.get("use_natpmp")) - self.glade.get_widget("chk_utpex").set_active(self.preferences.get("use_utpex")) - self.glade.get_widget("chk_use_tray").set_active(self.preferences.get("enable_system_tray")) - self.glade.get_widget("chk_min_on_close").set_active(self.preferences.get("close_to_tray")) - self.glade.get_widget("chk_lock_tray").set_active(self.preferences.get("lock_tray")) - self.glade.get_widget("txt_tray_passwd").set_text(self.preferences.get("tray_passwd")) - self.glade.get_widget("txt_proxy_hostname").set_text(self.preferences.get("proxy_hostname")) - self.glade.get_widget("txt_proxy_username").set_text(self.preferences.get("proxy_username")) - self.glade.get_widget("txt_proxy_password").set_text(self.preferences.get("proxy_password")) - if(self.preferences.get("use_default_dir")): - self.glade.get_widget("radio_save_all_to").set_active(True) - else: - self.glade.get_widget("radio_ask_save").set_active(True) - - self.glade.get_widget("download_path_button").set_filename(self.preferences.get("default_download_path")) - self.glade.get_widget("chk_compact").set_active(self.preferences.get("use_compact_storage")) - self.glade.get_widget("active_port_label").set_text(str(self.parent.manager.get_state()['port'])) - self.glade.get_widget("spin_port_min").set_value(self.preferences.get("listen_on")[0]) - self.glade.get_widget("spin_port_max").set_value(self.preferences.get("listen_on")[1]) - self.glade.get_widget("spin_max_upload").set_value(self.preferences.get("max_upload_speed")) - self.glade.get_widget("spin_num_upload").set_value(self.preferences.get("max_number_uploads")) - self.glade.get_widget("spin_max_download").set_value(self.preferences.get("max_download_speed")) - self.glade.get_widget("spin_max_connections").set_value(self.preferences.get("max_connections")) - self.glade.get_widget("spin_proxy_port").set_value(self.preferences.get("proxy_port")) - self.glade.get_widget("spin_torrents").set_value(float(self.preferences.get("max_active_torrents"))) - self.glade.get_widget("chk_seedbottom").set_active(self.preferences.get("queue_seeds_to_bottom")) - self.glade.get_widget("chk_autoseed").set_active(self.preferences.get("auto_end_seeding")) - self.glade.get_widget("ratio_spinner").set_value(self.preferences.get("auto_seed_ratio")) - self.glade.get_widget("chk_dht").set_active(self.preferences.get("enable_dht")) - self.glade.get_widget("spin_gui").set_value(self.preferences.get("gui_update_interval")) - - except KeyError: - pass - # Now, show the dialog - self.dialog.show() - r = self.dialog.run() - self.dialog.hide() - # Now, get the settings from the dialog - if r == 1: - self.preferences.set("encin_state", self.glade.get_widget("combo_encin").get_active()) - self.preferences.set("encout_state", self.glade.get_widget("combo_encout").get_active()) - self.preferences.set("enclevel_type", self.glade.get_widget("combo_enclevel").get_active()) - self.preferences.set("proxy_type", self.glade.get_widget("combo_proxy_type").get_active()) - self.preferences.set("pref_rc4", self.glade.get_widget("chk_pref_rc4").get_active()) - self.preferences.set("peer_proxy", self.glade.get_widget("chk_peer_proxy").get_active()) - self.preferences.set("tracker_proxy", self.glade.get_widget("chk_tracker_proxy").get_active()) - self.preferences.set("dht_proxy", self.glade.get_widget("chk_dht_proxy").get_active()) - self.preferences.set("use_upnp", self.glade.get_widget("chk_upnp").get_active()) - self.preferences.set("use_natpmp", self.glade.get_widget("chk_natpmp").get_active()) - self.preferences.set("use_utpex", self.glade.get_widget("chk_utpex").get_active()) - self.preferences.set("enable_system_tray", self.glade.get_widget("chk_use_tray").get_active()) - self.preferences.set("close_to_tray", self.glade.get_widget("chk_min_on_close").get_active()) - self.preferences.set("lock_tray", self.glade.get_widget("chk_lock_tray").get_active()) - self.preferences.set("tray_passwd", self.glade.get_widget("txt_tray_passwd").get_text()) - self.preferences.set("proxy_username", self.glade.get_widget("txt_proxy_username").get_text()) - self.preferences.set("proxy_password", self.glade.get_widget("txt_proxy_password").get_text()) - self.preferences.set("proxy_hostname", self.glade.get_widget("txt_proxy_hostname").get_text()) - self.preferences.set("use_default_dir", self.glade.get_widget("radio_save_all_to").get_active()) - self.preferences.set("default_download_path", self.glade.get_widget("download_path_button").get_filename()) - self.preferences.set("auto_end_seeding", self.glade.get_widget("chk_autoseed").get_active()) - self.preferences.set("auto_seed_ratio", self.glade.get_widget("ratio_spinner").get_value()) - self.preferences.set("use_compact_storage", self.glade.get_widget("chk_compact").get_active()) - self.preferences.set("listen_on", [self.glade.get_widget("spin_port_min").get_value(), self.glade.get_widget("spin_port_max").get_value()]) - self.preferences.set("max_upload_speed", self.glade.get_widget("spin_max_upload").get_value()) - self.preferences.set("max_number_uploads", self.glade.get_widget("spin_num_upload").get_value()) - self.preferences.set("max_download_speed", self.glade.get_widget("spin_max_download").get_value()) - self.preferences.set("proxy_port", self.glade.get_widget("spin_proxy_port").get_value()) - self.preferences.set("max_connections", int(self.glade.get_widget("spin_max_connections").get_value())) - self.preferences.set("max_active_torrents", int(self.glade.get_widget("spin_torrents").get_value())) - self.preferences.set("queue_seeds_to_bottom", self.glade.get_widget("chk_seedbottom").get_active()) - self.preferences.set("enable_dht", self.glade.get_widget("chk_dht").get_active()) - self.preferences.set("gui_update_interval", self.glade.get_widget("spin_gui").get_value()) + def __init__(self, parent, preferences): + self.glade = gtk.glade.XML(common.get_glade_file("preferences_dialog.glade"), domain='deluge') + self.dialog = self.glade.get_widget("pref_dialog") + self.dialog.set_icon_from_file(common.get_pixmap("deluge32.png")) + self.glade.signal_autoconnect({ + 'on_chk_use_tray_toggled': self.tray_toggle, + 'on_btn_testport_clicked': self.TestPort, + }) + self.parent = parent + self.preferences = preferences + + def show(self): + # Load settings into dialog + try: + self.glade.get_widget("combo_encin").set_active(self.preferences.get("encin_state")) + self.glade.get_widget("combo_encout").set_active(self.preferences.get("encout_state")) + self.glade.get_widget("combo_enclevel").set_active(self.preferences.get("enclevel_type")) + self.glade.get_widget("combo_proxy_type").set_active(self.preferences.get("proxy_type")) + self.glade.get_widget("chk_pref_rc4").set_active(self.preferences.get("pref_rc4")) + self.glade.get_widget("chk_peer_proxy").set_active(self.preferences.get("peer_proxy")) + self.glade.get_widget("chk_tracker_proxy").set_active(self.preferences.get("tracker_proxy")) + self.glade.get_widget("chk_dht_proxy").set_active(self.preferences.get("dht_proxy")) + self.glade.get_widget("chk_upnp").set_active(self.preferences.get("use_upnp")) + self.glade.get_widget("chk_natpmp").set_active(self.preferences.get("use_natpmp")) + self.glade.get_widget("chk_utpex").set_active(self.preferences.get("use_utpex")) + self.glade.get_widget("chk_use_tray").set_active(self.preferences.get("enable_system_tray")) + self.glade.get_widget("chk_min_on_close").set_active(self.preferences.get("close_to_tray")) + self.glade.get_widget("chk_lock_tray").set_active(self.preferences.get("lock_tray")) + self.glade.get_widget("txt_tray_passwd").set_text(self.preferences.get("tray_passwd")) + self.glade.get_widget("txt_proxy_hostname").set_text(self.preferences.get("proxy_hostname")) + self.glade.get_widget("txt_proxy_username").set_text(self.preferences.get("proxy_username")) + self.glade.get_widget("txt_proxy_password").set_text(self.preferences.get("proxy_password")) + if(self.preferences.get("use_default_dir")): + self.glade.get_widget("radio_save_all_to").set_active(True) + else: + self.glade.get_widget("radio_ask_save").set_active(True) + + self.glade.get_widget("download_path_button").set_filename(self.preferences.get("default_download_path")) + self.glade.get_widget("chk_compact").set_active(self.preferences.get("use_compact_storage")) + self.glade.get_widget("active_port_label").set_text(str(self.parent.manager.get_state()['port'])) + self.glade.get_widget("spin_port_min").set_value(self.preferences.get("listen_on")[0]) + self.glade.get_widget("spin_port_max").set_value(self.preferences.get("listen_on")[1]) + self.glade.get_widget("spin_max_upload").set_value(self.preferences.get("max_upload_speed")) + self.glade.get_widget("spin_num_upload").set_value(self.preferences.get("max_number_uploads")) + self.glade.get_widget("spin_max_download").set_value(self.preferences.get("max_download_speed")) + self.glade.get_widget("spin_max_connections").set_value(self.preferences.get("max_connections")) + self.glade.get_widget("spin_proxy_port").set_value(self.preferences.get("proxy_port")) + self.glade.get_widget("spin_torrents").set_value(float(self.preferences.get("max_active_torrents"))) + self.glade.get_widget("chk_seedbottom").set_active(self.preferences.get("queue_seeds_to_bottom")) + self.glade.get_widget("chk_autoseed").set_active(self.preferences.get("auto_end_seeding")) + self.glade.get_widget("ratio_spinner").set_value(self.preferences.get("auto_seed_ratio")) + self.glade.get_widget("chk_dht").set_active(self.preferences.get("enable_dht")) + self.glade.get_widget("spin_gui").set_value(self.preferences.get("gui_update_interval")) + + except KeyError: + pass + # Now, show the dialog + self.dialog.show() + r = self.dialog.run() + self.dialog.hide() + # Now, get the settings from the dialog + if r == 1: + self.preferences.set("encin_state", self.glade.get_widget("combo_encin").get_active()) + self.preferences.set("encout_state", self.glade.get_widget("combo_encout").get_active()) + self.preferences.set("enclevel_type", self.glade.get_widget("combo_enclevel").get_active()) + self.preferences.set("proxy_type", self.glade.get_widget("combo_proxy_type").get_active()) + self.preferences.set("pref_rc4", self.glade.get_widget("chk_pref_rc4").get_active()) + self.preferences.set("peer_proxy", self.glade.get_widget("chk_peer_proxy").get_active()) + self.preferences.set("tracker_proxy", self.glade.get_widget("chk_tracker_proxy").get_active()) + self.preferences.set("dht_proxy", self.glade.get_widget("chk_dht_proxy").get_active()) + self.preferences.set("use_upnp", self.glade.get_widget("chk_upnp").get_active()) + self.preferences.set("use_natpmp", self.glade.get_widget("chk_natpmp").get_active()) + self.preferences.set("use_utpex", self.glade.get_widget("chk_utpex").get_active()) + self.preferences.set("enable_system_tray", self.glade.get_widget("chk_use_tray").get_active()) + self.preferences.set("close_to_tray", self.glade.get_widget("chk_min_on_close").get_active()) + self.preferences.set("lock_tray", self.glade.get_widget("chk_lock_tray").get_active()) + self.preferences.set("tray_passwd", self.glade.get_widget("txt_tray_passwd").get_text()) + self.preferences.set("proxy_username", self.glade.get_widget("txt_proxy_username").get_text()) + self.preferences.set("proxy_password", self.glade.get_widget("txt_proxy_password").get_text()) + self.preferences.set("proxy_hostname", self.glade.get_widget("txt_proxy_hostname").get_text()) + self.preferences.set("use_default_dir", self.glade.get_widget("radio_save_all_to").get_active()) + self.preferences.set("default_download_path", self.glade.get_widget("download_path_button").get_filename()) + self.preferences.set("auto_end_seeding", self.glade.get_widget("chk_autoseed").get_active()) + self.preferences.set("auto_seed_ratio", self.glade.get_widget("ratio_spinner").get_value()) + self.preferences.set("use_compact_storage", self.glade.get_widget("chk_compact").get_active()) + self.preferences.set("listen_on", [self.glade.get_widget("spin_port_min").get_value(), self.glade.get_widget("spin_port_max").get_value()]) + self.preferences.set("max_upload_speed", self.glade.get_widget("spin_max_upload").get_value()) + self.preferences.set("max_number_uploads", self.glade.get_widget("spin_num_upload").get_value()) + self.preferences.set("max_download_speed", self.glade.get_widget("spin_max_download").get_value()) + self.preferences.set("proxy_port", self.glade.get_widget("spin_proxy_port").get_value()) + self.preferences.set("max_connections", int(self.glade.get_widget("spin_max_connections").get_value())) + self.preferences.set("max_active_torrents", int(self.glade.get_widget("spin_torrents").get_value())) + self.preferences.set("queue_seeds_to_bottom", self.glade.get_widget("chk_seedbottom").get_active()) + self.preferences.set("enable_dht", self.glade.get_widget("chk_dht").get_active()) + self.preferences.set("gui_update_interval", self.glade.get_widget("spin_gui").get_value()) - return r - - def TestPort(self, widget): - activep = str(self.parent.manager.get_state()['port']) - common.open_url_in_browser(self.dialog,'http://www.deluge-torrent.org/test-port.php?port=%s' %activep) + return r + + def TestPort(self, widget): + activep = str(self.parent.manager.get_state()['port']) + common.open_url_in_browser(self.dialog,'http://www.deluge-torrent.org/test-port.php?port=%s' %activep) - - def tray_toggle(self, widget): - is_active = widget.get_active() + + def tray_toggle(self, widget): + is_active = widget.get_active() - self.glade.get_widget("chk_min_on_close").set_sensitive(is_active) - self.glade.get_widget("chk_lock_tray").set_sensitive(is_active) - self.glade.get_widget("txt_tray_passwd").set_sensitive(is_active) - + self.glade.get_widget("chk_min_on_close").set_sensitive(is_active) + self.glade.get_widget("chk_lock_tray").set_sensitive(is_active) + self.glade.get_widget("txt_tray_passwd").set_sensitive(is_active) + class PluginDlg: - def __init__(self, parent, plugins): - self.glade = gtk.glade.XML(common.get_glade_file("plugin_dialog.glade"), domain='deluge') - self.dialog = self.glade.get_widget("plugin_dialog") - self.dialog.set_icon_from_file(common.get_pixmap("deluge32.png")) - self.view = self.glade.get_widget("plugin_view") - self.store = gtk.ListStore(str, bool) - self.view.set_model(self.store) - try: - self.view.get_selection().set_select_function(self.plugin_clicked, full=True) - except TypeError: - self.view.get_selection().set_select_function(self.old_clicked) - name_col = dgtk.add_text_column(self.view, _("Plugin"), 0) - name_col.set_expand(True) - dgtk.add_toggle_column(self.view, _("Enabled"), 1, toggled_signal=self.plugin_toggled) - self.glade.signal_autoconnect({'plugin_pref': self.plugin_pref}) - self.parent = parent - self.plugins = plugins - + def __init__(self, parent, plugins): + self.glade = gtk.glade.XML(common.get_glade_file("plugin_dialog.glade"), domain='deluge') + self.dialog = self.glade.get_widget("plugin_dialog") + self.dialog.set_icon_from_file(common.get_pixmap("deluge32.png")) + self.view = self.glade.get_widget("plugin_view") + self.store = gtk.ListStore(str, bool) + self.view.set_model(self.store) + try: + self.view.get_selection().set_select_function(self.plugin_clicked, full=True) + except TypeError: + self.view.get_selection().set_select_function(self.old_clicked) + name_col = dgtk.add_text_column(self.view, _("Plugin"), 0) + name_col.set_expand(True) + dgtk.add_toggle_column(self.view, _("Enabled"), 1, toggled_signal=self.plugin_toggled) + self.glade.signal_autoconnect({'plugin_pref': self.plugin_pref}) + self.parent = parent + self.plugins = plugins + - def show(self): - self.store.clear() - for plugin in self.plugins.get_available_plugins(): - #print plugin - if plugin in self.plugins.get_enabled_plugins(): - self.store.append( (plugin, True) ) - else: - self.store.append( (plugin, False) ) - self.glade.get_widget("plugin_text").get_buffer().set_text("") - self.glade.get_widget("plugin_conf").set_sensitive(False) - self.dialog.show() - self.dialog.run() - self.dialog.hide() - - def old_clicked(self, path): - return self.plugin_clicked(self.view.get_selection(), self.store, path, False) - - def plugin_clicked(self, selection, model, path, is_selected): - if is_selected: - return True - name = model.get_value(model.get_iter(path), 0) - plugin = self.plugins.get_plugin(name) - author = plugin.plugin_author - version = plugin.plugin_version - description = plugin.plugin_description - if name in self.plugins.get_enabled_plugins(): - config = self.plugins.configurable_plugin(name) - self.glade.get_widget("plugin_conf").set_sensitive(config) - else: - self.glade.get_widget("plugin_conf").set_sensitive(False) - self.glade.get_widget("plugin_text").get_buffer( - ).set_text("%s\nBy: %s\nVersion: %s\n\n%s"% - (name, author, version, description)) - return True + def show(self): + self.store.clear() + for plugin in self.plugins.get_available_plugins(): + #print plugin + if plugin in self.plugins.get_enabled_plugins(): + self.store.append( (plugin, True) ) + else: + self.store.append( (plugin, False) ) + self.glade.get_widget("plugin_text").get_buffer().set_text("") + self.glade.get_widget("plugin_conf").set_sensitive(False) + self.dialog.show() + self.dialog.run() + self.dialog.hide() + + def old_clicked(self, path): + return self.plugin_clicked(self.view.get_selection(), self.store, path, False) + + def plugin_clicked(self, selection, model, path, is_selected): + if is_selected: + return True + name = model.get_value(model.get_iter(path), 0) + plugin = self.plugins.get_plugin(name) + author = plugin.plugin_author + version = plugin.plugin_version + description = plugin.plugin_description + if name in self.plugins.get_enabled_plugins(): + config = self.plugins.configurable_plugin(name) + self.glade.get_widget("plugin_conf").set_sensitive(config) + else: + self.glade.get_widget("plugin_conf").set_sensitive(False) + self.glade.get_widget("plugin_text").get_buffer( + ).set_text("%s\nBy: %s\nVersion: %s\n\n%s"% + (name, author, version, description)) + return True - def plugin_toggled(self, renderer, path): - plugin_iter = self.store.get_iter_from_string(path) - plugin_name = self.store.get_value(plugin_iter, 0) - plugin_value = not self.store.get_value(plugin_iter, 1) - self.store.set_value(plugin_iter, 1, plugin_value) - if plugin_value: - config = self.plugins.configurable_plugin(plugin_name) - self.glade.get_widget("plugin_conf").set_sensitive(config) - self.plugins.enable_plugin(plugin_name) - else: - self.plugins.disable_plugin(plugin_name) - self.glade.get_widget("plugin_conf").set_sensitive(False) - - def plugin_pref(self, widget=None): - (model, plugin_iter) = self.view.get_selection().get_selected() - plugin_name = self.store.get_value(plugin_iter, 0) - self.plugins.configure_plugin(plugin_name) + def plugin_toggled(self, renderer, path): + plugin_iter = self.store.get_iter_from_string(path) + plugin_name = self.store.get_value(plugin_iter, 0) + plugin_value = not self.store.get_value(plugin_iter, 1) + self.store.set_value(plugin_iter, 1, plugin_value) + if plugin_value: + config = self.plugins.configurable_plugin(plugin_name) + self.glade.get_widget("plugin_conf").set_sensitive(config) + self.plugins.enable_plugin(plugin_name) + else: + self.plugins.disable_plugin(plugin_name) + self.glade.get_widget("plugin_conf").set_sensitive(False) + + def plugin_pref(self, widget=None): + (model, plugin_iter) = self.view.get_selection().get_selected() + plugin_name = self.store.get_value(plugin_iter, 0) + self.plugins.configure_plugin(plugin_name) def show_about_dialog(parent=None): - gtk.about_dialog_set_url_hook(common.open_url_in_browser) - abt = gtk.glade.XML(common.get_glade_file("aboutdialog.glade")).get_widget("aboutdialog") - abt.set_name(common.PROGRAM_NAME) - abt.set_version(common.PROGRAM_VERSION) - abt.set_authors(["Zach Tibbitts", "Alon Zakai", "Marcos Pinto", "Andrew Resch"]) - abt.set_artists(["Andrew Wedderburn"]) - abt.set_translator_credits(_("translator-credits")) - abt.set_website("http://deluge-torrent.org") - abt.set_website_label("http://deluge-torrent.org") - abt.set_icon_from_file(common.get_pixmap("deluge32.png")) - abt.set_logo(gtk.gdk.pixbuf_new_from_file( - common.get_pixmap("deluge-about.png"))) - abt.show_all() - abt.run() - abt.hide_all() + gtk.about_dialog_set_url_hook(common.open_url_in_browser) + abt = gtk.glade.XML(common.get_glade_file("aboutdialog.glade")).get_widget("aboutdialog") + abt.set_name(common.PROGRAM_NAME) + abt.set_version(common.PROGRAM_VERSION) + abt.set_authors(["Zach Tibbitts", "Alon Zakai", "Marcos Pinto", "Andrew Resch"]) + abt.set_artists(["Andrew Wedderburn"]) + abt.set_translator_credits(_("translator-credits")) + abt.set_website("http://deluge-torrent.org") + abt.set_website_label("http://deluge-torrent.org") + abt.set_icon_from_file(common.get_pixmap("deluge32.png")) + abt.set_logo(gtk.gdk.pixbuf_new_from_file( + common.get_pixmap("deluge-about.png"))) + abt.show_all() + abt.run() + abt.hide_all() def show_popup_warning(window, message): - warner = gtk.MessageDialog(parent = window, - flags = gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT, - buttons= gtk.BUTTONS_OK, - message_format=message, - type = gtk.MESSAGE_WARNING) - warner.run() - warner.destroy() + warner = gtk.MessageDialog(parent = window, + flags = gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT, + buttons= gtk.BUTTONS_OK, + message_format=message, + type = gtk.MESSAGE_WARNING) + warner.run() + warner.destroy() def show_popup_question(window, message): - asker = gtk.MessageDialog(parent = window, - flags = gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT, - buttons = gtk.BUTTONS_YES_NO, - message_format=message, - type=gtk.MESSAGE_QUESTION) - result = asker.run() - asker.destroy() - if result == gtk.RESPONSE_YES: - return True - elif result == gtk.RESPONSE_NO: - return False - elif result == gtk.RESPONSE_DELETE_EVENT: - return False - else: - return False + asker = gtk.MessageDialog(parent = window, + flags = gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT, + buttons = gtk.BUTTONS_YES_NO, + message_format=message, + type=gtk.MESSAGE_QUESTION) + result = asker.run() + asker.destroy() + if result == gtk.RESPONSE_YES: + return True + elif result == gtk.RESPONSE_NO: + return False + elif result == gtk.RESPONSE_DELETE_EVENT: + return False + else: + return False ## Browse for .torrent files def show_file_open_dialog(parent=None, title=None): - if title is None: - title = _("Choose a .torrent file") - chooser = gtk.FileChooserDialog(title, parent, gtk.FILE_CHOOSER_ACTION_OPEN, - buttons=(gtk.STOCK_CANCEL,gtk.RESPONSE_CANCEL,gtk.STOCK_OPEN,gtk.RESPONSE_OK)) - - f0 = gtk.FileFilter() - f0.set_name(_("Torrent files")) - f0.add_pattern("*." + "torrent") - chooser.add_filter(f0) - f1 = gtk.FileFilter() - f1.set_name(_("All files")) - f1.add_pattern("*") - loadpref = pref.Preferences() - chooser.set_current_folder(loadpref.get("default_load_path")) - chooser.add_filter(f1) - chooser.set_select_multiple(True) - - chooser.set_icon_from_file(common.get_pixmap("deluge32.png")) - chooser.set_property("skip-taskbar-hint", True) - - response = chooser.run() - if response == gtk.RESPONSE_OK: - result = chooser.get_filenames() - loadpref.set("default_load_path", chooser.get_current_folder()) - else: - result = None - chooser.destroy() - return result + if title is None: + title = _("Choose a .torrent file") + chooser = gtk.FileChooserDialog(title, parent, gtk.FILE_CHOOSER_ACTION_OPEN, + buttons=(gtk.STOCK_CANCEL,gtk.RESPONSE_CANCEL,gtk.STOCK_OPEN,gtk.RESPONSE_OK)) + + f0 = gtk.FileFilter() + f0.set_name(_("Torrent files")) + f0.add_pattern("*." + "torrent") + chooser.add_filter(f0) + f1 = gtk.FileFilter() + f1.set_name(_("All files")) + f1.add_pattern("*") + loadpref = pref.Preferences() + chooser.set_current_folder(loadpref.get("default_load_path")) + chooser.add_filter(f1) + chooser.set_select_multiple(True) + + chooser.set_icon_from_file(common.get_pixmap("deluge32.png")) + chooser.set_property("skip-taskbar-hint", True) + + response = chooser.run() + if response == gtk.RESPONSE_OK: + result = chooser.get_filenames() + loadpref.set("default_load_path", chooser.get_current_folder()) + else: + result = None + chooser.destroy() + return result def show_directory_chooser_dialog(parent=None, title=None): - if title is None: - title = _("Choose a download directory") - chooser = gtk.FileChooserDialog(title, parent, gtk.FILE_CHOOSER_ACTION_SELECT_FOLDER, - buttons=(gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL, gtk.STOCK_OK, gtk.RESPONSE_OK)) - chooser.set_icon_from_file(common.get_pixmap("deluge32.png")) - chooser.set_property("skip-taskbar-hint", True) - if chooser.run() == gtk.RESPONSE_OK: - result = chooser.get_filename() - else: - result = None - chooser.destroy() - return result + if title is None: + title = _("Choose a download directory") + chooser = gtk.FileChooserDialog(title, parent, gtk.FILE_CHOOSER_ACTION_SELECT_FOLDER, + buttons=(gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL, gtk.STOCK_OK, gtk.RESPONSE_OK)) + chooser.set_icon_from_file(common.get_pixmap("deluge32.png")) + chooser.set_property("skip-taskbar-hint", True) + if chooser.run() == gtk.RESPONSE_OK: + result = chooser.get_filename() + else: + result = None + chooser.destroy() + return result diff --git a/src/interface.py b/src/interface.py index 615d73794..fc51f2d4e 100644 --- a/src/interface.py +++ b/src/interface.py @@ -16,9 +16,9 @@ # # You should have received a copy of the GNU General Public License # along with this program. If not, write to: -# The Free Software Foundation, Inc., -# 51 Franklin Street, Fifth Floor -# Boston, MA 02110-1301, USA. +# The Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor +# Boston, MA 02110-1301, USA. # # In addition, as a special exception, the copyright holders give # permission to link the code of portions of this program with the OpenSSL @@ -30,1393 +30,1401 @@ # this exception statement from your version. If you delete this exception # statement from all source files in the program, then also delete it here. -import sys, os, os.path, urllib +import sys +import os +import os.path +import urllib from itertools import izip -import core, common, dgtk, ipc_manager, dialogs -import plugins, pref +import core +import common +import dgtk +import ipc_manager +import dialogs +import plugins +import pref import pygtk pygtk.require('2.0') -import gtk, gtk.glade, gobject -import xdg, xdg.BaseDirectory -import gettext, locale +import gtk +import gtk.glade +import gobject +import xdg +import xdg.BaseDirectory +import gettext +import locale class DelugeGTK: - def __init__(self): - APP = 'deluge' - DIR = os.path.join(common.INSTALL_PREFIX, 'share', 'locale') - locale.setlocale(locale.LC_ALL, '') - locale.bindtextdomain(APP, DIR) - locale.textdomain(APP) - gettext.bindtextdomain(APP, DIR) - gettext.textdomain(APP) - gettext.install(APP, DIR) - - self.is_running = False - self.update_queue = [] - self.ipc_manager = ipc_manager.Manager(self) - self.torrent_file_queue = [] - #Start the Deluge Manager: - self.manager = core.Manager(common.CLIENT_CODE, common.CLIENT_VERSION, - '%s %s'%(common.PROGRAM_NAME, common.PROGRAM_VERSION), common.CONFIG_DIR) - self.something_screwed_up = False - self.plugins = plugins.PluginManager(self.manager, self) - self.plugins.add_plugin_dir(common.PLUGIN_DIR) - if os.path.isdir(os.path.join(common.CONFIG_DIR , 'plugins')): - self.plugins.add_plugin_dir(os.path.join(common.CONFIG_DIR, 'plugins')) - self.plugins.scan_for_plugins() - self.config = self.manager.get_config() - #Set up the interface: - self.wtree = gtk.glade.XML(common.get_glade_file("delugegtk.glade"), domain=APP) - self.window = self.wtree.get_widget("main_window") - self.toolbar = self.wtree.get_widget("tb_middle") - self.window.drag_dest_set(gtk.DEST_DEFAULT_ALL,[('text/uri-list', 0, 80)], gtk.gdk.ACTION_COPY) - self.window.connect("delete_event", self.close) - self.window.connect("drag_data_received", self.on_drag_data) - self.window.connect("window-state-event", self.window_state_event) - self.window.connect("configure-event", self.window_configure_event) - self.window.set_title(common.PROGRAM_NAME) - self.window.set_icon_from_file(common.get_pixmap("deluge32.png")) - self.notebook = self.wtree.get_widget("torrent_info") - self.notebook.connect("change-current-page", self.notebook_change_page_event) - self.statusbar = self.wtree.get_widget("statusbar") - - - ## Construct the Interface - try: - self.build_tray_icon() - except AttributeError: - #python-pygtk is < 2.9 - self.tray_icon = dgtk.StupidTray() - self.has_tray = False - else: - self.has_tray = True - - self.preferences_dialog = dialogs.PreferencesDlg(self, self.config) - self.plugin_dialog = dialogs.PluginDlg(self, self.plugins) - self.build_torrent_table() - self.build_summary_tab() - self.build_file_tab() - self.build_peer_tab() + def __init__(self): + APP = 'deluge' + DIR = os.path.join(common.INSTALL_PREFIX, 'share', 'locale') + locale.setlocale(locale.LC_ALL, '') + locale.bindtextdomain(APP, DIR) + locale.textdomain(APP) + gettext.bindtextdomain(APP, DIR) + gettext.textdomain(APP) + gettext.install(APP, DIR) + + self.is_running = False + self.update_queue = [] + self.ipc_manager = ipc_manager.Manager(self) + self.torrent_file_queue = [] + #Start the Deluge Manager: + self.manager = core.Manager(common.CLIENT_CODE, common.CLIENT_VERSION, + '%s %s'%(common.PROGRAM_NAME, common.PROGRAM_VERSION), common.CONFIG_DIR) + self.something_screwed_up = False + self.plugins = plugins.PluginManager(self.manager, self) + self.plugins.add_plugin_dir(common.PLUGIN_DIR) + if os.path.isdir(os.path.join(common.CONFIG_DIR , 'plugins')): + self.plugins.add_plugin_dir(os.path.join(common.CONFIG_DIR, 'plugins')) + self.plugins.scan_for_plugins() + self.config = self.manager.get_config() + #Set up the interface: + self.wtree = gtk.glade.XML(common.get_glade_file("delugegtk.glade"), domain=APP) + self.window = self.wtree.get_widget("main_window") + self.toolbar = self.wtree.get_widget("tb_middle") + self.window.drag_dest_set(gtk.DEST_DEFAULT_ALL,[('text/uri-list', 0, 80)], gtk.gdk.ACTION_COPY) + self.window.connect("delete_event", self.close) + self.window.connect("drag_data_received", self.on_drag_data) + self.window.connect("window-state-event", self.window_state_event) + self.window.connect("configure-event", self.window_configure_event) + self.window.set_title(common.PROGRAM_NAME) + self.window.set_icon_from_file(common.get_pixmap("deluge32.png")) + self.notebook = self.wtree.get_widget("torrent_info") + self.notebook.connect("change-current-page", self.notebook_change_page_event) + self.statusbar = self.wtree.get_widget("statusbar") + + + ## Construct the Interface + try: + self.build_tray_icon() + except AttributeError: + #python-pygtk is < 2.9 + self.tray_icon = dgtk.StupidTray() + self.has_tray = False + else: + self.has_tray = True + + self.preferences_dialog = dialogs.PreferencesDlg(self, self.config) + self.plugin_dialog = dialogs.PluginDlg(self, self.plugins) + self.build_torrent_table() + self.build_summary_tab() + self.build_file_tab() + self.build_peer_tab() - # Set the Torrent menu bar sub-menu to the same as the right-click Torrent pop-up menu - self.wtree.get_widget("menu_torrent").set_submenu(self.torrent_menu) - self.wtree.get_widget("menu_torrent").set_sensitive(False) - - self.connect_signals() - - try: - self.load_window_settings() - except KeyError: - pass - - self.apply_prefs() - self.load_window_geometry() - # Load plugins after GTK is initialised - self.update_queue.append(self.load_plugins) + # Set the Torrent menu bar sub-menu to the same as the right-click Torrent pop-up menu + self.wtree.get_widget("menu_torrent").set_submenu(self.torrent_menu) + self.wtree.get_widget("menu_torrent").set_sensitive(False) + + self.connect_signals() + + try: + self.load_window_settings() + except KeyError: + pass + + self.apply_prefs() + self.load_window_geometry() + # Load plugins after GTK is initialised + self.update_queue.append(self.load_plugins) - def external_add_torrent(self, torrent_file): - print "Ding!" - print "Got torrent externally:", os.path.basename(torrent_file) - print "Here's the raw data:", torrent_file - print "\tNow, what to do with it?" - if self.is_running: - print "\t\tthe client seems to already be running, i'll try and add the torrent" - uid = self.interactive_add_torrent(torrent_file) - else: - print "\t\tthe client hasn't started yet, I'll queue the torrent" - self.torrent_file_queue.append(torrent_file) - - def connect_signals(self): - self.wtree.signal_autoconnect({ - ## File Menu - "add_torrent": self.add_torrent_clicked, - "add_torrent_url": self.add_torrent_url_clicked, - "remove_torrent": self.remove_torrent_clicked, - "menu_quit": self.quit, - ## Edit Menu - "pref_clicked": self.show_pref_dialog, - "plugins_clicked": self.show_plugin_dialog, - ## View Menu - "toolbar_toggle": self.toolbar_toggle, - "infopane_toggle": self.infopane_toggle, - "size_toggle": self.size_toggle, - "status_toggle": self.status_toggle, - "seeders_toggle": self.seeders_toggle, - "peers_toggle": self.peers_toggle, - "dl_toggle": self.dl_toggle, - "ul_toggle": self.ul_toggle, - "eta_toggle": self.eta_toggle, - "share_toggle": self.share_toggle, - ## Help Menu - "show_about_dialog": self.show_about_dialog, - "launchpad": self.launchpad, - ## Toolbar - "start_pause": self.start_pause, - "update_tracker": self.update_tracker, - "clear_finished": self.clear_finished, - "queue_up": self.q_torrent_up, - "queue_down": self.q_torrent_down - }) - - def notebook_change_page_event(self, widget): - # Force an update when user changes the notebook tab - self.update() - - def build_tray_icon(self): - self.tray_icon = gtk.status_icon_new_from_file(common.get_pixmap("deluge32.png")) - - self.tray_glade = gtk.glade.XML(common.get_glade_file("tray_menu.glade"), domain='deluge') - self.tray_menu = self.tray_glade.get_widget("tray_menu") - self.tray_glade.signal_autoconnect({ - "quit": self.quit, - "plugins": self.show_plugin_dialog, - "preferences": self.show_pref_dialog, - "add_torrent": self.add_torrent_clicked, - "clear_finished": self.clear_finished, - "show_hide_window_toggled": self.show_hide_window_toggled - }) - - self.tray_glade.get_widget("download-limit-image").set_from_file(common.get_pixmap('downloading16.png')) - self.tray_glade.get_widget("upload-limit-image").set_from_file(common.get_pixmap('seeding16.png')) - self.build_tray_bwsetsubmenu() - - self.tray_icon.connect("activate", self.tray_clicked) - self.tray_icon.connect("popup-menu", self.tray_popup) - - def tray_popup(self, status_icon, button, activate_time): - if self.window.get_property("visible"): - self.tray_glade.get_widget("show_hide_window").set_active(True) - else: - self.tray_glade.get_widget("show_hide_window").set_active(False) - - self.tray_menu.popup(None, None, gtk.status_icon_position_menu, - button, activate_time, status_icon) - - def build_tray_bwsetsubmenu(self): - # Create the Download speed list sub-menu - self.submenu_bwdownset = self.build_menu_radio_list( - self.config.get("tray_downloadspeedlist"), self.tray_setbwdown, - self.config.get("max_download_speed"), _("KiB/s"), - show_notset=True) - - # Create the Upload speed list sub-menu - self.submenu_bwupset = self.build_menu_radio_list( - self.config.get("tray_uploadspeedlist"), self.tray_setbwup, - self.config.get("max_upload_speed"), _("KiB/s"), - show_notset=True) - - # Add the sub-menus to the tray menu - self.tray_glade.get_widget("download_limit").set_submenu(self.submenu_bwdownset) - self.tray_glade.get_widget("upload_limit").set_submenu(self.submenu_bwupset) - - # Show the sub-menus for all to see - self.submenu_bwdownset.show_all() - self.submenu_bwupset.show_all() + def external_add_torrent(self, torrent_file): + print "Ding!" + print "Got torrent externally:", os.path.basename(torrent_file) + print "Here's the raw data:", torrent_file + print "\tNow, what to do with it?" + if self.is_running: + print "\t\tthe client seems to already be running, i'll try and add the torrent" + uid = self.interactive_add_torrent(torrent_file) + else: + print "\t\tthe client hasn't started yet, I'll queue the torrent" + self.torrent_file_queue.append(torrent_file) + + def connect_signals(self): + self.wtree.signal_autoconnect({ + ## File Menu + "add_torrent": self.add_torrent_clicked, + "add_torrent_url": self.add_torrent_url_clicked, + "remove_torrent": self.remove_torrent_clicked, + "menu_quit": self.quit, + ## Edit Menu + "pref_clicked": self.show_pref_dialog, + "plugins_clicked": self.show_plugin_dialog, + ## View Menu + "toolbar_toggle": self.toolbar_toggle, + "infopane_toggle": self.infopane_toggle, + "size_toggle": self.size_toggle, + "status_toggle": self.status_toggle, + "seeders_toggle": self.seeders_toggle, + "peers_toggle": self.peers_toggle, + "dl_toggle": self.dl_toggle, + "ul_toggle": self.ul_toggle, + "eta_toggle": self.eta_toggle, + "share_toggle": self.share_toggle, + ## Help Menu + "show_about_dialog": self.show_about_dialog, + "launchpad": self.launchpad, + ## Toolbar + "start_pause": self.start_pause, + "update_tracker": self.update_tracker, + "clear_finished": self.clear_finished, + "queue_up": self.q_torrent_up, + "queue_down": self.q_torrent_down + }) + + def notebook_change_page_event(self, widget): + # Force an update when user changes the notebook tab + self.update() + + def build_tray_icon(self): + self.tray_icon = gtk.status_icon_new_from_file(common.get_pixmap("deluge32.png")) + + self.tray_glade = gtk.glade.XML(common.get_glade_file("tray_menu.glade"), domain='deluge') + self.tray_menu = self.tray_glade.get_widget("tray_menu") + self.tray_glade.signal_autoconnect({ + "quit": self.quit, + "plugins": self.show_plugin_dialog, + "preferences": self.show_pref_dialog, + "add_torrent": self.add_torrent_clicked, + "clear_finished": self.clear_finished, + "show_hide_window_toggled": self.show_hide_window_toggled + }) + + self.tray_glade.get_widget("download-limit-image").set_from_file(common.get_pixmap('downloading16.png')) + self.tray_glade.get_widget("upload-limit-image").set_from_file(common.get_pixmap('seeding16.png')) + self.build_tray_bwsetsubmenu() + + self.tray_icon.connect("activate", self.tray_clicked) + self.tray_icon.connect("popup-menu", self.tray_popup) + + def tray_popup(self, status_icon, button, activate_time): + if self.window.get_property("visible"): + self.tray_glade.get_widget("show_hide_window").set_active(True) + else: + self.tray_glade.get_widget("show_hide_window").set_active(False) + + self.tray_menu.popup(None, None, gtk.status_icon_position_menu, + button, activate_time, status_icon) + + def build_tray_bwsetsubmenu(self): + # Create the Download speed list sub-menu + self.submenu_bwdownset = self.build_menu_radio_list( + self.config.get("tray_downloadspeedlist"), self.tray_setbwdown, + self.config.get("max_download_speed"), _("KiB/s"), + show_notset=True) + + # Create the Upload speed list sub-menu + self.submenu_bwupset = self.build_menu_radio_list( + self.config.get("tray_uploadspeedlist"), self.tray_setbwup, + self.config.get("max_upload_speed"), _("KiB/s"), + show_notset=True) + + # Add the sub-menus to the tray menu + self.tray_glade.get_widget("download_limit").set_submenu(self.submenu_bwdownset) + self.tray_glade.get_widget("upload_limit").set_submenu(self.submenu_bwupset) + + # Show the sub-menus for all to see + self.submenu_bwdownset.show_all() + self.submenu_bwupset.show_all() - def build_menu_radio_list(self, value_list, callback, pref_value=None, - suffix=None, show_notset=False, - notset_label="Unlimited", notset_lessthan=0): - # Build a menu with radio menu items from a list and connect them to the callback - # The pref_value is what you would like to test for the default active radio item - # Setting show_unlimited will include an Unlimited radio item - - menu = gtk.Menu() - - group = None - for value in sorted(value_list): - if suffix != None: - menuitem = gtk.RadioMenuItem(group, str(value) + " " + suffix) - else: - menuitem = gtk.RadioMenuItem(group, str(value)) - - group = menuitem + def build_menu_radio_list(self, value_list, callback, pref_value=None, + suffix=None, show_notset=False, + notset_label="Unlimited", notset_lessthan=0): + # Build a menu with radio menu items from a list and connect them to the callback + # The pref_value is what you would like to test for the default active radio item + # Setting show_unlimited will include an Unlimited radio item + + menu = gtk.Menu() + + group = None + for value in sorted(value_list): + if suffix != None: + menuitem = gtk.RadioMenuItem(group, str(value) + " " + suffix) + else: + menuitem = gtk.RadioMenuItem(group, str(value)) + + group = menuitem - if value == pref_value and pref_value != None: - menuitem.set_active(True) + if value == pref_value and pref_value != None: + menuitem.set_active(True) - if callback != None: - menuitem.connect("toggled", callback) + if callback != None: + menuitem.connect("toggled", callback) - menu.append(menuitem) + menu.append(menuitem) - if show_notset: - menuitem = gtk.RadioMenuItem(group, _(notset_label)) - if pref_value < notset_lessthan and pref_value != None: - menuitem.set_active(True) - menuitem.connect("toggled", callback) - menu.append(menuitem) - - # Add the Other... menuitem - menuitem = gtk.SeparatorMenuItem() - menu.append(menuitem) - menuitem = gtk.MenuItem(_("Other...")) - menuitem.connect("activate", callback) - menu.append(menuitem) - - return menu - - def tray_setbwdown(self, widget, data=None): - str_bwdown = widget.get_children()[0].get_text().rstrip(" "+_("KiB/s")) - if str_bwdown == _("Unlimited"): - str_bwdown = -1 - - if str_bwdown == _("Other..."): - dialog_glade = gtk.glade.XML(common.get_glade_file("dgtkpopups.glade")) - speed_dialog = dialog_glade.get_widget("speed_dialog") - spin_speed = dialog_glade.get_widget("spin_speed") - spin_speed.set_value(self.config.get("max_download_speed")) - spin_speed.select_region(0, -1) - response = speed_dialog.run() - if response == 1: # OK Response - str_bwdown = spin_speed.get_value() - else: - speed_dialog.destroy() - return - speed_dialog.destroy() - - self.config.set("max_download_speed", float(str_bwdown)) - self.apply_prefs() + if show_notset: + menuitem = gtk.RadioMenuItem(group, _(notset_label)) + if pref_value < notset_lessthan and pref_value != None: + menuitem.set_active(True) + menuitem.connect("toggled", callback) + menu.append(menuitem) + + # Add the Other... menuitem + menuitem = gtk.SeparatorMenuItem() + menu.append(menuitem) + menuitem = gtk.MenuItem(_("Other...")) + menuitem.connect("activate", callback) + menu.append(menuitem) + + return menu + + def tray_setbwdown(self, widget, data=None): + str_bwdown = widget.get_children()[0].get_text().rstrip(" "+_("KiB/s")) + if str_bwdown == _("Unlimited"): + str_bwdown = -1 + + if str_bwdown == _("Other..."): + dialog_glade = gtk.glade.XML(common.get_glade_file("dgtkpopups.glade")) + speed_dialog = dialog_glade.get_widget("speed_dialog") + spin_speed = dialog_glade.get_widget("spin_speed") + spin_speed.set_value(self.config.get("max_download_speed")) + spin_speed.select_region(0, -1) + response = speed_dialog.run() + if response == 1: # OK Response + str_bwdown = spin_speed.get_value() + else: + speed_dialog.destroy() + return + speed_dialog.destroy() + + self.config.set("max_download_speed", float(str_bwdown)) + self.apply_prefs() - def tray_setbwup(self, widget, data=None): - str_bwup = widget.get_children()[0].get_text().rstrip(" "+_("KiB/s")) - if str_bwup == _("Unlimited"): - str_bwup = -1 - - if str_bwup == _("Other..."): - dialog_glade = gtk.glade.XML(common.get_glade_file("dgtkpopups.glade")) - speed_dialog = dialog_glade.get_widget("speed_dialog") - spin_speed = dialog_glade.get_widget("spin_speed") - spin_speed.set_value(self.config.get("max_upload_speed")) - spin_speed.select_region(0, -1) - response = speed_dialog.run() - if response == 1: # OK Response - str_bwup = spin_speed.get_value() - else: - speed_dialog.destroy() - return - speed_dialog.destroy() - - self.config.set("max_upload_speed", float(str_bwup)) - self.apply_prefs() + def tray_setbwup(self, widget, data=None): + str_bwup = widget.get_children()[0].get_text().rstrip(" "+_("KiB/s")) + if str_bwup == _("Unlimited"): + str_bwup = -1 + + if str_bwup == _("Other..."): + dialog_glade = gtk.glade.XML(common.get_glade_file("dgtkpopups.glade")) + speed_dialog = dialog_glade.get_widget("speed_dialog") + spin_speed = dialog_glade.get_widget("spin_speed") + spin_speed.set_value(self.config.get("max_upload_speed")) + spin_speed.select_region(0, -1) + response = speed_dialog.run() + if response == 1: # OK Response + str_bwup = spin_speed.get_value() + else: + speed_dialog.destroy() + return + speed_dialog.destroy() + + self.config.set("max_upload_speed", float(str_bwup)) + self.apply_prefs() - def unlock_tray(self,comingnext): - entered_pass = gtk.Entry(25) - entered_pass.set_activates_default(True) - entered_pass.set_width_chars(25) - entered_pass.set_visibility(False) - entered_pass.show() - tray_lock = gtk.Dialog(title=_("Deluge is locked"), parent=self.window, - buttons=(gtk.STOCK_CANCEL, gtk.RESPONSE_REJECT, gtk.STOCK_OK, gtk.RESPONSE_ACCEPT)) - label = gtk.Label(_("Deluge is password protected.\nTo show the Deluge window, please enter your password")) - label.set_line_wrap(True) - label.set_justify(gtk.JUSTIFY_CENTER) - tray_lock.set_position(gtk.WIN_POS_CENTER_ALWAYS) - tray_lock.set_size_request(400, 200) - tray_lock.set_default_response(gtk.RESPONSE_ACCEPT) - tray_lock.vbox.pack_start(label) - tray_lock.vbox.pack_start(entered_pass) - tray_lock.show_all() - if tray_lock.run() == gtk.RESPONSE_ACCEPT: - if self.config.get("tray_passwd") == entered_pass.get_text(): - if comingnext == "mainwinshow": - self.window.show() - elif comingnext == "prefwinshow": - self.preferences_dialog.show() - self.apply_prefs() - self.config.save_to_file() - elif comingnext == "quitus": - self.window.hide() - self.shutdown() + def unlock_tray(self,comingnext): + entered_pass = gtk.Entry(25) + entered_pass.set_activates_default(True) + entered_pass.set_width_chars(25) + entered_pass.set_visibility(False) + entered_pass.show() + tray_lock = gtk.Dialog(title=_("Deluge is locked"), parent=self.window, + buttons=(gtk.STOCK_CANCEL, gtk.RESPONSE_REJECT, gtk.STOCK_OK, gtk.RESPONSE_ACCEPT)) + label = gtk.Label(_("Deluge is password protected.\nTo show the Deluge window, please enter your password")) + label.set_line_wrap(True) + label.set_justify(gtk.JUSTIFY_CENTER) + tray_lock.set_position(gtk.WIN_POS_CENTER_ALWAYS) + tray_lock.set_size_request(400, 200) + tray_lock.set_default_response(gtk.RESPONSE_ACCEPT) + tray_lock.vbox.pack_start(label) + tray_lock.vbox.pack_start(entered_pass) + tray_lock.show_all() + if tray_lock.run() == gtk.RESPONSE_ACCEPT: + if self.config.get("tray_passwd") == entered_pass.get_text(): + if comingnext == "mainwinshow": + self.window.show() + elif comingnext == "prefwinshow": + self.preferences_dialog.show() + self.apply_prefs() + self.config.save_to_file() + elif comingnext == "quitus": + self.window.hide() + self.shutdown() - tray_lock.destroy() - return True + tray_lock.destroy() + return True - def list_of_trackers(self,obj=None): - torrent = self.get_selected_torrent() - if torrent is not None: - trackerslist = self.manager.get_trackers(torrent) - self.show_edit_tracker_dialog(trackerslist) + def list_of_trackers(self,obj=None): + torrent = self.get_selected_torrent() + if torrent is not None: + trackerslist = self.manager.get_trackers(torrent) + self.show_edit_tracker_dialog(trackerslist) - def cancel_edit_window(self,arg=None): - self.edit_window.destroy() + def cancel_edit_window(self,arg=None): + self.edit_window.destroy() - def accept_edit_window(self,arg=None): - torrent = self.get_selected_torrent() - self.textlist = self.textbuffer.get_text(self.textbuffer.get_start_iter(), self.textbuffer.get_end_iter(), include_hidden_chars=False).strip() - self.manager.replace_trackers(torrent, self.textlist) - self.edit_window.destroy() + def accept_edit_window(self,arg=None): + torrent = self.get_selected_torrent() + self.textlist = self.textbuffer.get_text(self.textbuffer.get_start_iter(), self.textbuffer.get_end_iter(), include_hidden_chars=False).strip() + self.manager.replace_trackers(torrent, self.textlist) + self.edit_window.destroy() - def show_edit_tracker_dialog(self,list): - self.textbuffer = gtk.TextBuffer(table=None) - self.textbuffer.set_text(list) - self.edit_glade = gtk.glade.XML(common.get_glade_file("edit_trackers.glade")) - self.edit_list = self.edit_glade.get_widget("txt_tracker_list") - self.edit_list.set_buffer(self.textbuffer) - self.edit_window = self.edit_glade.get_widget("edittrackers") - self.edit_window.set_position(gtk.WIN_POS_CENTER_ALWAYS) - self.edit_window.set_size_request(400, 200) - self.edit_glade.signal_autoconnect({"cancel_button_clicked": self.cancel_edit_window, - "ok_button_clicked": self.accept_edit_window - }) + def show_edit_tracker_dialog(self,list): + self.textbuffer = gtk.TextBuffer(table=None) + self.textbuffer.set_text(list) + self.edit_glade = gtk.glade.XML(common.get_glade_file("edit_trackers.glade")) + self.edit_list = self.edit_glade.get_widget("txt_tracker_list") + self.edit_list.set_buffer(self.textbuffer) + self.edit_window = self.edit_glade.get_widget("edittrackers") + self.edit_window.set_position(gtk.WIN_POS_CENTER_ALWAYS) + self.edit_window.set_size_request(400, 200) + self.edit_glade.signal_autoconnect({"cancel_button_clicked": self.cancel_edit_window, + "ok_button_clicked": self.accept_edit_window + }) - self.edit_window.show_all() + self.edit_window.show_all() - return True + return True - def tray_clicked(self, status_icon): - if self.window.get_property("visible"): - if self.window.is_active(): - self.window.hide() - else: - self.window.present() - else: - if self.config.get("lock_tray") == True: - self.unlock_tray("mainwinshow") - else: - self.load_window_geometry() - self.window.show() - - def show_hide_window_toggled(self, widget): - if widget.get_active() and not self.window.get_property("visible"): - if self.config.get("lock_tray") == True: - self.unlock_tray("mainwinshow") - else: - self.window.show() - elif not widget.get_active() and self.window.get_property("visible"): - self.window.hide() + def tray_clicked(self, status_icon): + if self.window.get_property("visible"): + if self.window.is_active(): + self.window.hide() + else: + self.window.present() + else: + if self.config.get("lock_tray") == True: + self.unlock_tray("mainwinshow") + else: + self.load_window_geometry() + self.window.show() + + def show_hide_window_toggled(self, widget): + if widget.get_active() and not self.window.get_property("visible"): + if self.config.get("lock_tray") == True: + self.unlock_tray("mainwinshow") + else: + self.window.show() + elif not widget.get_active() and self.window.get_property("visible"): + self.window.hide() - def build_torrent_table(self): - ## Create the torrent listview - self.torrent_view = self.wtree.get_widget("torrent_view") - self.torrent_glade = gtk.glade.XML(common.get_glade_file("torrent_menu.glade"), domain='deluge') - self.torrent_menu = self.torrent_glade.get_widget("torrent_menu") - self.torrent_glade.signal_autoconnect({ "remove_torrent": self.remove_torrent_clicked, - "edit_trackers": self.list_of_trackers, - "start_pause": self.start_pause, - "update_tracker": self.update_tracker, - "clear_finished": self.clear_finished, - "queue_up": self.q_torrent_up, - "queue_down": self.q_torrent_down, - "queue_bottom": self.q_to_bottom, - "queue_top": self.q_to_top, - }) - self.torrent_menu.connect("focus", self.torrent_menu_focus) - # UID, Q#, Status Icon, Name, Size, Progress, Message, Seeders, Peers, DL, UL, ETA, Share - self.torrent_model = gtk.ListStore(int, int, gtk.gdk.Pixbuf, str, str, float, str, int, int, int, int, int, int, str, float) - self.torrent_view.set_model(self.torrent_model) - self.torrent_view.set_rules_hint(True) - self.torrent_view.set_reorderable(True) - self.torrent_view.get_selection().set_mode(gtk.SELECTION_MULTIPLE) - self.torrent_selected = None - - def size(column, cell, model, iter, data): - size = long(model.get_value(iter, data)) - size_str = common.fsize(size) - cell.set_property('text', size_str) - - def peer(column, cell, model, iter, data): - c1, c2 = data - a = int(model.get_value(iter, c1)) - b = int(model.get_value(iter, c2)) - cell.set_property('text', '%d (%d)'%(a, b)) - - def time(column, cell, model, iter, data): - time = int(model.get_value(iter, data)) - if time < 0 or time == 0: - time_str = _("Infinity") - else: - time_str = common.ftime(time) - cell.set_property('text', time_str) - - def ratio(column, cell, model, iter, data): - ratio = float(model.get_value(iter, data)) - if ratio == -1: - ratio_str = _("Unknown") - else: - ratio_str = "%.3f"%ratio - cell.set_property('text', ratio_str) - - - ## Initializes the columns for the torrent_view - (TORRENT_VIEW_COL_UID, TORRENT_VIEW_COL_QUEUE, TORRENT_VIEW_COL_STATUSICON, TORRENT_VIEW_COL_NAME, - TORRENT_VIEW_COL_SIZE, TORRENT_VIEW_COL_PROGRESS, TORRENT_VIEW_COL_STATUS, - TORRENT_VIEW_COL_CONNECTED_SEEDS, TORRENT_VIEW_COL_SEEDS, - TORRENT_VIEW_COL_CONNECTED_PEERS, TORRENT_VIEW_COL_PEERS, TORRENT_VIEW_COL_DOWNLOAD, - TORRENT_VIEW_COL_UPLOAD, TORRENT_VIEW_COL_ETA, TORRENT_VIEW_COL_RATIO) = range(15) + def build_torrent_table(self): + ## Create the torrent listview + self.torrent_view = self.wtree.get_widget("torrent_view") + self.torrent_glade = gtk.glade.XML(common.get_glade_file("torrent_menu.glade"), domain='deluge') + self.torrent_menu = self.torrent_glade.get_widget("torrent_menu") + self.torrent_glade.signal_autoconnect({ "remove_torrent": self.remove_torrent_clicked, + "edit_trackers": self.list_of_trackers, + "start_pause": self.start_pause, + "update_tracker": self.update_tracker, + "clear_finished": self.clear_finished, + "queue_up": self.q_torrent_up, + "queue_down": self.q_torrent_down, + "queue_bottom": self.q_to_bottom, + "queue_top": self.q_to_top, + }) + self.torrent_menu.connect("focus", self.torrent_menu_focus) + # UID, Q#, Status Icon, Name, Size, Progress, Message, Seeders, Peers, DL, UL, ETA, Share + self.torrent_model = gtk.ListStore(int, int, gtk.gdk.Pixbuf, str, str, float, str, int, int, int, int, int, int, str, float) + self.torrent_view.set_model(self.torrent_model) + self.torrent_view.set_rules_hint(True) + self.torrent_view.set_reorderable(True) + self.torrent_view.get_selection().set_mode(gtk.SELECTION_MULTIPLE) + self.torrent_selected = None + + def size(column, cell, model, iter, data): + size = long(model.get_value(iter, data)) + size_str = common.fsize(size) + cell.set_property('text', size_str) + + def peer(column, cell, model, iter, data): + c1, c2 = data + a = int(model.get_value(iter, c1)) + b = int(model.get_value(iter, c2)) + cell.set_property('text', '%d (%d)'%(a, b)) + + def time(column, cell, model, iter, data): + time = int(model.get_value(iter, data)) + if time < 0 or time == 0: + time_str = _("Infinity") + else: + time_str = common.ftime(time) + cell.set_property('text', time_str) + + def ratio(column, cell, model, iter, data): + ratio = float(model.get_value(iter, data)) + if ratio == -1: + ratio_str = _("Unknown") + else: + ratio_str = "%.3f"%ratio + cell.set_property('text', ratio_str) + + + ## Initializes the columns for the torrent_view + (TORRENT_VIEW_COL_UID, TORRENT_VIEW_COL_QUEUE, TORRENT_VIEW_COL_STATUSICON, TORRENT_VIEW_COL_NAME, + TORRENT_VIEW_COL_SIZE, TORRENT_VIEW_COL_PROGRESS, TORRENT_VIEW_COL_STATUS, + TORRENT_VIEW_COL_CONNECTED_SEEDS, TORRENT_VIEW_COL_SEEDS, + TORRENT_VIEW_COL_CONNECTED_PEERS, TORRENT_VIEW_COL_PEERS, TORRENT_VIEW_COL_DOWNLOAD, + TORRENT_VIEW_COL_UPLOAD, TORRENT_VIEW_COL_ETA, TORRENT_VIEW_COL_RATIO) = range(15) - self.queue_column = dgtk.add_text_column(self.torrent_view, "#", TORRENT_VIEW_COL_QUEUE) - self.name_column = dgtk.add_texticon_column(self.torrent_view, _("Name"), TORRENT_VIEW_COL_STATUSICON, TORRENT_VIEW_COL_NAME) - self.size_column = dgtk.add_func_column(self.torrent_view, _("Size"), size, TORRENT_VIEW_COL_SIZE) - self.status_column = dgtk.add_progress_column(self.torrent_view, _("Status"), TORRENT_VIEW_COL_PROGRESS, TORRENT_VIEW_COL_STATUS) - self.seed_column = dgtk.add_func_column(self.torrent_view, _("Seeders"), peer, (TORRENT_VIEW_COL_CONNECTED_SEEDS, TORRENT_VIEW_COL_SEEDS)) - self.peer_column = dgtk.add_func_column(self.torrent_view, _("Peers"), peer, (TORRENT_VIEW_COL_CONNECTED_PEERS, TORRENT_VIEW_COL_PEERS)) - self.dl_column = dgtk.add_func_column(self.torrent_view, _("Down Speed"), dgtk.cell_data_speed, TORRENT_VIEW_COL_DOWNLOAD) - self.ul_column = dgtk.add_func_column(self.torrent_view, _("Up Speed"), dgtk.cell_data_speed, TORRENT_VIEW_COL_UPLOAD) - self.eta_column = dgtk.add_func_column(self.torrent_view, _("ETA"), time, TORRENT_VIEW_COL_ETA) - self.share_column = dgtk.add_func_column(self.torrent_view, _("Ratio"), ratio, TORRENT_VIEW_COL_RATIO) - - self.status_column.set_expand(True) - self.name_column.set_sort_column_id(TORRENT_VIEW_COL_NAME) - self.seed_column.set_sort_column_id(TORRENT_VIEW_COL_CONNECTED_SEEDS) - self.peer_column.set_sort_column_id(TORRENT_VIEW_COL_CONNECTED_PEERS) - - def long_sort(model, iter1, iter2, data): - value1 = long(model.get_value(iter1, data)) - value2 = long(model.get_value(iter2, data)) - if value1 < value2: - return -1 - elif value1 > value2: - return 1 - else: - return 0 - - self.torrent_model.set_sort_func(TORRENT_VIEW_COL_QUEUE, long_sort, TORRENT_VIEW_COL_QUEUE) - self.torrent_model.set_sort_func(TORRENT_VIEW_COL_SIZE, long_sort, TORRENT_VIEW_COL_SIZE) - self.torrent_model.set_sort_func(TORRENT_VIEW_COL_ETA, long_sort, TORRENT_VIEW_COL_ETA) - - self.torrent_model.set_sort_column_id(TORRENT_VIEW_COL_QUEUE, gtk.SORT_ASCENDING) - - try: - self.torrent_view.get_selection().set_select_function(self.torrent_clicked, full=True) - except TypeError: - self.torrent_view.get_selection().set_select_function(self.old_t_click) - self.torrent_view.connect("button-press-event", self.torrent_view_clicked) - self.right_click = False + self.queue_column = dgtk.add_text_column(self.torrent_view, "#", TORRENT_VIEW_COL_QUEUE) + self.name_column = dgtk.add_texticon_column(self.torrent_view, _("Name"), TORRENT_VIEW_COL_STATUSICON, TORRENT_VIEW_COL_NAME) + self.size_column = dgtk.add_func_column(self.torrent_view, _("Size"), size, TORRENT_VIEW_COL_SIZE) + self.status_column = dgtk.add_progress_column(self.torrent_view, _("Status"), TORRENT_VIEW_COL_PROGRESS, TORRENT_VIEW_COL_STATUS) + self.seed_column = dgtk.add_func_column(self.torrent_view, _("Seeders"), peer, (TORRENT_VIEW_COL_CONNECTED_SEEDS, TORRENT_VIEW_COL_SEEDS)) + self.peer_column = dgtk.add_func_column(self.torrent_view, _("Peers"), peer, (TORRENT_VIEW_COL_CONNECTED_PEERS, TORRENT_VIEW_COL_PEERS)) + self.dl_column = dgtk.add_func_column(self.torrent_view, _("Down Speed"), dgtk.cell_data_speed, TORRENT_VIEW_COL_DOWNLOAD) + self.ul_column = dgtk.add_func_column(self.torrent_view, _("Up Speed"), dgtk.cell_data_speed, TORRENT_VIEW_COL_UPLOAD) + self.eta_column = dgtk.add_func_column(self.torrent_view, _("ETA"), time, TORRENT_VIEW_COL_ETA) + self.share_column = dgtk.add_func_column(self.torrent_view, _("Ratio"), ratio, TORRENT_VIEW_COL_RATIO) + + self.status_column.set_expand(True) + self.name_column.set_sort_column_id(TORRENT_VIEW_COL_NAME) + self.seed_column.set_sort_column_id(TORRENT_VIEW_COL_CONNECTED_SEEDS) + self.peer_column.set_sort_column_id(TORRENT_VIEW_COL_CONNECTED_PEERS) + + def long_sort(model, iter1, iter2, data): + value1 = long(model.get_value(iter1, data)) + value2 = long(model.get_value(iter2, data)) + if value1 < value2: + return -1 + elif value1 > value2: + return 1 + else: + return 0 + + self.torrent_model.set_sort_func(TORRENT_VIEW_COL_QUEUE, long_sort, TORRENT_VIEW_COL_QUEUE) + self.torrent_model.set_sort_func(TORRENT_VIEW_COL_SIZE, long_sort, TORRENT_VIEW_COL_SIZE) + self.torrent_model.set_sort_func(TORRENT_VIEW_COL_ETA, long_sort, TORRENT_VIEW_COL_ETA) + + self.torrent_model.set_sort_column_id(TORRENT_VIEW_COL_QUEUE, gtk.SORT_ASCENDING) + + try: + self.torrent_view.get_selection().set_select_function(self.torrent_clicked, full=True) + except TypeError: + self.torrent_view.get_selection().set_select_function(self.old_t_click) + self.torrent_view.connect("button-press-event", self.torrent_view_clicked) + self.right_click = False - def old_t_click(self, path): - return self.torrent_clicked(self.torrent_view.get_selection(), self.torrent_model, path, False) - - def torrent_clicked(self, selection, model, path, is_selected): - if is_selected: - # Torrent is already selected, we don't need to do anything - return not self.right_click - unique_id = model.get_value(model.get_iter(path), 0) - state = self.manager.get_torrent_state(unique_id) - # A new torrent has been selected, need to update parts of interface - self.text_summary_total_size.set_text(common.fsize(state["total_size"])) - self.text_summary_pieces.set_text(str(state["num_pieces"])) - self.text_summary_tracker.set_text(str(state["tracker"])) - # Now for the File tab - self.file_store.clear() - all_files = self.manager.get_torrent_file_info(unique_id) - file_filter = self.manager.get_file_filter(unique_id) - if file_filter is None: - file_filter = [False] * len(all_files) - assert(len(all_files) == len(file_filter)) - i=0 - for f in all_files: + def old_t_click(self, path): + return self.torrent_clicked(self.torrent_view.get_selection(), self.torrent_model, path, False) + + def torrent_clicked(self, selection, model, path, is_selected): + if is_selected: + # Torrent is already selected, we don't need to do anything + return not self.right_click + unique_id = model.get_value(model.get_iter(path), 0) + state = self.manager.get_torrent_state(unique_id) + # A new torrent has been selected, need to update parts of interface + self.text_summary_total_size.set_text(common.fsize(state["total_size"])) + self.text_summary_pieces.set_text(str(state["num_pieces"])) + self.text_summary_tracker.set_text(str(state["tracker"])) + # Now for the File tab + self.file_store.clear() + all_files = self.manager.get_torrent_file_info(unique_id) + file_filter = self.manager.get_file_filter(unique_id) + if file_filter is None: + file_filter = [False] * len(all_files) + assert(len(all_files) == len(file_filter)) + i=0 + for f in all_files: self.file_store.append([not file_filter[i], f['path'], common.fsize(f['size']), f['offset'], round(f['progress'],2)]) i=i+1 - - return True - - def torrent_view_clicked(self, widget, event): - if event.button == 3: - x = int(event.x) - y = int(event.y) - data = self.torrent_view.get_path_at_pos(x, y) - if data is None: - return True - path, col, cellx, celly = data - self.right_click = self.torrent_view.get_selection().path_is_selected(path) - self.torrent_view.grab_focus() - self.torrent_view.set_cursor(path, col, 0) - unique_id = self.torrent_model.get_value(self.torrent_model.get_iter(path), 0) - # Get the torrent state so we can check if the torrent is paused. - torrent_state = self.manager.get_torrent_state(unique_id) - widget = self.torrent_glade.get_widget("menu_pause") - if torrent_state["is_paused"]: - widget.set_image(gtk.image_new_from_stock(gtk.STOCK_MEDIA_PLAY, gtk.ICON_SIZE_MENU)) - widget.get_children()[0].set_text(_("Resume")) - else: - widget.set_image(gtk.image_new_from_stock(gtk.STOCK_MEDIA_PAUSE, gtk.ICON_SIZE_MENU)) - widget.get_children()[0].set_text(_("Pause")) - - self.torrent_menu.popup(None, None, None, event.button, event.time) - - return True - else: - self.right_click = False - return False - - def start_pause(self, widget): - unique_ids = self.get_selected_torrent_rows() - try: - for uid in unique_ids: - self.manager.set_user_pause(uid, not self.manager.is_user_paused(uid)) - - # We need to force an update so the GUI looks more responsive - self.update() + + return True + + def torrent_view_clicked(self, widget, event): + if event.button == 3: + x = int(event.x) + y = int(event.y) + data = self.torrent_view.get_path_at_pos(x, y) + if data is None: + return True + path, col, cellx, celly = data + self.right_click = self.torrent_view.get_selection().path_is_selected(path) + self.torrent_view.grab_focus() + self.torrent_view.set_cursor(path, col, 0) + unique_id = self.torrent_model.get_value(self.torrent_model.get_iter(path), 0) + # Get the torrent state so we can check if the torrent is paused. + torrent_state = self.manager.get_torrent_state(unique_id) + widget = self.torrent_glade.get_widget("menu_pause") + if torrent_state["is_paused"]: + widget.set_image(gtk.image_new_from_stock(gtk.STOCK_MEDIA_PLAY, gtk.ICON_SIZE_MENU)) + widget.get_children()[0].set_text(_("Resume")) + else: + widget.set_image(gtk.image_new_from_stock(gtk.STOCK_MEDIA_PAUSE, gtk.ICON_SIZE_MENU)) + widget.get_children()[0].set_text(_("Pause")) + + self.torrent_menu.popup(None, None, None, event.button, event.time) + + return True + else: + self.right_click = False + return False + + def start_pause(self, widget): + unique_ids = self.get_selected_torrent_rows() + try: + for uid in unique_ids: + self.manager.set_user_pause(uid, not self.manager.is_user_paused(uid)) + + # We need to force an update so the GUI looks more responsive + self.update() - except KeyError: - pass + except KeyError: + pass - def torrent_menu_focus(self, widget, direction): - menuitem = self.torrent_glade.get_widget("menu_pause") - # Check if we are selecting multiple torrents - if len(self.get_selected_torrent_rows()) > 1: - menuitem.set_image(gtk.image_new_from_stock(gtk.STOCK_MEDIA_PAUSE, gtk.ICON_SIZE_MENU)) - menuitem.get_children()[0].set_text(_("Pause/Resume")) - return - - # Get the selected torrent state so we can check if the torrent is paused. - unique_id = self.get_selected_torrent() - if unique_id is None: - return - torrent_state = self.manager.get_torrent_state(unique_id) - if torrent_state["is_paused"]: - menuitem.set_image(gtk.image_new_from_stock(gtk.STOCK_MEDIA_PLAY, gtk.ICON_SIZE_MENU)) - menuitem.get_children()[0].set_text(_("Resume")) - else: - menuitem.set_image(gtk.image_new_from_stock(gtk.STOCK_MEDIA_PAUSE, gtk.ICON_SIZE_MENU)) - menuitem.get_children()[0].set_text(_("Pause")) - - def build_summary_tab(self): - #Torrent Summary tab - # Look into glade's widget prefix function - self.text_summary_name = self.wtree.get_widget("summary_name") - self.text_summary_total_size = self.wtree.get_widget("summary_total_size") - self.text_summary_pieces = self.wtree.get_widget("summary_pieces") - self.text_summary_total_downloaded = self.wtree.get_widget("summary_total_downloaded") - self.text_summary_total_uploaded = self.wtree.get_widget("summary_total_uploaded") - self.text_summary_download_speed = self.wtree.get_widget("summary_download_speed") - self.text_summary_upload_speed = self.wtree.get_widget("summary_upload_speed") - self.text_summary_seeders = self.wtree.get_widget("summary_seeders") - self.text_summary_peers = self.wtree.get_widget("summary_peers") - self.text_summary_percentage_done = self.wtree.get_widget("summary_percentage_done") - self.text_summary_share_ratio = self.wtree.get_widget("summary_share_ratio") - self.text_summary_downloaded_this_session = self.wtree.get_widget("summary_downloaded_this_session") - self.text_summary_uploaded_this_session = self.wtree.get_widget("summary_uploaded_this_session") - self.text_summary_tracker = self.wtree.get_widget("summary_tracker") - self.text_summary_tracker_status = self.wtree.get_widget("summary_tracker_status") - self.text_summary_next_announce = self.wtree.get_widget("summary_next_announce") - self.text_summary_eta = self.wtree.get_widget("summary_eta") + def torrent_menu_focus(self, widget, direction): + menuitem = self.torrent_glade.get_widget("menu_pause") + # Check if we are selecting multiple torrents + if len(self.get_selected_torrent_rows()) > 1: + menuitem.set_image(gtk.image_new_from_stock(gtk.STOCK_MEDIA_PAUSE, gtk.ICON_SIZE_MENU)) + menuitem.get_children()[0].set_text(_("Pause/Resume")) + return + + # Get the selected torrent state so we can check if the torrent is paused. + unique_id = self.get_selected_torrent() + if unique_id is None: + return + torrent_state = self.manager.get_torrent_state(unique_id) + if torrent_state["is_paused"]: + menuitem.set_image(gtk.image_new_from_stock(gtk.STOCK_MEDIA_PLAY, gtk.ICON_SIZE_MENU)) + menuitem.get_children()[0].set_text(_("Resume")) + else: + menuitem.set_image(gtk.image_new_from_stock(gtk.STOCK_MEDIA_PAUSE, gtk.ICON_SIZE_MENU)) + menuitem.get_children()[0].set_text(_("Pause")) + + def build_summary_tab(self): + #Torrent Summary tab + # Look into glade's widget prefix function + self.text_summary_name = self.wtree.get_widget("summary_name") + self.text_summary_total_size = self.wtree.get_widget("summary_total_size") + self.text_summary_pieces = self.wtree.get_widget("summary_pieces") + self.text_summary_total_downloaded = self.wtree.get_widget("summary_total_downloaded") + self.text_summary_total_uploaded = self.wtree.get_widget("summary_total_uploaded") + self.text_summary_download_speed = self.wtree.get_widget("summary_download_speed") + self.text_summary_upload_speed = self.wtree.get_widget("summary_upload_speed") + self.text_summary_seeders = self.wtree.get_widget("summary_seeders") + self.text_summary_peers = self.wtree.get_widget("summary_peers") + self.text_summary_percentage_done = self.wtree.get_widget("summary_percentage_done") + self.text_summary_share_ratio = self.wtree.get_widget("summary_share_ratio") + self.text_summary_downloaded_this_session = self.wtree.get_widget("summary_downloaded_this_session") + self.text_summary_uploaded_this_session = self.wtree.get_widget("summary_uploaded_this_session") + self.text_summary_tracker = self.wtree.get_widget("summary_tracker") + self.text_summary_tracker_status = self.wtree.get_widget("summary_tracker_status") + self.text_summary_next_announce = self.wtree.get_widget("summary_next_announce") + self.text_summary_eta = self.wtree.get_widget("summary_eta") - def build_peer_tab(self): - self.peer_view = self.wtree.get_widget("peer_view") - # IP int, IP string, Client, Percent Complete, Down Speed, Up Speed - # IP int is for faster sorting - self.peer_store = gtk.ListStore(gobject.TYPE_UINT, str, str, float, int, int) - def percent(column, cell, model, iter, data): - percent = float(model.get_value(iter, data)) - percent_str = "%.2f%%"%percent - cell.set_property("text", percent_str) + def build_peer_tab(self): + self.peer_view = self.wtree.get_widget("peer_view") + # IP int, IP string, Client, Percent Complete, Down Speed, Up Speed + # IP int is for faster sorting + self.peer_store = gtk.ListStore(gobject.TYPE_UINT, str, str, float, int, int) + def percent(column, cell, model, iter, data): + percent = float(model.get_value(iter, data)) + percent_str = "%.2f%%"%percent + cell.set_property("text", percent_str) - self.peer_view.set_model(self.peer_store) - - self.peer_ip_column = dgtk.add_text_column(self.peer_view, _("IP Address"), 1) - self.peer_client_column = dgtk.add_text_column(self.peer_view, _("Client"), 2) - self.peer_complete_column = dgtk.add_func_column(self.peer_view, _("Percent Complete"), percent, 3) - self.peer_download_column = dgtk.add_func_column(self.peer_view, _("Down Speed"), dgtk.cell_data_speed, 4) - self.peer_upload_column = dgtk.add_func_column(self.peer_view, _("Up Speed"), dgtk.cell_data_speed, 5) + self.peer_view.set_model(self.peer_store) + + self.peer_ip_column = dgtk.add_text_column(self.peer_view, _("IP Address"), 1) + self.peer_client_column = dgtk.add_text_column(self.peer_view, _("Client"), 2) + self.peer_complete_column = dgtk.add_func_column(self.peer_view, _("Percent Complete"), percent, 3) + self.peer_download_column = dgtk.add_func_column(self.peer_view, _("Down Speed"), dgtk.cell_data_speed, 4) + self.peer_upload_column = dgtk.add_func_column(self.peer_view, _("Up Speed"), dgtk.cell_data_speed, 5) - self.peer_ip_column.set_sort_column_id(0) + self.peer_ip_column.set_sort_column_id(0) - def build_file_tab(self): - def percent(column, cell, model, iter, data): - percent = float(model.get_value(iter, data)) - percent_str = "%.2f%%"%percent - cell.set_property("text", percent_str) + def build_file_tab(self): + def percent(column, cell, model, iter, data): + percent = float(model.get_value(iter, data)) + percent_str = "%.2f%%"%percent + cell.set_property("text", percent_str) - self.file_view = self.wtree.get_widget("file_view") - self.file_glade = gtk.glade.XML(common.get_glade_file("file_tab_menu.glade"), domain='deluge') - self.file_menu = self.file_glade.get_widget("file_tab_menu") - self.file_glade.signal_autoconnect({ "select_all": self.file_select_all, - "unselect_all": self.file_unselect_all, - "check_selected": self.file_check_selected, - "uncheck_selected": self.file_uncheck_selected, - }) - self.file_store = gtk.ListStore(bool, str, str, str, float) - self.file_view.set_model(self.file_store) - self.file_view.get_selection().set_mode(gtk.SELECTION_MULTIPLE) - self.file_view.get_selection().set_select_function(self.file_clicked) - self.file_selected = [] - self.file_view.connect("button-press-event", self.file_view_clicked) - - dgtk.add_toggle_column(self.file_view, _("Download"), 0, toggled_signal=self.file_toggled) - dgtk.add_text_column(self.file_view, _("Filename"), 1).set_expand(True) - dgtk.add_text_column(self.file_view, _("Size"), 2) - dgtk.add_text_column(self.file_view, _("Offset"), 3) - dgtk.add_func_column(self.file_view, _("Progress"), percent, 4) - - def file_select_all(self, widget): - self.file_view.get_selection().select_all() - - def file_unselect_all(self, widget): - self.file_view.get_selection().unselect_all() - - def file_check_selected(self, widget): - self.file_view.get_selection().selected_foreach(self.file_toggle_selected, True) - - def file_uncheck_selected(self, widget): - self.file_view.get_selection().selected_foreach(self.file_toggle_selected, False) - - def file_clicked(self, path): - return not self.file_selected - - def file_view_clicked(self, widget, event): - if event.button == 3: - self.file_menu.popup(None, None, None, event.button, event.time) - return True - else: - self.file_selected = False - return False - - def file_toggle_selected(self, treemodel, path, selected_iter, value): - self.file_store.set_value(selected_iter, 0, value) - - def file_toggled(self, renderer, path): - self.file_selected = True - file_iter = self.file_store.get_iter_from_string(path) - value = not renderer.get_active() - selection = self.file_view.get_selection() - if selection.iter_is_selected(file_iter): - selection.selected_foreach(self.file_toggle_selected, value) - else: - self.file_store.set_value(file_iter, 0, value) - file_filter = [] - itr = self.file_store.get_iter_first() - while itr is not None: - file_filter.append(not self.file_store.get_value(itr, 0)) - itr = self.file_store.iter_next(itr) - self.manager.set_file_filter(self.get_selected_torrent(), file_filter) - - def file_get_iter_from_name(self, name): - iter = self.file_store.get_iter_first() - while iter: - if self.file_store.get_value(iter, 1) == name: - return iter - iter = self.file_store.iter_next(iter) - - return None - - def show_about_dialog(self, arg=None): - dialogs.show_about_dialog() + self.file_view = self.wtree.get_widget("file_view") + self.file_glade = gtk.glade.XML(common.get_glade_file("file_tab_menu.glade"), domain='deluge') + self.file_menu = self.file_glade.get_widget("file_tab_menu") + self.file_glade.signal_autoconnect({ "select_all": self.file_select_all, + "unselect_all": self.file_unselect_all, + "check_selected": self.file_check_selected, + "uncheck_selected": self.file_uncheck_selected, + }) + self.file_store = gtk.ListStore(bool, str, str, str, float) + self.file_view.set_model(self.file_store) + self.file_view.get_selection().set_mode(gtk.SELECTION_MULTIPLE) + self.file_view.get_selection().set_select_function(self.file_clicked) + self.file_selected = [] + self.file_view.connect("button-press-event", self.file_view_clicked) + + dgtk.add_toggle_column(self.file_view, _("Download"), 0, toggled_signal=self.file_toggled) + dgtk.add_text_column(self.file_view, _("Filename"), 1).set_expand(True) + dgtk.add_text_column(self.file_view, _("Size"), 2) + dgtk.add_text_column(self.file_view, _("Offset"), 3) + dgtk.add_func_column(self.file_view, _("Progress"), percent, 4) + + def file_select_all(self, widget): + self.file_view.get_selection().select_all() + + def file_unselect_all(self, widget): + self.file_view.get_selection().unselect_all() + + def file_check_selected(self, widget): + self.file_view.get_selection().selected_foreach(self.file_toggle_selected, True) + + def file_uncheck_selected(self, widget): + self.file_view.get_selection().selected_foreach(self.file_toggle_selected, False) + + def file_clicked(self, path): + return not self.file_selected + + def file_view_clicked(self, widget, event): + if event.button == 3: + self.file_menu.popup(None, None, None, event.button, event.time) + return True + else: + self.file_selected = False + return False + + def file_toggle_selected(self, treemodel, path, selected_iter, value): + self.file_store.set_value(selected_iter, 0, value) + + def file_toggled(self, renderer, path): + self.file_selected = True + file_iter = self.file_store.get_iter_from_string(path) + value = not renderer.get_active() + selection = self.file_view.get_selection() + if selection.iter_is_selected(file_iter): + selection.selected_foreach(self.file_toggle_selected, value) + else: + self.file_store.set_value(file_iter, 0, value) + file_filter = [] + itr = self.file_store.get_iter_first() + while itr is not None: + file_filter.append(not self.file_store.get_value(itr, 0)) + itr = self.file_store.iter_next(itr) + self.manager.set_file_filter(self.get_selected_torrent(), file_filter) + + def file_get_iter_from_name(self, name): + iter = self.file_store.get_iter_first() + while iter: + if self.file_store.get_value(iter, 1) == name: + return iter + iter = self.file_store.iter_next(iter) + + return None + + def show_about_dialog(self, arg=None): + dialogs.show_about_dialog() - def show_pref_dialog(self, arg=None): - if self.window.get_property("visible"): - # Only apply the prefs if the user pressed OK in the prefs dialog - if self.preferences_dialog.show() == 1: - self.apply_prefs() - self.config.save() + def show_pref_dialog(self, arg=None): + if self.window.get_property("visible"): + # Only apply the prefs if the user pressed OK in the prefs dialog + if self.preferences_dialog.show() == 1: + self.apply_prefs() + self.config.save() - else: - if self.config.get("lock_tray") == True: - self.unlock_tray("prefwinshow") - else: - # Only apply the prefs if the user pressed OK in the prefs dialog - if self.preferences_dialog.show() == 1: - self.apply_prefs() - self.config.save() - - def show_plugin_dialog(self, arg=None): - self.plugin_dialog.show() - - def apply_prefs(self): - # Show tray icon if necessary - self.tray_icon.set_visible(self.config.get("enable_system_tray")) - - # Update the max_*_speed_bps prefs - if self.config.get("max_upload_speed") < 0: - self.config.set("max_upload_speed_bps", -1) - else: - self.config.set("max_upload_speed_bps", - int(self.config.get("max_upload_speed") * 1024)) + else: + if self.config.get("lock_tray") == True: + self.unlock_tray("prefwinshow") + else: + # Only apply the prefs if the user pressed OK in the prefs dialog + if self.preferences_dialog.show() == 1: + self.apply_prefs() + self.config.save() + + def show_plugin_dialog(self, arg=None): + self.plugin_dialog.show() + + def apply_prefs(self): + # Show tray icon if necessary + self.tray_icon.set_visible(self.config.get("enable_system_tray")) + + # Update the max_*_speed_bps prefs + if self.config.get("max_upload_speed") < 0: + self.config.set("max_upload_speed_bps", -1) + else: + self.config.set("max_upload_speed_bps", + int(self.config.get("max_upload_speed") * 1024)) - if self.config.get("max_download_speed") < 0: - self.config.set("max_download_speed_bps", -1) - else: - self.config.set("max_download_speed_bps", - int(self.config.get("max_download_speed") * 1024)) - - # Update the tray download speed limits - if self.config.get("max_download_speed") not in self.config.get("tray_downloadspeedlist") and \ - self.config.get("max_download_speed") >= 0: - # We need to prepend this value and remove the last value in the list - self.config.get("tray_downloadspeedlist").insert(0, self.config.get("max_download_speed")) - self.config.get("tray_downloadspeedlist").pop() + if self.config.get("max_download_speed") < 0: + self.config.set("max_download_speed_bps", -1) + else: + self.config.set("max_download_speed_bps", + int(self.config.get("max_download_speed") * 1024)) + + # Update the tray download speed limits + if self.config.get("max_download_speed") not in self.config.get("tray_downloadspeedlist") and \ + self.config.get("max_download_speed") >= 0: + # We need to prepend this value and remove the last value in the list + self.config.get("tray_downloadspeedlist").insert(0, self.config.get("max_download_speed")) + self.config.get("tray_downloadspeedlist").pop() - # Do the same for the upload speed limits - if self.config.get("max_upload_speed") not in self.config.get("tray_uploadspeedlist") and \ - self.config.get("max_upload_speed") >= 0: - # We need to prepend this value and remove the last value in the list - self.config.get("tray_uploadspeedlist").insert(0, self.config.get("max_upload_speed")) - self.config.get("tray_uploadspeedlist").pop() + # Do the same for the upload speed limits + if self.config.get("max_upload_speed") not in self.config.get("tray_uploadspeedlist") and \ + self.config.get("max_upload_speed") >= 0: + # We need to prepend this value and remove the last value in the list + self.config.get("tray_uploadspeedlist").insert(0, self.config.get("max_upload_speed")) + self.config.get("tray_uploadspeedlist").pop() - # Re-build the tray sub-menu to display the correct active radio item - self.build_tray_bwsetsubmenu() - - # Apply the preferences in the core - self.manager.apply_prefs() - self.manager.pe_settings(self.config.get("encout_state"), self.config.get("encin_state"), self.config.get("enclevel_type"), self.config.get("pref_rc4")) - self.manager.proxy_settings(self.config.get("proxy_hostname"), self.config.get("proxy_username"), self.config.get("proxy_password"), int(self.config.get("proxy_port")), self.config.get("proxy_type"), self.config.get("peer_proxy"), self.config.get("tracker_proxy"), self.config.get("dht_proxy")) + # Re-build the tray sub-menu to display the correct active radio item + self.build_tray_bwsetsubmenu() + + # Apply the preferences in the core + self.manager.apply_prefs() + self.manager.pe_settings(self.config.get("encout_state"), self.config.get("encin_state"), self.config.get("enclevel_type"), self.config.get("pref_rc4")) + self.manager.proxy_settings(self.config.get("proxy_hostname"), self.config.get("proxy_username"), self.config.get("proxy_password"), int(self.config.get("proxy_port")), self.config.get("proxy_type"), self.config.get("peer_proxy"), self.config.get("tracker_proxy"), self.config.get("dht_proxy")) - def get_message_from_state(self, torrent_state): - state = torrent_state['state'] - is_paused = torrent_state['is_paused'] - progress = torrent_state['progress'] - progress = '%d%%'%int(progress * 100) - if is_paused: - message = _("Paused %s")%progress - else: - try: - message = _(core.STATE_MESSAGES[state]) - if state in (1, 3, 4, 7): - message = '%s %s'%(message, progress) - except IndexError: - message = '' - return message - - # UID, Q#, Name, Size, Progress, Message, Seeders, Peers, DL, UL, ETA, Share - def get_list_from_unique_id(self, unique_id): - state = self.manager.get_torrent_state(unique_id) - - queue = int(state['queue_pos']) + 1 - name = state['name'] - size = long(state['total_size']) - progress = float(state['progress'] * 100) - message = self.get_message_from_state(state) - seeds = int(state['num_seeds']) - seeds_t = int(state['total_seeds']) - peers = int(state['num_peers']) - peers_t = int(state['total_peers']) - dl_speed = int(state['download_rate']) - ul_speed = int(state['upload_rate']) - try: - eta = common.get_eta(state["total_size"], state["total_done"], state["download_rate"]) - except ZeroDivisionError: - eta = 0 - share = float(self.calc_share_ratio(unique_id, state)) - - # Set the appropriate status icon - if state["is_paused"]: - status_icon = gtk.gdk.pixbuf_new_from_file(common.get_pixmap("inactive16.png")) - elif state["is_seed"]: - status_icon = gtk.gdk.pixbuf_new_from_file(common.get_pixmap("seeding16.png")) - else: - status_icon = gtk.gdk.pixbuf_new_from_file(common.get_pixmap("downloading16.png")) - - rlist = [int(unique_id), queue, status_icon, name, size, progress, message, - seeds, seeds_t, peers, peers_t, dl_speed, ul_speed, int(eta), share] + def get_message_from_state(self, torrent_state): + state = torrent_state['state'] + is_paused = torrent_state['is_paused'] + progress = torrent_state['progress'] + progress = '%d%%'%int(progress * 100) + if is_paused: + message = _("Paused %s")%progress + else: + try: + message = _(core.STATE_MESSAGES[state]) + if state in (1, 3, 4, 7): + message = '%s %s'%(message, progress) + except IndexError: + message = '' + return message + + # UID, Q#, Name, Size, Progress, Message, Seeders, Peers, DL, UL, ETA, Share + def get_list_from_unique_id(self, unique_id): + state = self.manager.get_torrent_state(unique_id) + + queue = int(state['queue_pos']) + 1 + name = state['name'] + size = long(state['total_size']) + progress = float(state['progress'] * 100) + message = self.get_message_from_state(state) + seeds = int(state['num_seeds']) + seeds_t = int(state['total_seeds']) + peers = int(state['num_peers']) + peers_t = int(state['total_peers']) + dl_speed = int(state['download_rate']) + ul_speed = int(state['upload_rate']) + try: + eta = common.get_eta(state["total_size"], state["total_done"], state["download_rate"]) + except ZeroDivisionError: + eta = 0 + share = float(self.calc_share_ratio(unique_id, state)) + + # Set the appropriate status icon + if state["is_paused"]: + status_icon = gtk.gdk.pixbuf_new_from_file(common.get_pixmap("inactive16.png")) + elif state["is_seed"]: + status_icon = gtk.gdk.pixbuf_new_from_file(common.get_pixmap("seeding16.png")) + else: + status_icon = gtk.gdk.pixbuf_new_from_file(common.get_pixmap("downloading16.png")) + + rlist = [int(unique_id), queue, status_icon, name, size, progress, message, + seeds, seeds_t, peers, peers_t, dl_speed, ul_speed, int(eta), share] - return rlist - + return rlist + - ## Start the timer that updates the interface - def start(self, start_in_tray=False): - if not(start_in_tray and self.config.get("enable_system_tray") and - self.has_tray) and not self.window.get_property("visible"): - print "Showing window" - self.window.show() - # go through torrent files to add - #dummy preferences values: - use_default_download_location = True - default_download_location = "." - for torrent_file in self.torrent_file_queue: - print "adding torrent", torrent_file - try: - self.interactive_add_torrent(torrent_file, append=False) - except core.DelugeError: - print "duplicate torrent found, ignoring", torrent_file - ## add torrents in manager to interface - # self.torrent_model.append([0, 1, "Hello, World", 2048, 50.0, "Hi", 1, 2, 1, 2, 2048, 2048, 120, 1.0]) - for uid in self.manager.get_unique_IDs(): - self.torrent_model.append(self.get_list_from_unique_id(uid)) - # Call update now so everything is up-to-date when the window gains focus on startup - self.update() - - gobject.timeout_add(1000, self.update) - try: - self.is_running = True - gtk.main() - except KeyboardInterrupt: - self.manager.quit() + ## Start the timer that updates the interface + def start(self, start_in_tray=False): + if not(start_in_tray and self.config.get("enable_system_tray") and + self.has_tray) and not self.window.get_property("visible"): + print "Showing window" + self.window.show() + # go through torrent files to add + #dummy preferences values: + use_default_download_location = True + default_download_location = "." + for torrent_file in self.torrent_file_queue: + print "adding torrent", torrent_file + try: + self.interactive_add_torrent(torrent_file, append=False) + except core.DelugeError: + print "duplicate torrent found, ignoring", torrent_file + ## add torrents in manager to interface + # self.torrent_model.append([0, 1, "Hello, World", 2048, 50.0, "Hi", 1, 2, 1, 2, 2048, 2048, 120, 1.0]) + for uid in self.manager.get_unique_IDs(): + self.torrent_model.append(self.get_list_from_unique_id(uid)) + # Call update now so everything is up-to-date when the window gains focus on startup + self.update() + + gobject.timeout_add(1000, self.update) + try: + self.is_running = True + gtk.main() + except KeyboardInterrupt: + self.manager.quit() - def load_plugins(self): - enable_plugins = self.config.get('enabled_plugins').split(':') - for plugin in enable_plugins: - try: - self.plugins.enable_plugin(plugin) - except KeyError: - pass + def load_plugins(self): + enable_plugins = self.config.get('enabled_plugins').split(':') + for plugin in enable_plugins: + try: + self.plugins.enable_plugin(plugin) + except KeyError: + pass - ## Call via a timer to update the interface - def update(self): - self.update_queue.reverse() - while len(self.update_queue) > 0: - f = self.update_queue.pop() - f() - - # We need to apply the queue changes - self.manager.apply_queue() - - # Handle the events - self.manager.handle_events() - - # Make sure that the interface still exists - try: - tab = self.wtree.get_widget("torrent_info").get_current_page() - except AttributeError: - return False - - if self.something_screwed_up: - dialogs.show_popup_warning(self.window, - _("For some reason, the previous state could not be loaded, so a blank state has been loaded for you.")) - restore_torrents = dialogs.show_popup_question(self.window, - _("Would you like to attempt to reload the previous session's downloads?")) - if restore_torrents: - torrent_subdir = os.path.join(self.manager.base_dir, core.TORRENTS_SUBDIR) - for torrent in os.listdir(torrent_subdir): - if torrent.endswith('.torrent'): - self.interactive_add_torrent(torrent) - self.something_screwed_up = False - - # Update Statusbar and Tray Tips - core_state = self.manager.get_state() - connections = core_state['num_peers'] - if self.config.get("max_connections") < 0 : - max_connections = _("Unlimited") - else: - max_connections = int(self.config.get("max_connections")) - dlspeed = common.fspeed(core_state['download_rate']) - ulspeed = common.fspeed(core_state['upload_rate']) - if self.config.get("max_download_speed") < 0: - dlspeed_max = _("Unlimited") - else: - dlspeed_max = common.fspeed(self.config.get("max_download_speed_bps")) - if self.config.get("max_upload_speed") < 0: - ulspeed_max = _("Unlimited") - else: - ulspeed_max = common.fspeed(self.config.get("max_upload_speed_bps")) - - self.statusbar_temp_msg = '%s: %s (%s) %s: %s (%s) %s: %s (%s)'%( - _('Connections'), connections, max_connections, _('Down Speed'), - dlspeed, dlspeed_max, _('Up Speed'), ulspeed, ulspeed_max) - - if 'DHT_nodes' in core_state.keys(): - dht_peers = core_state['DHT_nodes'] - if dht_peers == -1: - dht_peers = '?' - else: - dht_peers = str(dht_peers) - self.statusbar_temp_msg = self.statusbar_temp_msg + ' [DHT: %s]'%(dht_peers) - - msg = _("Deluge Bittorrent Client") + "\n" + \ - _("Connections") + ": " + str(connections) + " (" + str(max_connections) + ")" + "\n" + _("Down Speed") + ": " + \ - dlspeed + " (" + dlspeed_max + ")" + "\n" + _("Up Speed") + ": " + ulspeed + " (" + ulspeed_max + ")" - - self.tray_icon.set_tooltip(msg) + ## Call via a timer to update the interface + def update(self): + self.update_queue.reverse() + while len(self.update_queue) > 0: + f = self.update_queue.pop() + f() + + # We need to apply the queue changes + self.manager.apply_queue() + + # Handle the events + self.manager.handle_events() + + # Make sure that the interface still exists + try: + tab = self.wtree.get_widget("torrent_info").get_current_page() + except AttributeError: + return False + + if self.something_screwed_up: + dialogs.show_popup_warning(self.window, + _("For some reason, the previous state could not be loaded, so a blank state has been loaded for you.")) + restore_torrents = dialogs.show_popup_question(self.window, + _("Would you like to attempt to reload the previous session's downloads?")) + if restore_torrents: + torrent_subdir = os.path.join(self.manager.base_dir, core.TORRENTS_SUBDIR) + for torrent in os.listdir(torrent_subdir): + if torrent.endswith('.torrent'): + self.interactive_add_torrent(torrent) + self.something_screwed_up = False + + # Update Statusbar and Tray Tips + core_state = self.manager.get_state() + connections = core_state['num_peers'] + if self.config.get("max_connections") < 0 : + max_connections = _("Unlimited") + else: + max_connections = int(self.config.get("max_connections")) + dlspeed = common.fspeed(core_state['download_rate']) + ulspeed = common.fspeed(core_state['upload_rate']) + if self.config.get("max_download_speed") < 0: + dlspeed_max = _("Unlimited") + else: + dlspeed_max = common.fspeed(self.config.get("max_download_speed_bps")) + if self.config.get("max_upload_speed") < 0: + ulspeed_max = _("Unlimited") + else: + ulspeed_max = common.fspeed(self.config.get("max_upload_speed_bps")) + + self.statusbar_temp_msg = '%s: %s (%s) %s: %s (%s) %s: %s (%s)'%( + _('Connections'), connections, max_connections, _('Down Speed'), + dlspeed, dlspeed_max, _('Up Speed'), ulspeed, ulspeed_max) + + if 'DHT_nodes' in core_state.keys(): + dht_peers = core_state['DHT_nodes'] + if dht_peers == -1: + dht_peers = '?' + else: + dht_peers = str(dht_peers) + self.statusbar_temp_msg = self.statusbar_temp_msg + ' [DHT: %s]'%(dht_peers) + + msg = _("Deluge Bittorrent Client") + "\n" + \ + _("Connections") + ": " + str(connections) + " (" + str(max_connections) + ")" + "\n" + _("Down Speed") + ": " + \ + dlspeed + " (" + dlspeed_max + ")" + "\n" + _("Up Speed") + ": " + ulspeed + " (" + ulspeed_max + ")" + + self.tray_icon.set_tooltip(msg) - #Update any active plugins - self.plugins.update_active_plugins() - - # Put the generated message into the statusbar - # This gives plugins a chance to write to the - # statusbar if they want - self.statusbar.pop(1) - self.statusbar.push(1, self.statusbar_temp_msg) + #Update any active plugins + self.plugins.update_active_plugins() + + # Put the generated message into the statusbar + # This gives plugins a chance to write to the + # statusbar if they want + self.statusbar.pop(1) + self.statusbar.push(1, self.statusbar_temp_msg) - # If no torrent is selected, select the first torrent: - if self.torrent_selected is None: - self.torrent_view.get_selection().select_path("0") - #Torrent List - itr = self.torrent_model.get_iter_first() - if itr is None: - return True + # If no torrent is selected, select the first torrent: + if self.torrent_selected is None: + self.torrent_view.get_selection().select_path("0") + #Torrent List + itr = self.torrent_model.get_iter_first() + if itr is None: + return True - while itr is not None: - uid = self.torrent_model.get_value(itr, 0) - try: - state = self.manager.get_torrent_state(uid) - tlist = self.get_list_from_unique_id(uid) - for i in range(len(tlist)): - try: - self.torrent_model.set_value(itr, i, tlist[i]) - except: - print "ERR", i, type(tlist[i]), tlist[i] - itr = self.torrent_model.iter_next(itr) - except core.InvalidUniqueIDError: - self.torrent_model.remove(itr) - if not self.torrent_model.iter_is_valid(itr): - itr = None + while itr is not None: + uid = self.torrent_model.get_value(itr, 0) + try: + state = self.manager.get_torrent_state(uid) + tlist = self.get_list_from_unique_id(uid) + for i in range(len(tlist)): + try: + self.torrent_model.set_value(itr, i, tlist[i]) + except: + print "ERR", i, type(tlist[i]), tlist[i] + itr = self.torrent_model.iter_next(itr) + except core.InvalidUniqueIDError: + self.torrent_model.remove(itr) + if not self.torrent_model.iter_is_valid(itr): + itr = None - # Disable torrent options if no torrents are selected - torrent_selection = self.torrent_view.get_selection() - selection_count = torrent_selection.count_selected_rows() - - self.wtree.get_widget("menu_torrent").set_sensitive(selection_count > 0) - self.wtree.get_widget("toolbutton_remove").set_sensitive(selection_count > 0) - self.wtree.get_widget("toolbutton_pause").set_sensitive(selection_count > 0) - self.wtree.get_widget("toolbutton_up").set_sensitive(selection_count > 0) - self.wtree.get_widget("toolbutton_down").set_sensitive(selection_count > 0) - - # Disable moving top torrents up or bottom torrents down - top_torrents_selected = True - bottom_torrents_selected = True - - for i in range(selection_count): - if not torrent_selection.path_is_selected(i): - top_torrents_selected = False - - if not torrent_selection.path_is_selected(len(self.torrent_model) - 1 - i): - bottom_torrents_selected = False - - self.torrent_glade.get_widget("menu_queue_top").set_sensitive(not top_torrents_selected) - self.torrent_glade.get_widget("menu_queue_up").set_sensitive(not top_torrents_selected) - self.torrent_glade.get_widget("menu_queue_down").set_sensitive(not bottom_torrents_selected) - self.torrent_glade.get_widget("menu_queue_bottom").set_sensitive(not bottom_torrents_selected) - self.wtree.get_widget("toolbutton_up").set_sensitive(not top_torrents_selected) - self.wtree.get_widget("toolbutton_down").set_sensitive(not bottom_torrents_selected) - - if selection_count == 0: - return True + # Disable torrent options if no torrents are selected + torrent_selection = self.torrent_view.get_selection() + selection_count = torrent_selection.count_selected_rows() + + self.wtree.get_widget("menu_torrent").set_sensitive(selection_count > 0) + self.wtree.get_widget("toolbutton_remove").set_sensitive(selection_count > 0) + self.wtree.get_widget("toolbutton_pause").set_sensitive(selection_count > 0) + self.wtree.get_widget("toolbutton_up").set_sensitive(selection_count > 0) + self.wtree.get_widget("toolbutton_down").set_sensitive(selection_count > 0) + + # Disable moving top torrents up or bottom torrents down + top_torrents_selected = True + bottom_torrents_selected = True + + for i in range(selection_count): + if not torrent_selection.path_is_selected(i): + top_torrents_selected = False + + if not torrent_selection.path_is_selected(len(self.torrent_model) - 1 - i): + bottom_torrents_selected = False + + self.torrent_glade.get_widget("menu_queue_top").set_sensitive(not top_torrents_selected) + self.torrent_glade.get_widget("menu_queue_up").set_sensitive(not top_torrents_selected) + self.torrent_glade.get_widget("menu_queue_down").set_sensitive(not bottom_torrents_selected) + self.torrent_glade.get_widget("menu_queue_bottom").set_sensitive(not bottom_torrents_selected) + self.wtree.get_widget("toolbutton_up").set_sensitive(not top_torrents_selected) + self.wtree.get_widget("toolbutton_down").set_sensitive(not bottom_torrents_selected) + + if selection_count == 0: + return True - try: - if self.manager.get_torrent_state(self.get_selected_torrent())["is_paused"]: - self.wtree.get_widget("toolbutton_pause").set_stock_id(gtk.STOCK_MEDIA_PLAY) - self.wtree.get_widget("toolbutton_pause").set_label(_("Resume")) - else: - self.wtree.get_widget("toolbutton_pause").set_stock_id(gtk.STOCK_MEDIA_PAUSE) - self.wtree.get_widget("toolbutton_pause").set_label(_("Pause")) + try: + if self.manager.get_torrent_state(self.get_selected_torrent())["is_paused"]: + self.wtree.get_widget("toolbutton_pause").set_stock_id(gtk.STOCK_MEDIA_PLAY) + self.wtree.get_widget("toolbutton_pause").set_label(_("Resume")) + else: + self.wtree.get_widget("toolbutton_pause").set_stock_id(gtk.STOCK_MEDIA_PAUSE) + self.wtree.get_widget("toolbutton_pause").set_label(_("Pause")) - except KeyError: - pass - - try: - state = self.manager.get_torrent_state(self.get_selected_torrent()) - except core.InvalidUniqueIDError: - return True + except KeyError: + pass + + try: + state = self.manager.get_torrent_state(self.get_selected_torrent()) + except core.InvalidUniqueIDError: + return True - - if tab == 0: #Details Pane - self.wtree.get_widget("summary_name").set_text(state['name']) - self.text_summary_total_size.set_text(common.fsize(state["total_size"])) - self.text_summary_pieces.set_text(str(state["num_pieces"])) - self.text_summary_total_downloaded.set_text(common.fsize(state["total_done"]) + " (" + common.fsize(state["total_download"]) + ")") - self.text_summary_total_uploaded.set_text(common.fsize(self.manager.unique_IDs[self.get_selected_torrent()].uploaded_memory + state["total_payload_upload"]) + " (" + common.fsize(state["total_upload"]) + ")") - self.text_summary_download_speed.set_text(common.fspeed(state["download_rate"])) - self.text_summary_upload_speed.set_text(common.fspeed(state["upload_rate"])) - self.text_summary_seeders.set_text(common.fseed(state)) - self.text_summary_peers.set_text(common.fpeer(state)) - self.wtree.get_widget("progressbar").set_fraction(float(state['progress'])) - self.wtree.get_widget("progressbar").set_text(common.fpcnt(state["progress"])) - self.text_summary_share_ratio.set_text('%.3f'%(self.calc_share_ratio(self.get_selected_torrent(), state))) - self.text_summary_tracker.set_text(str(state["tracker"])) - self.text_summary_tracker_status.set_text(str(state["tracker_ok"])) - self.text_summary_next_announce.set_text(str(state["next_announce"])) - self.text_summary_eta.set_text(common.estimate_eta(state)) - elif tab == 1: #Peers List - def biographer(model, path, iter, dictionary): - assert(model.get_value(iter, 1) not in dictionary.keys()) - dictionary[model.get_value(iter, 1)] = model.get_string_from_iter(iter) - - class remover_data: - def __init__(self, new_ips): - self.new_ips = new_ips - self.removed = False - - def remover(model, path, iter, data): - if model.get_value(iter, 1) not in data.new_ips: - model.remove(iter) - data.removed = True - return True - else: - return False + + if tab == 0: #Details Pane + self.wtree.get_widget("summary_name").set_text(state['name']) + self.text_summary_total_size.set_text(common.fsize(state["total_size"])) + self.text_summary_pieces.set_text(str(state["num_pieces"])) + self.text_summary_total_downloaded.set_text(common.fsize(state["total_done"]) + " (" + common.fsize(state["total_download"]) + ")") + self.text_summary_total_uploaded.set_text(common.fsize(self.manager.unique_IDs[self.get_selected_torrent()].uploaded_memory + state["total_payload_upload"]) + " (" + common.fsize(state["total_upload"]) + ")") + self.text_summary_download_speed.set_text(common.fspeed(state["download_rate"])) + self.text_summary_upload_speed.set_text(common.fspeed(state["upload_rate"])) + self.text_summary_seeders.set_text(common.fseed(state)) + self.text_summary_peers.set_text(common.fpeer(state)) + self.wtree.get_widget("progressbar").set_fraction(float(state['progress'])) + self.wtree.get_widget("progressbar").set_text(common.fpcnt(state["progress"])) + self.text_summary_share_ratio.set_text('%.3f'%(self.calc_share_ratio(self.get_selected_torrent(), state))) + self.text_summary_tracker.set_text(str(state["tracker"])) + self.text_summary_tracker_status.set_text(str(state["tracker_ok"])) + self.text_summary_next_announce.set_text(str(state["next_announce"])) + self.text_summary_eta.set_text(common.estimate_eta(state)) + elif tab == 1: #Peers List + def biographer(model, path, iter, dictionary): + assert(model.get_value(iter, 1) not in dictionary.keys()) + dictionary[model.get_value(iter, 1)] = model.get_string_from_iter(iter) + + class remover_data: + def __init__(self, new_ips): + self.new_ips = new_ips + self.removed = False + + def remover(model, path, iter, data): + if model.get_value(iter, 1) not in data.new_ips: + model.remove(iter) + data.removed = True + return True + else: + return False - unique_id = self.get_selected_torrent() - - new_peer_info = self.manager.get_torrent_peer_info(unique_id) - - new_ips = {} - - for index in range(len(new_peer_info)): - if not new_peer_info[index]['client'] == "": - assert(new_peer_info[index]['ip'] not in new_ips.keys()) - new_ips[new_peer_info[index]['ip']] = index - - while True: - data = remover_data(new_ips.keys()) - self.peer_store.foreach(remover, data) - if not data.removed: - break - - curr_ips = {} - - self.peer_store.foreach(biographer, curr_ips) - - assert(self.peer_store.iter_n_children(None) == len(curr_ips.keys())) - - for peer in new_peer_info: - if peer['ip'] in curr_ips.keys(): - self.peer_store.set(self.peer_store.get_iter_from_string(curr_ips[peer['ip']]), - 2, unicode(peer['client'], "latin-1"), - 3, round(peer["peer_has"],2), - 4, peer["download_speed"], - 5, peer["upload_speed"]) + unique_id = self.get_selected_torrent() + + new_peer_info = self.manager.get_torrent_peer_info(unique_id) + + new_ips = {} + + for index in range(len(new_peer_info)): + if not new_peer_info[index]['client'] == "": + assert(new_peer_info[index]['ip'] not in new_ips.keys()) + new_ips[new_peer_info[index]['ip']] = index + + while True: + data = remover_data(new_ips.keys()) + self.peer_store.foreach(remover, data) + if not data.removed: + break + + curr_ips = {} + + self.peer_store.foreach(biographer, curr_ips) + + assert(self.peer_store.iter_n_children(None) == len(curr_ips.keys())) + + for peer in new_peer_info: + if peer['ip'] in curr_ips.keys(): + self.peer_store.set(self.peer_store.get_iter_from_string(curr_ips[peer['ip']]), + 2, unicode(peer['client'], "latin-1"), + 3, round(peer["peer_has"],2), + 4, peer["download_speed"], + 5, peer["upload_speed"]) - if peer['ip'] not in curr_ips.keys() and peer['client'] is not "": - # convert IP adrress to int for sorting purposes - ip_int = sum([int(byte) << shift - for byte, shift in izip(peer["ip"].split("."), (24, 16, 8, 0))]) + if peer['ip'] not in curr_ips.keys() and peer['client'] is not "": + # convert IP adrress to int for sorting purposes + ip_int = sum([int(byte) << shift + for byte, shift in izip(peer["ip"].split("."), (24, 16, 8, 0))]) - self.peer_store.append([ip_int, peer["ip"], - unicode(peer["client"], "latin-1"), - round(peer["peer_has"],2), - peer["download_speed"], - peer["upload_speed"]]) + self.peer_store.append([ip_int, peer["ip"], + unicode(peer["client"], "latin-1"), + round(peer["peer_has"],2), + peer["download_speed"], + peer["upload_speed"]]) - del new_peer_info - del new_ips - del curr_ips - - - elif tab == 2: #file tab + del new_peer_info + del new_ips + del curr_ips + + + elif tab == 2: #file tab + unique_id = self.get_selected_torrent() + new_file_info = self.manager.get_torrent_file_info(unique_id) + for file in new_file_info: + iter = self.file_get_iter_from_name(file['path']) + if (iter != None) and (round(self.file_store.get_value(iter, 4),2) != round(file['progress'],2)): + self.file_store.set_value(iter, 4, round(file['progress'],2)) + return True - unique_id = self.get_selected_torrent() + else: + pass - new_file_info = self.manager.get_torrent_file_info(unique_id) + return True + + def calc_share_ratio(self, unique_id, torrent_state): + r = float(self.manager.calc_ratio(unique_id, torrent_state)) + return r + + # Return the id of the last single selected torrent + def get_selected_torrent(self): + try: + if self.torrent_view.get_selection().count_selected_rows() == 1: + self.torrent_selected = self.torrent_view.get_selection().get_selected_rows()[1][0] + selected_torrent = self.torrent_model.get_value(self.torrent_model.get_iter(self.torrent_selected), 0) + return selected_torrent + except TypeError, ValueError: + return None + + # Return a list of ids of the selected torrents + def get_selected_torrent_rows(self): + selected_ids = [] + selected_paths = self.torrent_view.get_selection().get_selected_rows()[1] + + try: + for path in selected_paths: + selected_ids.append(self.torrent_model.get_value(self.torrent_model.get_iter(path), 0)) + return selected_ids + except ValueError: + return None + + def on_drag_data(self, widget, drag_context, x, y, selection_data, info, timestamp): + uri_split = selection_data.data.strip().split() + for uri in uri_split: + path = urllib.url2pathname(uri).strip('\r\n\x00') + if path.startswith('file:\\\\\\'): + path = path[8:] + elif path.startswith('file://'): + path = path[7:] + elif path.startswith('file:'): + path = path[5:] + if path.endswith('.torrent'): + self.interactive_add_torrent(path) + + def interactive_add_torrent(self, torrent, append=True): + if self.config.get('use_default_dir'): + path = self.config.get('default_download_path') + else: + path = dialogs.show_directory_chooser_dialog(self.window) + if path is None: + return + try: + unique_id = self.manager.add_torrent(torrent, path, self.config.get('use_compact_storage')) + + if append: + self.torrent_model.append(self.get_list_from_unique_id(unique_id)) + except core.InvalidEncodingError, e: + print "InvalidEncodingError", e + dialogs.show_popup_warning(self.window, _("An error occured while trying to add the torrent. It's possible your .torrent file is corrupted.")) + except core.DuplicateTorrentError, e: + dialogs.show_popup_warning(self.window, _("The torrent you've added seems to already be in Deluge.")) + except core.InsufficientFreeSpaceError, e: + nice_need = common.fsize(e.needed_space) + nice_free = common.fsize(e.free_space) + dialogs.show_popup_warning(self.window, _("There is not enough free disk space to complete your download.") + "\n" + \ + _("Space Needed:") + " " + nice_need + "\n" + \ + _("Available Space:") + " " + nice_free) + + def launchpad(self, obj=None): + common.open_url_in_browser('self', 'https://translations.launchpad.net/deluge/trunk/+pots/deluge') + + def add_torrent_clicked(self, obj=None): + torrent = dialogs.show_file_open_dialog() + if torrent is not None: + for single in torrent: + self.interactive_add_torrent(single) - for file in new_file_info: - iter = self.file_get_iter_from_name(file['path']) - if (iter != None) and (round(self.file_store.get_value(iter, 4),2) != round(file['progress'],2)): - self.file_store.set_value(iter, 4, round(file['progress'],2)) + def add_torrent_url_clicked(self, obj=None): + dlg = gtk.Dialog(title=_("Add torrent from URL"), parent=self.window, + buttons=(gtk.STOCK_CANCEL, 0, gtk.STOCK_OK, 1)) + dlg.set_icon_from_file(common.get_pixmap("deluge32.png")) + + label = gtk.Label(_("Enter the URL of the .torrent to download")) + entry = gtk.Entry() + dlg.vbox.pack_start(label) + dlg.vbox.pack_start(entry) + clip = gtk.clipboard_get(selection='PRIMARY') + text = clip.wait_for_text() + #watch out for an empty clipboard, TODO check for non url garbage + if text: + entry.set_text(text) + dlg.show_all() + result = dlg.run() + url = entry.get_text() + dlg.destroy() + + if result == 1: + self.add_torrent_url(url) - return True + def external_add_url(self, url): + print "Got URL externally:", url + if self.is_running: + print "\t\tthe client seems to already be running, i'll try and add the URL" + self.add_torrent_url(url) + else: + print "\t\tthe client hasn't started yet, I'll queue the URL torrent file" + self.queue_torrent_url(url) - else: - pass + def add_torrent_url(self, url): + filename, headers = self.fetch_url(url) + if filename: + self.interactive_add_torrent(filename) - return True - - def calc_share_ratio(self, unique_id, torrent_state): - r = float(self.manager.calc_ratio(unique_id, torrent_state)) - return r - - # Return the id of the last single selected torrent - def get_selected_torrent(self): - try: - if self.torrent_view.get_selection().count_selected_rows() == 1: - self.torrent_selected = self.torrent_view.get_selection().get_selected_rows()[1][0] - selected_torrent = self.torrent_model.get_value(self.torrent_model.get_iter(self.torrent_selected), 0) - return selected_torrent - except TypeError, ValueError: - return None - - # Return a list of ids of the selected torrents - def get_selected_torrent_rows(self): - selected_ids = [] - selected_paths = self.torrent_view.get_selection().get_selected_rows()[1] - - try: - for path in selected_paths: - selected_ids.append(self.torrent_model.get_value(self.torrent_model.get_iter(path), 0)) - return selected_ids - except ValueError: - return None - - def on_drag_data(self, widget, drag_context, x, y, selection_data, info, timestamp): - uri_split = selection_data.data.strip().split() - for uri in uri_split: - path = urllib.url2pathname(uri).strip('\r\n\x00') - if path.startswith('file:\\\\\\'): - path = path[8:] - elif path.startswith('file://'): - path = path[7:] - elif path.startswith('file:'): - path = path[5:] - if path.endswith('.torrent'): - self.interactive_add_torrent(path) - - def interactive_add_torrent(self, torrent, append=True): - if self.config.get('use_default_dir'): - path = self.config.get('default_download_path') - else: - path = dialogs.show_directory_chooser_dialog(self.window) - if path is None: - return - try: - unique_id = self.manager.add_torrent(torrent, path, self.config.get('use_compact_storage')) - - if append: - self.torrent_model.append(self.get_list_from_unique_id(unique_id)) - except core.InvalidEncodingError, e: - print "InvalidEncodingError", e - dialogs.show_popup_warning(self.window, _("An error occured while trying to add the torrent. It's possible your .torrent file is corrupted.")) - except core.DuplicateTorrentError, e: - dialogs.show_popup_warning(self.window, _("The torrent you've added seems to already be in Deluge.")) - except core.InsufficientFreeSpaceError, e: - nice_need = common.fsize(e.needed_space) - nice_free = common.fsize(e.free_space) - dialogs.show_popup_warning(self.window, _("There is not enough free disk space to complete your download.") + "\n" + \ - _("Space Needed:") + " " + nice_need + "\n" + \ - _("Available Space:") + " " + nice_free) - - def launchpad(self, obj=None): - common.open_url_in_browser('self', 'https://translations.launchpad.net/deluge/trunk/+pots/deluge') - - def add_torrent_clicked(self, obj=None): - torrent = dialogs.show_file_open_dialog() - if torrent is not None: - for single in torrent: - self.interactive_add_torrent(single) + def queue_torrent_url(self, url): + filename, headers = self.fetch_url(url) + if filename: + self.torrent_file_queue.append(filename) - def add_torrent_url_clicked(self, obj=None): - dlg = gtk.Dialog(title=_("Add torrent from URL"), parent=self.window, - buttons=(gtk.STOCK_CANCEL, 0, gtk.STOCK_OK, 1)) - dlg.set_icon_from_file(common.get_pixmap("deluge32.png")) - - label = gtk.Label(_("Enter the URL of the .torrent to download")) - entry = gtk.Entry() - dlg.vbox.pack_start(label) - dlg.vbox.pack_start(entry) - clip = gtk.clipboard_get(selection='PRIMARY') - text = clip.wait_for_text() - #watch out for an empty clipboard, TODO check for non url garbage - if text: - entry.set_text(text) - dlg.show_all() - result = dlg.run() - url = entry.get_text() - dlg.destroy() - - if result == 1: - self.add_torrent_url(url) + def fetch_url(self, url): + filename, headers = urllib.urlretrieve(url) + if filename.endswith(".torrent") or headers["content-type"]=="application/x-bittorrent": + return filename, headers + else: + print "URL doesn't appear to be a valid torrent file:", url + return None, None + + + def remove_torrent_clicked(self, obj=None): + glade = gtk.glade.XML(common.get_glade_file("dgtkpopups.glade"), domain='deluge') + asker = glade.get_widget("remove_torrent_dlg") + + asker.set_icon_from_file(common.get_pixmap("deluge32.png")) - def external_add_url(self, url): - print "Got URL externally:", url - if self.is_running: - print "\t\tthe client seems to already be running, i'll try and add the URL" - self.add_torrent_url(url) - else: - print "\t\tthe client hasn't started yet, I'll queue the URL torrent file" - self.queue_torrent_url(url) + warning = glade.get_widget("warning") + warning.set_text(" ") - def add_torrent_url(self, url): - filename, headers = self.fetch_url(url) - if filename: - self.interactive_add_torrent(filename) + torrent_also = glade.get_widget("torrent_also") + data_also = glade.get_widget("data_also") + data_also.connect("toggled", self.remove_toggle_warning, warning) - def queue_torrent_url(self, url): - filename, headers = self.fetch_url(url) - if filename: - self.torrent_file_queue.append(filename) - - def fetch_url(self, url): - filename, headers = urllib.urlretrieve(url) - if filename.endswith(".torrent") or headers["content-type"]=="application/x-bittorrent": - return filename, headers - else: - print "URL doesn't appear to be a valid torrent file:", url - return None, None - - - def remove_torrent_clicked(self, obj=None): - glade = gtk.glade.XML(common.get_glade_file("dgtkpopups.glade"), domain='deluge') - asker = glade.get_widget("remove_torrent_dlg") - - asker.set_icon_from_file(common.get_pixmap("deluge32.png")) - - warning = glade.get_widget("warning") - warning.set_text(" ") - - torrent_also = glade.get_widget("torrent_also") - data_also = glade.get_widget("data_also") - data_also.connect("toggled", self.remove_toggle_warning, warning) - - response = asker.run() - asker.destroy() - if response == 1: - torrent_list = self.get_selected_torrent_rows() - self.clear_details_pane() - self.torrent_selected = None - for torrent in torrent_list: - self.manager.remove_torrent(torrent, data_also.get_active(), torrent_also.get_active()) - self.update() - - def clear_details_pane(self): - self.wtree.get_widget("progressbar").set_text("") - self.wtree.get_widget("summary_name").set_text("") - self.text_summary_total_size.set_text("") - self.text_summary_pieces.set_text("") - self.text_summary_total_downloaded.set_text("") - self.text_summary_total_uploaded.set_text("") - self.text_summary_download_speed.set_text("") - self.text_summary_upload_speed.set_text("") - self.text_summary_seeders.set_text("") - self.text_summary_peers.set_text("") - self.wtree.get_widget("progressbar").set_fraction(0.0) - self.text_summary_share_ratio.set_text("") - self.text_summary_tracker.set_text("") - self.text_summary_tracker_status.set_text("") - self.text_summary_next_announce.set_text("") - self.text_summary_eta.set_text("") - self.peer_store.clear() - self.file_store.clear() + response = asker.run() + asker.destroy() + if response == 1: + torrent_list = self.get_selected_torrent_rows() + self.clear_details_pane() + self.torrent_selected = None + for torrent in torrent_list: + self.manager.remove_torrent(torrent, data_also.get_active(), torrent_also.get_active()) + self.update() + + def clear_details_pane(self): + self.wtree.get_widget("progressbar").set_text("") + self.wtree.get_widget("summary_name").set_text("") + self.text_summary_total_size.set_text("") + self.text_summary_pieces.set_text("") + self.text_summary_total_downloaded.set_text("") + self.text_summary_total_uploaded.set_text("") + self.text_summary_download_speed.set_text("") + self.text_summary_upload_speed.set_text("") + self.text_summary_seeders.set_text("") + self.text_summary_peers.set_text("") + self.wtree.get_widget("progressbar").set_fraction(0.0) + self.text_summary_share_ratio.set_text("") + self.text_summary_tracker.set_text("") + self.text_summary_tracker_status.set_text("") + self.text_summary_next_announce.set_text("") + self.text_summary_eta.set_text("") + self.peer_store.clear() + self.file_store.clear() - def remove_toggle_warning(self, args, warning): - if not args.get_active(): - warning.set_text(" ") - else: - warning.set_markup("" + _("Warning - all downloaded files for this torrent will be deleted!") + "") - return False + def remove_toggle_warning(self, args, warning): + if not args.get_active(): + warning.set_text(" ") + else: + warning.set_markup("" + _("Warning - all downloaded files for this torrent will be deleted!") + "") + return False - def update_tracker(self, obj=None): - torrent = self.get_selected_torrent() - if torrent is not None: - self.manager.update_tracker(torrent) - - def clear_finished(self, obj=None): - print "Clearing Completed Torrents" - self.manager.clear_completed() - self.update() - - def q_torrent_up(self, obj=None): - for torrent in self.get_selected_torrent_rows(): - self.manager.queue_up(torrent) - self.update() + def update_tracker(self, obj=None): + torrent = self.get_selected_torrent() + if torrent is not None: + self.manager.update_tracker(torrent) + + def clear_finished(self, obj=None): + print "Clearing Completed Torrents" + self.manager.clear_completed() + self.update() + + def q_torrent_up(self, obj=None): + for torrent in self.get_selected_torrent_rows(): + self.manager.queue_up(torrent) + self.update() - def q_torrent_down(self, obj=None): - for torrent in reversed(self.get_selected_torrent_rows()): - self.manager.queue_down(torrent) - self.update() + def q_torrent_down(self, obj=None): + for torrent in reversed(self.get_selected_torrent_rows()): + self.manager.queue_down(torrent) + self.update() - def q_to_bottom(self, widget): - for torrent in self.get_selected_torrent_rows(): - self.manager.queue_bottom(torrent) - self.update() + def q_to_bottom(self, widget): + for torrent in self.get_selected_torrent_rows(): + self.manager.queue_bottom(torrent) + self.update() - def q_to_top(self, widget): - for torrent in reversed(self.get_selected_torrent_rows()): - self.manager.queue_top(torrent) - self.update() - - def toolbar_toggle(self, widget): - if widget.get_active(): - self.wtree.get_widget("tb_left").show() - self.wtree.get_widget("tb_middle").show() - self.wtree.get_widget("tb_right").show() - else: - self.wtree.get_widget("tb_left").hide() - self.wtree.get_widget("tb_middle").hide() - self.wtree.get_widget("tb_right").hide() - - def infopane_toggle(self, widget): - if widget.get_active(): - self.wtree.get_widget("torrent_info").show() - else: - self.wtree.get_widget("torrent_info").hide() - - def size_toggle(self, obj): - self.size_column.set_visible(obj.get_active()) - - - def status_toggle(self, obj): - self.status_column.set_visible(obj.get_active()) - - def seeders_toggle(self, obj): - self.seed_column.set_visible(obj.get_active()) - - def peers_toggle(self, obj): - self.peer_column.set_visible(obj.get_active()) - - def dl_toggle(self, obj): - self.dl_column.set_visible(obj.get_active()) - - def ul_toggle(self, obj): - self.ul_column.set_visible(obj.get_active()) - - def eta_toggle(self, obj): - self.eta_column.set_visible(obj.get_active()) - - def share_toggle(self, obj): - self.share_column.set_visible(obj.get_active()) - - def load_window_settings(self): - self.wtree.get_widget("chk_infopane").set_active(self.config.get("show_infopane")) - self.wtree.get_widget("chk_toolbar").set_active(self.config.get("show_toolbar")) - self.wtree.get_widget("chk_size").set_active(self.config.get("show_size")) - self.wtree.get_widget("chk_status").set_active(self.config.get("show_status")) - self.wtree.get_widget("chk_seed").set_active(self.config.get("show_seeders")) - self.wtree.get_widget("chk_peer").set_active(self.config.get("show_peers")) - self.wtree.get_widget("chk_download").set_active(self.config.get("show_dl")) - self.wtree.get_widget("chk_upload").set_active(self.config.get("show_ul")) - self.wtree.get_widget("chk_eta").set_active(self.config.get("show_eta")) - self.wtree.get_widget("chk_ratio").set_active(self.config.get("show_share")) - self.wtree.get_widget("vpaned1").set_position(self.config.get("window_height") - self.config.get("window_pane_position")) - - def save_window_settings(self): - self.config.set("show_infopane", self.wtree.get_widget("chk_infopane").get_active()) - self.config.set("show_toolbar", self.wtree.get_widget("chk_toolbar").get_active()) - self.config.set("show_size", self.size_column.get_visible()) - self.config.set("show_status", self.status_column.get_visible()) - self.config.set("show_seeders", self.seed_column.get_visible()) - self.config.set("show_peers", self.peer_column.get_visible()) - self.config.set("show_dl", self.dl_column.get_visible()) - self.config.set("show_ul", self.ul_column.get_visible()) - self.config.set("show_eta", self.eta_column.get_visible()) - self.config.set("show_share", self.share_column.get_visible()) - self.config.set("window_pane_position", self.config.get("window_height") - self.wtree.get_widget("vpaned1").get_position()) - - def window_configure_event(self, widget, event): - if self.config.get("window_maximized") == False: - self.config.set("window_x_pos", self.window.get_position()[0]) - self.config.set("window_y_pos", self.window.get_position()[1]) - self.config.set("window_width", event.width) - self.config.set("window_height", event.height) + def q_to_top(self, widget): + for torrent in reversed(self.get_selected_torrent_rows()): + self.manager.queue_top(torrent) + self.update() + + def toolbar_toggle(self, widget): + if widget.get_active(): + self.wtree.get_widget("tb_left").show() + self.wtree.get_widget("tb_middle").show() + self.wtree.get_widget("tb_right").show() + else: + self.wtree.get_widget("tb_left").hide() + self.wtree.get_widget("tb_middle").hide() + self.wtree.get_widget("tb_right").hide() + + def infopane_toggle(self, widget): + if widget.get_active(): + self.wtree.get_widget("torrent_info").show() + else: + self.wtree.get_widget("torrent_info").hide() + + def size_toggle(self, obj): + self.size_column.set_visible(obj.get_active()) + + + def status_toggle(self, obj): + self.status_column.set_visible(obj.get_active()) + + def seeders_toggle(self, obj): + self.seed_column.set_visible(obj.get_active()) + + def peers_toggle(self, obj): + self.peer_column.set_visible(obj.get_active()) + + def dl_toggle(self, obj): + self.dl_column.set_visible(obj.get_active()) + + def ul_toggle(self, obj): + self.ul_column.set_visible(obj.get_active()) + + def eta_toggle(self, obj): + self.eta_column.set_visible(obj.get_active()) + + def share_toggle(self, obj): + self.share_column.set_visible(obj.get_active()) + + def load_window_settings(self): + self.wtree.get_widget("chk_infopane").set_active(self.config.get("show_infopane")) + self.wtree.get_widget("chk_toolbar").set_active(self.config.get("show_toolbar")) + self.wtree.get_widget("chk_size").set_active(self.config.get("show_size")) + self.wtree.get_widget("chk_status").set_active(self.config.get("show_status")) + self.wtree.get_widget("chk_seed").set_active(self.config.get("show_seeders")) + self.wtree.get_widget("chk_peer").set_active(self.config.get("show_peers")) + self.wtree.get_widget("chk_download").set_active(self.config.get("show_dl")) + self.wtree.get_widget("chk_upload").set_active(self.config.get("show_ul")) + self.wtree.get_widget("chk_eta").set_active(self.config.get("show_eta")) + self.wtree.get_widget("chk_ratio").set_active(self.config.get("show_share")) + self.wtree.get_widget("vpaned1").set_position(self.config.get("window_height") - self.config.get("window_pane_position")) + + def save_window_settings(self): + self.config.set("show_infopane", self.wtree.get_widget("chk_infopane").get_active()) + self.config.set("show_toolbar", self.wtree.get_widget("chk_toolbar").get_active()) + self.config.set("show_size", self.size_column.get_visible()) + self.config.set("show_status", self.status_column.get_visible()) + self.config.set("show_seeders", self.seed_column.get_visible()) + self.config.set("show_peers", self.peer_column.get_visible()) + self.config.set("show_dl", self.dl_column.get_visible()) + self.config.set("show_ul", self.ul_column.get_visible()) + self.config.set("show_eta", self.eta_column.get_visible()) + self.config.set("show_share", self.share_column.get_visible()) + self.config.set("window_pane_position", self.config.get("window_height") - self.wtree.get_widget("vpaned1").get_position()) + + def window_configure_event(self, widget, event): + if self.config.get("window_maximized") == False: + self.config.set("window_x_pos", self.window.get_position()[0]) + self.config.set("window_y_pos", self.window.get_position()[1]) + self.config.set("window_width", event.width) + self.config.set("window_height", event.height) - def window_state_event(self, widget, event): - if event.changed_mask & gtk.gdk.WINDOW_STATE_MAXIMIZED: - if event.new_window_state & gtk.gdk.WINDOW_STATE_MAXIMIZED: - self.config.set("window_maximized", True) - else: - self.config.set("window_maximized", False) - return False + def window_state_event(self, widget, event): + if event.changed_mask & gtk.gdk.WINDOW_STATE_MAXIMIZED: + if event.new_window_state & gtk.gdk.WINDOW_STATE_MAXIMIZED: + self.config.set("window_maximized", True) + else: + self.config.set("window_maximized", False) + return False - def load_window_geometry(self): - x = self.config.get('window_x_pos') - y = self.config.get('window_y_pos') - w = self.config.get('window_width') - h = self.config.get('window_height') - self.window.move(x, y) - self.window.resize(w, h) - if self.config.get("window_maximized") == True: - self.window.maximize() + def load_window_geometry(self): + x = self.config.get('window_x_pos') + y = self.config.get('window_y_pos') + w = self.config.get('window_width') + h = self.config.get('window_height') + self.window.move(x, y) + self.window.resize(w, h) + if self.config.get("window_maximized") == True: + self.window.maximize() - def close(self, widget, event): - if self.config.get("close_to_tray") and self.config.get("enable_system_tray") and self.has_tray: - self.window.hide() - return True - else: - self.quit() - - def quit(self, widget=None): - if self.window.get_property("visible"): - self.window.hide() - self.shutdown() - else: - if self.config.get("lock_tray") == True: - self.unlock_tray("quitus") - else: - self.window.hide() - self.shutdown() - - def shutdown(self): - enabled_plugins = ':'.join(self.plugins.get_enabled_plugins()) - self.config.set('enabled_plugins', enabled_plugins) - self.save_window_settings() - self.config.save() - self.plugins.shutdown_all_plugins() - self.manager.quit() - gtk.main_quit() + def close(self, widget, event): + if self.config.get("close_to_tray") and self.config.get("enable_system_tray") and self.has_tray: + self.window.hide() + return True + else: + self.quit() + + def quit(self, widget=None): + if self.window.get_property("visible"): + self.window.hide() + self.shutdown() + else: + if self.config.get("lock_tray") == True: + self.unlock_tray("quitus") + else: + self.window.hide() + self.shutdown() + + def shutdown(self): + enabled_plugins = ':'.join(self.plugins.get_enabled_plugins()) + self.config.set('enabled_plugins', enabled_plugins) + self.save_window_settings() + self.config.save() + self.plugins.shutdown_all_plugins() + self.manager.quit() + gtk.main_quit() ## For testing purposes, create a copy of the interface if __name__ == "__main__": - interface = DelugeGTK() - interface.start() + interface = DelugeGTK() + interface.start() diff --git a/src/ipc_manager.py b/src/ipc_manager.py index c5de29ddf..21c1c38a1 100644 --- a/src/ipc_manager.py +++ b/src/ipc_manager.py @@ -14,9 +14,9 @@ # # You should have received a copy of the GNU General Public License # along with this program. If not, write to: -# The Free Software Foundation, Inc., -# 51 Franklin Street, Fifth Floor -# Boston, MA 02110-1301, USA. +# The Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor +# Boston, MA 02110-1301, USA. # # In addition, as a special exception, the copyright holders give # permission to link the code of portions of this program with the OpenSSL @@ -34,42 +34,43 @@ # 0.80.0. I finally found a solution by reading the source code from the # Listen project. try: - import dbus, dbus.service - dbus_version = getattr(dbus, 'version', (0,0,0)) - if dbus_version >= (0,41,0) and dbus_version < (0,80,0): - dbus.SessionBus() - import dbus.glib - elif dbus_version >= (0,80,0): - from dbus.mainloop.glib import DBusGMainLoop - DBusGMainLoop(set_as_default=True) - dbus.SessionBus() - else: - pass + import dbus + import dbus.service + dbus_version = getattr(dbus, 'version', (0,0,0)) + if dbus_version >= (0,41,0) and dbus_version < (0,80,0): + dbus.SessionBus() + import dbus.glib + elif dbus_version >= (0,80,0): + from dbus.mainloop.glib import DBusGMainLoop + DBusGMainLoop(set_as_default=True) + dbus.SessionBus() + else: + pass except: dbus_imported = False else: dbus_imported = True if dbus_imported: - class Manager(dbus.service.Object): - def __init__(self, interface, object_path='/org/deluge_torrent/DelugeObject'): - self.interface = interface - self.bus = dbus.SessionBus() - bus_name = dbus.service.BusName("org.deluge_torrent.Deluge", bus=self.bus) - dbus.service.Object.__init__(self, bus_name, object_path) + class Manager(dbus.service.Object): + def __init__(self, interface, object_path='/org/deluge_torrent/DelugeObject'): + self.interface = interface + self.bus = dbus.SessionBus() + bus_name = dbus.service.BusName("org.deluge_torrent.Deluge", bus=self.bus) + dbus.service.Object.__init__(self, bus_name, object_path) - ## external_add_torrent should only be called from outside the class - @dbus.service.method('org.deluge_torrent.Deluge') - def external_add_torrent(self, torrent_file): - self.interface.external_add_torrent(torrent_file) - @dbus.service.method('org.deluge_torrent.Deluge') - def external_add_url(self, url): - self.interface.external_add_url(url) + ## external_add_torrent should only be called from outside the class + @dbus.service.method('org.deluge_torrent.Deluge') + def external_add_torrent(self, torrent_file): + self.interface.external_add_torrent(torrent_file) + @dbus.service.method('org.deluge_torrent.Deluge') + def external_add_url(self, url): + self.interface.external_add_url(url) else: - # This is a fallback class in case dbus is not available - class Manager: - def __init__(self, interface, object_path=None): - self.interface = interface - - def external_add_torrent(self, torrent_file): - print "I can't do anything with this." - def external_add_url(self, url): - print "I can't do anything with this." + # This is a fallback class in case dbus is not available + class Manager: + def __init__(self, interface, object_path=None): + self.interface = interface + + def external_add_torrent(self, torrent_file): + print "I can't do anything with this." + def external_add_url(self, url): + print "I can't do anything with this." diff --git a/src/plugins.py b/src/plugins.py index 5a9e75c22..a87aa3479 100644 --- a/src/plugins.py +++ b/src/plugins.py @@ -16,9 +16,9 @@ # # You should have received a copy of the GNU General Public License # along with this program. If not, write to: -# The Free Software Foundation, Inc., -# 51 Franklin Street, Fifth Floor -# Boston, MA 02110-1301, USA. +# The Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor +# Boston, MA 02110-1301, USA. # # In addition, as a special exception, the copyright holders give # permission to link the code of portions of this program with the OpenSSL @@ -30,85 +30,87 @@ # this exception statement from your version. If you delete this exception # statement from all source files in the program, then also delete it here. -import os, sys, imp +import os +import sys +import imp class PluginManager: - def __init__(self, deluge_core, deluge_interface): - self.plugin_dirs = [] - self.available_plugins = {} - self.enabled_plugins = {} - self.core = deluge_core - self.interface = deluge_interface - - def add_plugin_dir(self, directory): - self.plugin_dirs.append(directory) - sys.path.append(directory) - - # Scans all defined plugin dirs for Deluge plugins. The resulting - # module object is store with the defined name. - def scan_for_plugins(self): - for folder in self.plugin_dirs: - print "Scanning plugin dir",folder - for modname in os.listdir(folder): - path = folder+'/'+modname - if '__init__.py' in os.listdir(path): - # Import the found module. Note that the last - # parameter is important otherwise only the base - # modules (ie. 'plugins') is imported. This appears - # to be by design. - print "Loading module",modname - mod = __import__(modname, globals(), locals(), ['']) - if 'deluge_init' in dir(mod): - print "Initialising plugin",modname - mod.deluge_init(path) - self.available_plugins[mod.plugin_name] = mod - - def get_available_plugins(self): - return self.available_plugins.keys() - - def get_plugin(self, name): - return self.available_plugins[name] - - def enable_plugin(self, name): - plugin = self.available_plugins[name] - self.enabled_plugins[name] = plugin.enable(self.core, self.interface) + def __init__(self, deluge_core, deluge_interface): + self.plugin_dirs = [] + self.available_plugins = {} + self.enabled_plugins = {} + self.core = deluge_core + self.interface = deluge_interface + + def add_plugin_dir(self, directory): + self.plugin_dirs.append(directory) + sys.path.append(directory) + + # Scans all defined plugin dirs for Deluge plugins. The resulting + # module object is store with the defined name. + def scan_for_plugins(self): + for folder in self.plugin_dirs: + print "Scanning plugin dir",folder + for modname in os.listdir(folder): + path = folder+'/'+modname + if '__init__.py' in os.listdir(path): + # Import the found module. Note that the last + # parameter is important otherwise only the base + # modules (ie. 'plugins') is imported. This appears + # to be by design. + print "Loading module",modname + mod = __import__(modname, globals(), locals(), ['']) + if 'deluge_init' in dir(mod): + print "Initialising plugin",modname + mod.deluge_init(path) + self.available_plugins[mod.plugin_name] = mod + + def get_available_plugins(self): + return self.available_plugins.keys() + + def get_plugin(self, name): + return self.available_plugins[name] + + def enable_plugin(self, name): + plugin = self.available_plugins[name] + self.enabled_plugins[name] = plugin.enable(self.core, self.interface) - def get_enabled_plugins(self): - return self.enabled_plugins.keys() + def get_enabled_plugins(self): + return self.enabled_plugins.keys() - def disable_plugin(self, name): - plugin = self.enabled_plugins[name] - if 'unload' in dir(plugin): - plugin.unload() - self.enabled_plugins.pop(name) - - def configurable_plugin(self, name): - if name in self.enabled_plugins: - return 'configure' in dir(self.enabled_plugins[name]) - else: - return False + def disable_plugin(self, name): + plugin = self.enabled_plugins[name] + if 'unload' in dir(plugin): + plugin.unload() + self.enabled_plugins.pop(name) + + def configurable_plugin(self, name): + if name in self.enabled_plugins: + return 'configure' in dir(self.enabled_plugins[name]) + else: + return False - def configure_plugin(self, name): - self.enabled_plugins[name].configure() - - def update_active_plugins(self): - for name in self.enabled_plugins.keys(): - plugin = self.enabled_plugins[name] - if 'update' in dir(plugin): - plugin.update() - - def shutdown_all_plugins(self): - for name in self.enabled_plugins.keys(): - self.disable_plugin(name) - self.enabled_plugins.clear() - + def configure_plugin(self, name): + self.enabled_plugins[name].configure() + + def update_active_plugins(self): + for name in self.enabled_plugins.keys(): + plugin = self.enabled_plugins[name] + if 'update' in dir(plugin): + plugin.update() + + def shutdown_all_plugins(self): + for name in self.enabled_plugins.keys(): + self.disable_plugin(name) + self.enabled_plugins.clear() + ## Few lines of code to test functionality if __name__ == "__main__": - p = PluginManager() - p.add_plugin_dir("plugins/") - p.scan_for_plugins() - for x in p.plugins: - print x - for y in p.plugins[x]: - print "\t", y + p = PluginManager() + p.add_plugin_dir("plugins/") + p.scan_for_plugins() + for x in p.plugins: + print x + for y in p.plugins[x]: + print "\t", y diff --git a/src/pref.py b/src/pref.py index c1c384af2..8ea76e573 100644 --- a/src/pref.py +++ b/src/pref.py @@ -14,9 +14,9 @@ # # You should have received a copy of the GNU General Public License # along with this program. If not, write to: -# The Free Software Foundation, Inc., -# 51 Franklin Street, Fifth Floor -# Boston, MA 02110-1301, USA. +# The Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor +# Boston, MA 02110-1301, USA. # # In addition, as a special exception, the copyright holders give # permission to link the code of portions of this program with the OpenSSL @@ -38,141 +38,141 @@ import common import os.path DEFAULT_PREFS = { - "auto_end_seeding" : False, - "auto_seed_ratio" : 0, - "close_to_tray" : False, - "default_download_path" : "", - "default_load_path" : os.path.expanduser("~/"), - "enable_dht" : True, - "enable_system_tray" : True, - "enabled_plugins" : "", - "encin_state" : common.EncState.enabled, - "encout_state" : common.EncState.enabled, - "enclevel_type" : common.EncLevel.both, - "end_seed_ratio" : 0.0, - "gui_update_interval" : 1.0, - "listen_on" : [6881,6889], - "lock_tray" : False, - "max_active_torrents" : -1, - "max_connections" : 400, - "max_download_speed" : -1, - "max_download_speed_bps": -1, - "max_number_downloads" : -1, - "max_number_uploads" : -1, - "max_upload_speed" : -1, - "max_upload_speed_bps" : -1, - "max_uploads" : 2, - "pref_rc4" : True, - "proxy_type" : common.ProxyType.none, - "peer_proxy" : False, - "tracker_proxy" : False, - "dht_proxy" : False, - "proxy_hostname" : "", - "proxy_username" : "", - "proxy_password" : "", - "proxy_port": 8080, - "queue_seeds_to_bottom" : False, - "show_dl" : True, - "show_eta" : True, - "show_infopane" : True, - "show_peers" : True, - "show_seeders" : True, - "show_share" : True, - "show_size" : True, - "show_status" : True, - "show_toolbar" : True, - "show_ul" : True, - "tray_downloadspeedlist" : [5.0, 10.0, 30.0, 80.0, 300.0], - "tray_passwd" : "", - "tray_uploadspeedlist" : [5.0, 10.0, 30.0, 80.0, 300.0], - "use_compact_storage" : True, - "use_default_dir" : False, - "use_natpmp" : False, - "use_upnp" : False, - "use_utpex" : True, - "window_height" : 480, - "window_maximized" : False, - "window_pane_position" : -1, - "window_width" : 640, - "window_x_pos" : 0, - "window_y_pos" : 0, + "auto_end_seeding" : False, + "auto_seed_ratio" : 0, + "close_to_tray" : False, + "default_download_path" : "", + "default_load_path" : os.path.expanduser("~/"), + "enable_dht" : True, + "enable_system_tray" : True, + "enabled_plugins" : "", + "encin_state" : common.EncState.enabled, + "encout_state" : common.EncState.enabled, + "enclevel_type" : common.EncLevel.both, + "end_seed_ratio" : 0.0, + "gui_update_interval" : 1.0, + "listen_on" : [6881,6889], + "lock_tray" : False, + "max_active_torrents" : -1, + "max_connections" : 400, + "max_download_speed" : -1, + "max_download_speed_bps": -1, + "max_number_downloads" : -1, + "max_number_uploads" : -1, + "max_upload_speed" : -1, + "max_upload_speed_bps" : -1, + "max_uploads" : 2, + "pref_rc4" : True, + "proxy_type" : common.ProxyType.none, + "peer_proxy" : False, + "tracker_proxy" : False, + "dht_proxy" : False, + "proxy_hostname" : "", + "proxy_username" : "", + "proxy_password" : "", + "proxy_port": 8080, + "queue_seeds_to_bottom" : False, + "show_dl" : True, + "show_eta" : True, + "show_infopane" : True, + "show_peers" : True, + "show_seeders" : True, + "show_share" : True, + "show_size" : True, + "show_status" : True, + "show_toolbar" : True, + "show_ul" : True, + "tray_downloadspeedlist" : [5.0, 10.0, 30.0, 80.0, 300.0], + "tray_passwd" : "", + "tray_uploadspeedlist" : [5.0, 10.0, 30.0, 80.0, 300.0], + "use_compact_storage" : True, + "use_default_dir" : False, + "use_natpmp" : False, + "use_upnp" : False, + "use_utpex" : True, + "window_height" : 480, + "window_maximized" : False, + "window_pane_position" : -1, + "window_width" : 640, + "window_x_pos" : 0, + "window_y_pos" : 0, } class Preferences: - def __init__(self, filename=None, global_defaults=True, defaults=None): - self.mapping = {} - if defaults is not None: - for key in defaults.keys(): - self.mapping.setdefault(key, defaults[key]) - - if global_defaults is True: - self.mapping = DEFAULT_PREFS - - self.config_file = filename - if self.config_file is not None: - self.load(self.config_file) - - # Allows you to access an item in a Preferences objecy by calling - # instance[key] rather than instance.get(key). However, this will - # return the value as the type it is currently in memory, so it is - # advisable to use get() if you need the value converted. - def __getitem__(self, key): - return self.mapping[key] - - def __setitem__(self, key, value): - self.mapping[key] = value - - def __delitem__(self, key): - del self.mapping[key] - - def __len__(self): - return len(self.mapping) - - def has_key(self, key): return self.mapping.has_key(key) - def items(self): return self.mapping.items() - def keys(self): return self.mapping.keys() - def values(self): return self.mapping.values() - - def save(self, filename=None): - if filename is None: - filename = self.config_file - try: - pkl_file = open(filename, 'wb') - pickle.dump(self.mapping, pkl_file) - pkl_file.close() - except IOError: - pass + def __init__(self, filename=None, global_defaults=True, defaults=None): + self.mapping = {} + if defaults is not None: + for key in defaults.keys(): + self.mapping.setdefault(key, defaults[key]) + + if global_defaults is True: + self.mapping = DEFAULT_PREFS + + self.config_file = filename + if self.config_file is not None: + self.load(self.config_file) + + # Allows you to access an item in a Preferences objecy by calling + # instance[key] rather than instance.get(key). However, this will + # return the value as the type it is currently in memory, so it is + # advisable to use get() if you need the value converted. + def __getitem__(self, key): + return self.mapping[key] + + def __setitem__(self, key, value): + self.mapping[key] = value + + def __delitem__(self, key): + del self.mapping[key] + + def __len__(self): + return len(self.mapping) + + def has_key(self, key): return self.mapping.has_key(key) + def items(self): return self.mapping.items() + def keys(self): return self.mapping.keys() + def values(self): return self.mapping.values() + + def save(self, filename=None): + if filename is None: + filename = self.config_file + try: + pkl_file = open(filename, 'wb') + pickle.dump(self.mapping, pkl_file) + pkl_file.close() + except IOError: + pass - def load(self, filename=None): - if filename is None: - filename = self.config_file - try: - pkl_file = open(filename, 'rb') - self.dump = pickle.load(pkl_file) - self.mapping.update(self.dump) - pkl_file.close() - except IOError: - pass - except EOFError: - pkl_file.close() - pass - - def set(self, key, value): - self.mapping[key] = value - - def get(self, key): - try: - value = self.mapping[key] - return value - except KeyError: - return None - - def remove(self, key): - self.mapping.pop(key) - - def clear(self): - self.mapping.clear() - - def printout(self): - for key in self.mapping.keys(): - print key, ':', self.mapping[key] - + def load(self, filename=None): + if filename is None: + filename = self.config_file + try: + pkl_file = open(filename, 'rb') + self.dump = pickle.load(pkl_file) + self.mapping.update(self.dump) + pkl_file.close() + except IOError: + pass + except EOFError: + pkl_file.close() + pass + + def set(self, key, value): + self.mapping[key] = value + + def get(self, key): + try: + value = self.mapping[key] + return value + except KeyError: + return None + + def remove(self, key): + self.mapping.pop(key) + + def clear(self): + self.mapping.clear() + + def printout(self): + for key in self.mapping.keys(): + print key, ':', self.mapping[key] +