diff --git a/deluge/core/core.py b/deluge/core/core.py index cdf219004..562da3c7c 100644 --- a/deluge/core/core.py +++ b/deluge/core/core.py @@ -88,7 +88,7 @@ class Core( # Setup the xmlrpc server try: SimpleXMLRPCServer.SimpleXMLRPCServer.__init__( - self, ("localhost", 6666), logRequests=False, allow_none=True) + self, ("localhost", 58846), logRequests=False, allow_none=True) except: log.info("Daemon already running or port not available..") sys.exit(0) @@ -200,6 +200,10 @@ class Core( self.loop.quit() # Exported Methods + def export_ping(self): + """A method to see if the core is running""" + return True + def export_shutdown(self): """Shutdown the core""" # Make shutdown an async call @@ -209,6 +213,10 @@ class Core( """Registers a client with the signal manager so that signals are sent to it.""" self.signals.register_client(uri) + + def export_deregister_client(self, uri): + """De-registers a client with the signal manager.""" + self.signals.deregister_client(uri) def export_add_torrent_file(self, filename, save_path, filedump): """Adds a torrent file to the libtorrent session diff --git a/deluge/core/signalmanager.py b/deluge/core/signalmanager.py index ec3fdf318..db018330f 100644 --- a/deluge/core/signalmanager.py +++ b/deluge/core/signalmanager.py @@ -39,6 +39,11 @@ class SignalManager: def __init__(self): self.clients = [] + def deregister_client(self, uri): + """Deregisters a client""" + log.debug("Deregistering %s as a signal reciever..", uri) + self.clients.remove(self.clients.index(uri)) + def register_client(self, uri): """Registers a client to emit signals to.""" log.debug("Registering %s as a signal reciever..", uri) diff --git a/deluge/ui/functions.py b/deluge/ui/client.py similarity index 83% rename from deluge/ui/functions.py rename to deluge/ui/client.py index 2334d1b6d..c84a864e6 100644 --- a/deluge/ui/functions.py +++ b/deluge/ui/client.py @@ -45,12 +45,27 @@ from deluge.log import LOG as log class CoreProxy: def __init__(self): + self._uri = None self._core = None + self._on_new_core_callbacks = [] + + def connect_on_new_core(self, callback): + """Connect a callback to be called when a new core is connected to.""" + self._on_new_core_callbacks.append(callback) + + def set_core_uri(self, uri): + log.info("Setting core uri as %s", uri) + self._uri = uri + # Get a new core + self.get_core() def get_core(self): - if self._core is None: + if self._core is None and self._uri is not None: log.debug("Creating ServerProxy..") - self._core = xmlrpclib.ServerProxy("http://localhost:6666") + self._core = xmlrpclib.ServerProxy(self._uri) + # Call any callbacks registered + for callback in self._on_new_core_callbacks: + callback() return self._core @@ -69,6 +84,14 @@ def get_core_plugin(plugin): core = dbus.Interface(proxy, "org.deluge_torrent.Deluge." + plugin) return core +def connect_on_new_core(callback): + """Connect a callback whenever a new core is connected to.""" + return _core.connect_on_new_core(callback) + +def set_core_uri(uri): + """Sets the core uri""" + return _core.set_core_uri(uri) + def shutdown(): """Shutdown the core daemon""" get_core().shutdown() @@ -156,6 +179,15 @@ def get_available_plugins(): def get_enabled_plugins(): return get_core().get_enabled_plugins() +def get_download_rate(): + return get_core().get_download_rate() + +def get_upload_rate(): + return get_core().get_upload_rate() + +def get_num_connections(): + return get_core().get_num_connections() + def open_url_in_browser(url): """Opens link in the desktop's default browser""" def start_browser(): diff --git a/deluge/ui/gtkui/aboutdialog.py b/deluge/ui/gtkui/aboutdialog.py index 2c596580d..e53ef24f4 100644 --- a/deluge/ui/gtkui/aboutdialog.py +++ b/deluge/ui/gtkui/aboutdialog.py @@ -37,13 +37,13 @@ import gtk import pkg_resources import deluge.common -import deluge.ui.functions as functions +import deluge.ui.client as client class AboutDialog: def __init__(self): # Get the glade file for the about dialog def url_hook(dialog, url): - functions.open_url_in_browser(url) + client.open_url_in_browser(url) gtk.about_dialog_set_url_hook(url_hook) self.about = gtk.glade.XML(pkg_resources.resource_filename(\ "deluge.ui.gtkui", "glade/aboutdialog.glade")).get_widget(\ diff --git a/deluge/ui/gtkui/connectionmanager.py b/deluge/ui/gtkui/connectionmanager.py index d088e6c00..9fe9e4f31 100644 --- a/deluge/ui/gtkui/connectionmanager.py +++ b/deluge/ui/gtkui/connectionmanager.py @@ -31,6 +31,169 @@ # 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 gtk, gtk.glade +import pkg_resources +import gobject +import socket + +import deluge.xmlrpclib as xmlrpclib +import deluge.common +import deluge.ui.client as client +from deluge.configmanager import ConfigManager +from deluge.log import LOG as log + +DEFAULT_CONFIG = { + "hosts": ["localhost:58846"] +} + class ConnectionManager: - def __init__(self): + def __init__(self, window): + # Get the glade file for the connection manager + self.glade = gtk.glade.XML( + pkg_resources.resource_filename("deluge.ui.gtkui", + "glade/connection_manager.glade")) + + self.window = window + self.config = ConfigManager("hostlist.conf", DEFAULT_CONFIG) + self.connection_manager = self.glade.get_widget("connection_manager") + self.hostlist = self.glade.get_widget("hostlist") + self.connection_manager.set_icon(deluge.common.get_logo(16)) + self.glade.get_widget("image1").set_from_pixbuf( + deluge.common.get_logo(32)) + + self.liststore = gtk.ListStore(gtk.gdk.Pixbuf, str) + + # Fill in hosts from config file + for host in self.config["hosts"]: + row = self.liststore.append() + self.liststore.set_value(row, 1, host) + + # Setup host list treeview + self.hostlist.set_model(self.liststore) + render = gtk.CellRendererPixbuf() + column = gtk.TreeViewColumn("Status", render, pixbuf=0) + self.hostlist.append_column(column) + render = gtk.CellRendererText() + column = gtk.TreeViewColumn("Host", render, text=1) + self.hostlist.append_column(column) + + self.glade.signal_autoconnect({ + "on_button_addhost_clicked": self.on_button_addhost_clicked, + "on_button_removehost_clicked": self.on_button_removehost_clicked, + "on_button_startdaemon_clicked": \ + self.on_button_startdaemon_clicked, + "on_button_cancel_clicked": self.on_button_cancel_clicked, + "on_button_connect_clicked": self.on_button_connect_clicked, + }) + + self.connection_manager.connect("delete-event", self.on_delete_event) + + def show(self): + self.update_timer = gobject.timeout_add(5000, self.update) + self.update() + self.connection_manager.show_all() + + def hide(self): + self.connection_manager.hide() + gobject.source_remove(self.update_timer) + + def update(self): + """Updates the host status""" + def update_row(model=None, path=None, row=None, columns=None): + uri = model.get_value(row, 1) + uri = "http://" + uri + online = True + host = None + try: + host = xmlrpclib.ServerProxy(uri) + host.ping() + except socket.error: + print "socket.error!" + online = False + + print "online: ", online + del host + + if online: + image = gtk.STOCK_YES + else: + image = gtk.STOCK_NO + + pixbuf = self.connection_manager.render_icon( + image, gtk.ICON_SIZE_MENU) + + model.set_value(row, 0, pixbuf) + + self.liststore.foreach(update_row) + return True + + def save(self): + """Save the current host list to file""" + def append_row(model=None, path=None, row=None, columns=None): + hostlist.append(model.get_value(row, 1)) + + hostlist = [] + self.liststore.foreach(append_row, hostlist) + self.config["hosts"] = hostlist + self.config.save() + + ## Callbacks + def on_delete_event(self, widget, event): + self.hide() + return True + + def on_button_addhost_clicked(self, widget): + log.debug("on_button_addhost_clicked") + dialog = self.glade.get_widget("addhost_dialog") + dialog.set_icon(deluge.common.get_logo(16)) + hostname_entry = self.glade.get_widget("entry_hostname") + port_spinbutton = self.glade.get_widget("spinbutton_port") + response = dialog.run() + if response == 1: + # We add the host + hostname = hostname_entry.get_text() + if hostname.startswith("http://"): + hostname = hostname[7:] + + # Check to make sure the hostname is at least 1 character long + if len(hostname) < 1: + dialog.hide() + return + + # Get the port and concatenate the hostname string + port = port_spinbutton.get_value_as_int() + hostname = hostname + ":" + str(port) + row = self.liststore.append() + self.liststore.set_value(row, 1, hostname) + # Save the host list to file + self.save() + + dialog.hide() + + def on_button_removehost_clicked(self, widget): + log.debug("on_button_removehost_clicked") + # Get the selected rows + paths = self.hostlist.get_selection().get_selected_rows()[1] + for path in paths: + self.liststore.remove(self.liststore.get_iter(path)) + + # Save the host list + self.save() + + def on_button_startdaemon_clicked(self, widget): + log.debug("on_button_startdaemon_clicked") + + def on_button_cancel_clicked(self, widget): + log.debug("on_button_cancel_clicked") + self.hide() + + def on_button_connect_clicked(self, widget): + log.debug("on_button_connect_clicked") + paths = self.hostlist.get_selection().get_selected_rows()[1] + row = self.liststore.get_iter(paths[0]) + uri = self.liststore.get_value(row, 1) + uri = "http://" + uri + client.set_core_uri(uri) + self.window.start() + self.hide() diff --git a/deluge/ui/gtkui/glade/connection_manager.glade b/deluge/ui/gtkui/glade/connection_manager.glade index 301294e08..ba85aee3b 100644 --- a/deluge/ui/gtkui/glade/connection_manager.glade +++ b/deluge/ui/gtkui/glade/connection_manager.glade @@ -1,14 +1,23 @@ - + - + + True + True GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - Deluge Connection Manager - - + 5 + Connection Manager + GTK_WIN_POS_CENTER_ON_PARENT + 350 + 300 + GDK_WINDOW_TYPE_HINT_DIALOG + False + + True GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + 2 True @@ -29,7 +38,7 @@ True GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - <big><b>Deluge Connection Manager</b></big> + <big><b>Connection Manager</b></big> True @@ -41,12 +50,14 @@ False 5 + 1 - + True GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + 5 True @@ -60,7 +71,7 @@ GTK_POLICY_AUTOMATIC GTK_POLICY_AUTOMATIC - + True True GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK @@ -72,25 +83,41 @@ - + True GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - GTK_BUTTONBOX_SPREAD - + True - True - True GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - 0 + GTK_BUTTONBOX_START - + True + True + True GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - 0 - gtk-add + gtk-add + True + 0 + + + + True + True + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + gtk-remove + True + 0 + + + + 1 + + False @@ -98,61 +125,123 @@ - + True True True GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - 0 + 0 + - + True GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - 0 - gtk-remove + 2 + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + gtk-execute + + + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + _Start local daemon + True + + + 1 + + False False + GTK_PACK_END 1 False + False 1 - 1 + 10 + 2 - + + True + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + + + True + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + checkbutton + 0 + True + + + + + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + Options + + + label_item + + + + + False + 3 + + + + True GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - GTK_BUTTONBOX_EDGE + GTK_BUTTONBOX_END - + True True True GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK gtk-cancel True + 0 + - + True True True GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK gtk-connect True + 0 + 1 @@ -161,7 +250,123 @@ False - 2 + GTK_PACK_END + + + + + + + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + 5 + Add Host + GTK_WIN_POS_CENTER + True + GDK_WINDOW_TYPE_HINT_DIALOG + False + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + 2 + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + 5 + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + Hostname: + + + False + False + + + + + True + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + + + 1 + + + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + Port: + + + False + False + 2 + + + + + True + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + 5 + 5 + 1 + 58846 1 65535 1 10 10 + True + + + False + False + 3 + + + + + False + False + 1 + + + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + GTK_BUTTONBOX_END + + + True + True + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + gtk-cancel + True + 0 + + + + + True + True + True + True + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + gtk-add + True + 1 + + + 1 + + + + + False + GTK_PACK_END diff --git a/deluge/ui/gtkui/glade/main_window.glade b/deluge/ui/gtkui/glade/main_window.glade index abbfc68fc..801b52a1a 100644 --- a/deluge/ui/gtkui/glade/main_window.glade +++ b/deluge/ui/gtkui/glade/main_window.glade @@ -113,6 +113,20 @@ + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + _Connection Manager + True + + + + gtk-connect + + + + @@ -348,6 +362,287 @@ 1 2 10 + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + 0 + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + 10 + 10 + 15 + 15 + + + True + 7 + 2 + 2 + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + 0 + True + PANGO_WRAP_WORD_CHAR + + + 1 + 2 + 1 + 2 + + + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + 5 + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + 0 + <b>Path:</b> + True + + + + + 1 + 2 + + + + + True + 0 + + + 1 + 2 + 6 + 7 + + + + + + True + 0 + + + 1 + 2 + 5 + 6 + + + + + + True + 0 + True + PANGO_WRAP_WORD_CHAR + + + 1 + 2 + 4 + 5 + + + + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + 5 + + + True + 0 + 0 + 1 + <b>Name:</b> + True + + + + + GTK_FILL + + + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + 5 + + + True + 0 + 1 + <b>Next Announce:</b> + True + + + + + 6 + 7 + GTK_FILL + + + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + 5 + + + True + 0 + 1 + <b>Tracker Status:</b> + True + + + + + 5 + 6 + GTK_FILL + + + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + 5 + + + True + 0 + 1 + <b>Tracker:</b> + True + + + + + 4 + 5 + GTK_FILL + + + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + 5 + + + True + 0 + 1 + <b>Total Size:</b> + True + + + + + 2 + 3 + GTK_FILL + + + + + True + 0 + True + PANGO_WRAP_WORD_CHAR + + + 1 + 2 + + + + + + True + 0 + + + 1 + 2 + 2 + 3 + + + + + + True + 0 + + + 1 + 2 + 3 + 4 + + + + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + 5 + + + True + 0 + 1 + <b># of files:</b> + True + + + + + 3 + 4 + GTK_FILL + + + + + + + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + <b>Torrent Info</b> + True + + + label_item + + + + + 1 + 2 + GTK_FILL + + True @@ -380,277 +675,18 @@ 4 5 - - True - 0 - - - 1 - 2 - - - - + True 0 + True + PANGO_WRAP_WORD_CHAR 3 4 - - - - - True - 0 - - - 1 - 2 - 1 - 2 - - - - - True - 0 - - - 3 - 4 - 1 - 2 - - - - - True - 0 - - - 1 - 2 - 2 - 3 - - - - - True - 0 - - - 3 - 4 - 2 - 3 - - - - - True - 0 - - - 1 - 2 - 3 - 4 - - - - - True - 0 - - - 3 - 4 - 3 - 4 - - - - - True - 5 - - - True - 0 - <b>Downloaded:</b> - True - - - - - - - True - 5 - - - True - 0 - <b>Uploaded:</b> - True - - - - - 1 - 2 - - - - - True - 5 - - - True - 0 - <b>Seeders:</b> - True - - - - - 2 - 3 - - - - - True - 5 - - - True - 0 - <b>Share Ratio:</b> - True - - - - - 3 - 4 - - - - - True - 15 - 5 - - - True - 0 - <b>Speed:</b> - True - - - - - 2 - 3 - - - - - True - 15 - 5 - - - True - 0 - <b>Speed:</b> - True - - - - - 2 - 3 - 1 - 2 - - - - - True - 15 - 5 - - - True - 0 - <b>Peers:</b> - True - - - - - 2 - 3 - 2 - 3 - - - - - True - 15 - 5 - - - True - 0 - <b>ETA:</b> - True - - - - - 2 - 3 - 3 - 4 - - - - - True - 0 - 1 - <b>Pieces:</b> - True - - - 4 - 5 - - - - - True - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - 5 - - - True - 0 - - - - - 1 - 2 4 5 + @@ -677,18 +713,277 @@ - + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + 5 + + + True + 0 + + + + + 1 + 2 + 4 + 5 + + + + + True + 0 + 1 + <b>Pieces:</b> + True + + + 4 + 5 + + + + + True + 15 + 5 + + + True + 0 + <b>ETA:</b> + True + + + + + 2 + 3 + 3 + 4 + + + + + True + 15 + 5 + + + True + 0 + <b>Peers:</b> + True + + + + + 2 + 3 + 2 + 3 + + + + + True + 15 + 5 + + + True + 0 + <b>Speed:</b> + True + + + + + 2 + 3 + 1 + 2 + + + + + True + 15 + 5 + + + True + 0 + <b>Speed:</b> + True + + + + + 2 + 3 + + + + + True + 5 + + + True + 0 + <b>Share Ratio:</b> + True + + + + + 3 + 4 + + + + + True + 5 + + + True + 0 + <b>Seeders:</b> + True + + + + + 2 + 3 + + + + + True + 5 + + + True + 0 + <b>Uploaded:</b> + True + + + + + 1 + 2 + + + + + True + 5 + + + True + 0 + <b>Downloaded:</b> + True + + + + + + True 0 - True - PANGO_WRAP_WORD_CHAR 3 4 - 4 - 5 - + 3 + 4 + + + + + True + 0 + + + 1 + 2 + 3 + 4 + + + + + True + 0 + + + 3 + 4 + 2 + 3 + + + + + True + 0 + + + 1 + 2 + 2 + 3 + + + + + True + 0 + + + 3 + 4 + 1 + 2 + + + + + True + 0 + + + 1 + 2 + 1 + 2 + + + + + True + 0 + + + 3 + 4 + + + + + True + 0 + + + 1 + 2 @@ -718,287 +1013,6 @@ GTK_FILL - - - True - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - 0 - - - True - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - 10 - 10 - 15 - 15 - - - True - 7 - 2 - 2 - - - True - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - 5 - - - True - 0 - 1 - <b># of files:</b> - True - - - - - 3 - 4 - GTK_FILL - - - - - True - 0 - - - 1 - 2 - 3 - 4 - - - - - - True - 0 - - - 1 - 2 - 2 - 3 - - - - - - True - 0 - True - PANGO_WRAP_WORD_CHAR - - - 1 - 2 - - - - - - True - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - 5 - - - True - 0 - 1 - <b>Total Size:</b> - True - - - - - 2 - 3 - GTK_FILL - - - - - True - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - 5 - - - True - 0 - 1 - <b>Tracker:</b> - True - - - - - 4 - 5 - GTK_FILL - - - - - True - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - 5 - - - True - 0 - 1 - <b>Tracker Status:</b> - True - - - - - 5 - 6 - GTK_FILL - - - - - True - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - 5 - - - True - 0 - 1 - <b>Next Announce:</b> - True - - - - - 6 - 7 - GTK_FILL - - - - - True - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - 5 - - - True - 0 - 0 - 1 - <b>Name:</b> - True - - - - - GTK_FILL - - - - - True - 0 - True - PANGO_WRAP_WORD_CHAR - - - 1 - 2 - 4 - 5 - - - - - - True - 0 - - - 1 - 2 - 5 - 6 - - - - - - True - 0 - - - 1 - 2 - 6 - 7 - - - - - - True - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - 5 - - - True - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - 0 - <b>Path:</b> - True - - - - - 1 - 2 - - - - - True - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - 0 - True - PANGO_WRAP_WORD_CHAR - - - 1 - 2 - 1 - 2 - - - - - - - - - True - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - <b>Torrent Info</b> - True - - - label_item - - - - - 1 - 2 - GTK_FILL - - diff --git a/deluge/ui/gtkui/gtkui.py b/deluge/ui/gtkui/gtkui.py index f11c89198..8d761072d 100644 --- a/deluge/ui/gtkui/gtkui.py +++ b/deluge/ui/gtkui/gtkui.py @@ -93,13 +93,13 @@ class GtkUI: self.mainwindow = MainWindow() # Start the signal receiver - self.signal_receiver = Signals(self) + #self.signal_receiver = Signals(self) # Initalize the plugins self.plugins = PluginManager(self) # Start the mainwindow and show it - self.mainwindow.start() + #self.mainwindow.start() # Start the gtk main loop gtk.gdk.threads_init() @@ -113,6 +113,6 @@ class GtkUI: # Clean-up del self.mainwindow - #del self.signal_receiver + # del self.signal_receiver del self.plugins del deluge.configmanager diff --git a/deluge/ui/gtkui/mainwindow.py b/deluge/ui/gtkui/mainwindow.py index 5d882cbb4..5d4d14316 100644 --- a/deluge/ui/gtkui/mainwindow.py +++ b/deluge/ui/gtkui/mainwindow.py @@ -37,6 +37,7 @@ import gtk, gtk.glade import gobject import pkg_resources +import deluge.ui.client as client from deluge.configmanager import ConfigManager from menubar import MenuBar from toolbar import ToolBar @@ -45,6 +46,7 @@ from torrentdetails import TorrentDetails from preferences import Preferences from systemtray import SystemTray from statusbar import StatusBar +from connectionmanager import ConnectionManager import deluge.common from deluge.log import LOG as log @@ -81,15 +83,19 @@ class MainWindow: self.preferences = Preferences(self) self.systemtray = SystemTray(self) self.statusbar = StatusBar(self) - - def start(self): - """Start the update thread and show the window""" - self.update_timer = gobject.timeout_add(1000, self.update) + self.connectionmanager = ConnectionManager(self) + client.connect_on_new_core(self.start) if not(self.config["start_in_tray"] and \ self.config["enable_system_tray"]) and not \ self.window.get_property("visible"): log.debug("Showing window") self.show() + self.connectionmanager.show() + + def start(self): + """Start the update thread and show the window""" + self.torrentview.start() + self.update_timer = gobject.timeout_add(1000, self.update) def update(self): # Don't update the UI if the the window is minimized. @@ -121,7 +127,10 @@ class MainWindow: def quit(self): # Stop the update timer from running - gobject.source_remove(self.update_timer) + try: + gobject.source_remove(self.update_timer) + except: + pass del self.systemtray del self.menubar del self.toolbar diff --git a/deluge/ui/gtkui/menubar.py b/deluge/ui/gtkui/menubar.py index e7e3d8c0e..721228f3e 100644 --- a/deluge/ui/gtkui/menubar.py +++ b/deluge/ui/gtkui/menubar.py @@ -36,7 +36,7 @@ pygtk.require('2.0') import gtk, gtk.glade import pkg_resources -import deluge.ui.functions as functions +import deluge.ui.client as client from deluge.log import LOG as log @@ -70,6 +70,8 @@ class MenuBar: ## Edit Menu "on_menuitem_preferences_activate": \ self.on_menuitem_preferences_activate, + "on_menuitem_connectionmanager_activate": \ + self.on_menuitem_connectionmanager_activate, ## View Menu "on_menuitem_toolbar_toggled": self.on_menuitem_toolbar_toggled, @@ -97,14 +99,14 @@ class MenuBar: def on_menuitem_addtorrent_activate(self, data=None): log.debug("on_menuitem_addtorrent_activate") from addtorrentdialog import AddTorrentDialog - functions.add_torrent_file(AddTorrentDialog().run()) + client.add_torrent_file(AddTorrentDialog().run()) def on_menuitem_addurl_activate(self, data=None): log.debug("on_menuitem_addurl_activate") from addtorrenturl import AddTorrentUrl result = AddTorrentUrl().run() if result is not None: - functions.add_torrent_url(result) + client.add_torrent_url(result) def on_menuitem_clear_activate(self, data=None): log.debug("on_menuitem_clear_activate") @@ -113,7 +115,7 @@ class MenuBar: log.debug("on_menuitem_quitdaemon_activate") # Tell the core to shutdown self.window.quit() - functions.shutdown() + client.shutdown() def on_menuitem_quit_activate(self, data=None): log.debug("on_menuitem_quit_activate") @@ -124,20 +126,24 @@ class MenuBar: log.debug("on_menuitem_preferences_activate") self.window.preferences.show() + def on_menuitem_connectionmanager_activate(self, data=None): + log.debug("on_menuitem_connectionmanager_activate") + self.window.connectionmanager.show() + ## Torrent Menu ## def on_menuitem_pause_activate(self, data=None): log.debug("on_menuitem_pause_activate") - functions.pause_torrent( + client.pause_torrent( self.window.torrentview.get_selected_torrents()) def on_menuitem_resume_activate(self, data=None): log.debug("on_menuitem_resume_activate") - functions.resume_torrent( + client.resume_torrent( self.window.torrentview.get_selected_torrents()) def on_menuitem_updatetracker_activate(self, data=None): log.debug("on_menuitem_updatetracker_activate") - functions.force_reannounce( + client.force_reannounce( self.window.torrentview.get_selected_torrents()) def on_menuitem_edittrackers_activate(self, data=None): @@ -145,7 +151,7 @@ class MenuBar: def on_menuitem_remove_activate(self, data=None): log.debug("on_menuitem_remove_activate") - functions.remove_torrent( + client.remove_torrent( self.window.torrentview.get_selected_torrents()) ## View Menu ## diff --git a/deluge/ui/gtkui/pluginmanager.py b/deluge/ui/gtkui/pluginmanager.py index 9c46ada4f..57217d415 100644 --- a/deluge/ui/gtkui/pluginmanager.py +++ b/deluge/ui/gtkui/pluginmanager.py @@ -32,7 +32,7 @@ # statement from all source files in the program, then also delete it here. import deluge.pluginmanagerbase -import deluge.ui.functions as functions +import deluge.ui.client as client from deluge.configmanager import ConfigManager from deluge.log import LOG as log @@ -41,16 +41,21 @@ class PluginManager(deluge.pluginmanagerbase.PluginManagerBase): self.config = ConfigManager("gtkui.conf") self._gtkui = gtkui - + + # Register a callback with the client + client.connect_on_new_core(self.start) + + def start(self): + """Start the plugin manager""" # Update the enabled_plugins from the core - enabled_plugins = functions.get_enabled_plugins() + enabled_plugins = client.get_enabled_plugins() enabled_plugins += self.config["enabled_plugins"] enabled_plugins = list(set(enabled_plugins)) self.config["enabled_plugins"] = enabled_plugins deluge.pluginmanagerbase.PluginManagerBase.__init__( self, "gtkui.conf", "deluge.plugin.ui.gtk") - + def get_torrentview(self): """Returns a reference to the torrentview component""" return self._gtkui.mainwindow.torrentview diff --git a/deluge/ui/gtkui/preferences.py b/deluge/ui/gtkui/preferences.py index 9f65803a6..e78178243 100644 --- a/deluge/ui/gtkui/preferences.py +++ b/deluge/ui/gtkui/preferences.py @@ -37,7 +37,7 @@ import gtk, gtk.glade import pkg_resources from deluge.log import LOG as log -import deluge.ui.functions as functions +import deluge.ui.client as client import deluge.common from deluge.configmanager import ConfigManager @@ -51,7 +51,6 @@ class Preferences: self.pref_dialog.set_icon(deluge.common.get_logo(32)) self.treeview = self.glade.get_widget("treeview") self.notebook = self.glade.get_widget("notebook") - self.core = functions.get_core() self.gtkui_config = ConfigManager("gtkui.conf") # Setup the liststore for the categories (tab pages) self.liststore = gtk.ListStore(int, str) @@ -104,7 +103,7 @@ class Preferences: self.liststore.append([index, name]) def show(self): - self.core_config = functions.get_config() + self.core_config = client.get_config() # Update the preferences dialog to reflect current config settings ## Downloads tab ## @@ -134,7 +133,7 @@ class Preferences: self.glade.get_widget("spin_port_max").set_value( self.core_config["listen_ports"][1]) self.glade.get_widget("active_port_label").set_text( - str(functions.get_listen_port())) + str(client.get_listen_port())) self.glade.get_widget("chk_random_port").set_active( self.core_config["random_port"]) self.glade.get_widget("chk_dht").set_active( @@ -193,8 +192,8 @@ class Preferences: self.gtkui_config["send_info"]) ## Plugins tab ## - all_plugins = functions.get_available_plugins() - enabled_plugins = functions.get_enabled_plugins() + all_plugins = client.get_available_plugins() + enabled_plugins = client.get_enabled_plugins() # Clear the existing list so we don't duplicate entries. self.plugin_liststore.clear() # Iterate through the lists and add them to the liststore @@ -310,7 +309,7 @@ class Preferences: config_to_set[key] = new_core_config[key] # Set each changed config value in the core - functions.set_config(config_to_set) + client.set_config(config_to_set) # Update the configuration self.core_config.update(config_to_set) @@ -387,8 +386,8 @@ class Preferences: def on_test_port_clicked(self, data): log.debug("on_test_port_clicked") url = "http://deluge-torrent.org/test-port.php?port=%s" % \ - functions.get_listen_port() - functions.open_url_in_browser(url) + client.get_listen_port() + client.open_url_in_browser(url) def on_plugin_toggled(self, renderer, path): log.debug("on_plugin_toggled") diff --git a/deluge/ui/gtkui/signals.py b/deluge/ui/gtkui/signals.py index 37b9f35e3..dff1f8533 100644 --- a/deluge/ui/gtkui/signals.py +++ b/deluge/ui/gtkui/signals.py @@ -37,7 +37,7 @@ from deluge.log import LOG as log class Signals: def __init__(self, ui): self.ui = ui - self.receiver = SignalReceiver(6667, "http://localhost:6666") + self.receiver = SignalReceiver(6667, "http://localhost:56684") self.receiver.start() self.receiver.connect_to_signal("torrent_added", self.torrent_added_signal) @@ -49,7 +49,7 @@ class Signals: self.torrent_all_paused) self.receiver.connect_to_signal("torrent_all_resumed", self.torrent_all_resumed) - + def torrent_added_signal(self, torrent_id): log.debug("torrent_added signal received..") log.debug("torrent id: %s", torrent_id) diff --git a/deluge/ui/gtkui/statusbar.py b/deluge/ui/gtkui/statusbar.py index 64d0f9379..5d619bc8d 100644 --- a/deluge/ui/gtkui/statusbar.py +++ b/deluge/ui/gtkui/statusbar.py @@ -34,13 +34,12 @@ import gtk import deluge.common -import deluge.ui.functions as functions +import deluge.ui.client as client class StatusBar: def __init__(self, window): self.window = window self.statusbar = self.window.main_glade.get_widget("statusbar") - self.core = functions.get_core() # Add a HBox to the statusbar after removing the initial label widget self.hbox = gtk.HBox() @@ -69,36 +68,36 @@ class StatusBar: expand=False, fill=False) # Update once before showing - self.update() +# self.update() self.statusbar.show_all() def update(self): # Set the max connections label - max_connections = functions.get_config_value("max_connections_global") + max_connections = client.get_config_value("max_connections_global") if max_connections < 0: max_connections = _("Unlimited") self.label_connections.set_text("%s (%s)" % ( - self.core.get_num_connections(), max_connections)) + client.get_num_connections(), max_connections)) # Set the download speed label - max_download_speed = functions.get_config_value("max_download_speed") + max_download_speed = client.get_config_value("max_download_speed") if max_download_speed < 0: max_download_speed = _("Unlimited") else: max_download_speed = "%s %s" % (max_download_speed, _("KiB/s")) self.label_download_speed.set_text("%s/s (%s)" % ( - deluge.common.fsize(self.core.get_download_rate()), + deluge.common.fsize(client.get_download_rate()), max_download_speed)) # Set the upload speed label - max_upload_speed = functions.get_config_value("max_upload_speed") + max_upload_speed = client.get_config_value("max_upload_speed") if max_upload_speed < 0: max_upload_speed = _("Unlimited") else: max_upload_speed = "%s %s" % (max_upload_speed, _("KiB/s")) self.label_upload_speed.set_text("%s/s (%s)" % ( - deluge.common.fsize(self.core.get_upload_rate()), + deluge.common.fsize(client.get_upload_rate()), max_upload_speed)) diff --git a/deluge/ui/gtkui/systemtray.py b/deluge/ui/gtkui/systemtray.py index 14767206d..3f85072be 100644 --- a/deluge/ui/gtkui/systemtray.py +++ b/deluge/ui/gtkui/systemtray.py @@ -34,7 +34,7 @@ import gtk import pkg_resources -import deluge.ui.functions as functions +import deluge.ui.client as client import deluge.common from deluge.configmanager import ConfigManager from deluge.log import LOG as log @@ -49,7 +49,6 @@ class SystemTray: def enable(self): """Enables the system tray icon.""" log.debug("Enabling the system tray icon..") - self.core = functions.get_core() self.tray = gtk.status_icon_new_from_icon_name('deluge') self.tray.connect("activate", self.on_tray_clicked) self.tray.connect("popup-menu", self.on_tray_popup) @@ -79,6 +78,7 @@ class SystemTray: self.tray_glade.get_widget("upload-limit-image").set_from_file( deluge.common.get_pixmap("seeding16.png")) + def start(self): # Build the bandwidth speed limit menus self.build_tray_bwsetsubmenu() @@ -86,13 +86,13 @@ class SystemTray: # Create the Download speed list sub-menu submenu_bwdownset = self.build_menu_radio_list( self.config["tray_download_speed_list"], self.tray_setbwdown, - functions.get_config_value("max_download_speed"), + client.get_config_value("max_download_speed"), _("KiB/s"), show_notset=True, show_other=True) # Create the Upload speed list sub-menu submenu_bwupset = self.build_menu_radio_list( self.config["tray_upload_speed_list"], self.tray_setbwup, - functions.get_config_value("max_upload_speed"), + client.get_config_value("max_upload_speed"), _("KiB/s"), show_notset=True, show_other=True) # Add the sub-menus to the tray menu @@ -160,7 +160,7 @@ class SystemTray: def on_menuitem_add_torrent_activate(self, menuitem): log.debug("on_menuitem_add_torrent_activate") from addtorrentdialog import AddTorrentDialog - functions.add_torrent_file(AddTorrentDialog().run()) + client.add_torrent_file(AddTorrentDialog().run()) def on_menuitem_pause_all_activate(self, menuitem): log.debug("on_menuitem_pause_all_activate") @@ -184,13 +184,13 @@ class SystemTray: log.debug("on_menuitem_quitdaemon_activate") if self.window.visible(): self.window.quit() - functions.shutdown() + client.shutdown() else: if self.config["lock_tray"] == True: self.unlock_tray("quitdaemon") else: self.window.quit() - functions.shutdown() + client.shutdown() def build_menu_radio_list(self, value_list, callback, pref_value=None, suffix=None, show_notset=False, notset_label=None, notset_lessthan=0, @@ -281,7 +281,7 @@ class SystemTray: spin_title.set_text(_("%s Speed (KiB/s):" % string)) spin_speed = dialog_glade.get_widget("spin_speed") spin_speed.set_value( - functions.get_config_value(core_key)) + client.get_config_value(core_key)) spin_speed.select_region(0, -1) response = speed_dialog.run() if response == 1: # OK Response @@ -294,7 +294,7 @@ class SystemTray: # Set the config in the core value = float(value) config_to_set = {core_key: value} - functions.set_config(config_to_set) + client.set_config(config_to_set) # Update the tray speed limit list if value not in self.config[ui_key] and value >= 0: @@ -338,7 +338,7 @@ window, please enter your password")) log.debug("Showing main window via tray") self.window.show() elif comingnext == "quitdaemon": - functions.shutdown() + client.shutdown() self.window.hide() self.window.quit() elif comingnext == "quitui": diff --git a/deluge/ui/gtkui/torrentdetails.py b/deluge/ui/gtkui/torrentdetails.py index 03cc0c0bf..df36673ec 100644 --- a/deluge/ui/gtkui/torrentdetails.py +++ b/deluge/ui/gtkui/torrentdetails.py @@ -38,7 +38,7 @@ pygtk.require('2.0') import gtk, gtk.glade import gettext -import deluge.ui.functions as functions +import deluge.ui.client as client import deluge.common from deluge.log import LOG as log @@ -93,7 +93,7 @@ class TorrentDetails: "upload_payload_rate", "num_peers", "num_seeds", "total_peers", "total_seeds", "eta", "ratio", "tracker", "next_announce", "tracker_status", "save_path"] - status = functions.get_torrent_status(selected, status_keys) + status = client.get_torrent_status(selected, status_keys) # Check to see if we got valid data from the core if status is None: diff --git a/deluge/ui/gtkui/torrentview.py b/deluge/ui/gtkui/torrentview.py index dbf961862..f01649fff 100644 --- a/deluge/ui/gtkui/torrentview.py +++ b/deluge/ui/gtkui/torrentview.py @@ -40,7 +40,7 @@ import gettext import gobject import deluge.common -import deluge.ui.functions as functions +import deluge.ui.client as client from deluge.log import LOG as log import deluge.ui.gtkui.listview as listview @@ -163,12 +163,14 @@ class TorrentView(listview.ListView): self.treeview.get_selection().connect("changed", self.on_selection_changed) + def start(self): + """Start the torrentview""" # We need to get the core session state to know which torrents are in # the session so we can add them to our list. - session_state = functions.get_session_state() + session_state = client.get_session_state() for torrent_id in session_state: self.add_row(torrent_id) - + def update(self, columns=None): """Update the view. If columns is not None, it will attempt to only update those columns selected. @@ -212,7 +214,7 @@ class TorrentView(listview.ListView): # Remove duplicates from status_key list status_keys = list(set(status_keys)) - status = functions.get_torrent_status(torrent_id, + status = client.get_torrent_status(torrent_id, status_keys) # Set values for each column in the row diff --git a/deluge/ui/signalreceiver.py b/deluge/ui/signalreceiver.py index 2df0435e2..0c1f7e08e 100644 --- a/deluge/ui/signalreceiver.py +++ b/deluge/ui/signalreceiver.py @@ -48,6 +48,8 @@ class SignalReceiver( log.debug("SignalReceiver init..") threading.Thread.__init__(self) + self.port = port + # Daemonize the thread so it exits when the main program does self.setDaemon(True) @@ -68,7 +70,11 @@ class SignalReceiver( # FIXME: send actual URI not localhost core = xmlrpclib.ServerProxy(core_uri) core.register_client("http://localhost:" + str(port)) + + def __del__(self): + core.deregister_client("http://localhost:" + str(self.port)) + def run(self): """This gets called when we start the thread""" t = threading.Thread(target=self.serve_forever)