From 35fe99eee3fadd43d4466bd07fb09685cc21eec4 Mon Sep 17 00:00:00 2001 From: Andrew Resch Date: Sat, 17 Nov 2007 11:36:29 +0000 Subject: [PATCH] Updates to the QueuedTorrents dialog stuff. Updates to StatusBar. --- TODO | 6 +- deluge/core/torrentmanager.py | 3 +- deluge/ui/gtkui/dbusinterface.py | 58 +------ deluge/ui/gtkui/glade/queuedtorrents.glade | 70 +++------ deluge/ui/gtkui/gtkui.py | 12 +- deluge/ui/gtkui/queuedtorrents.py | 166 +++++++++++++++++++++ deluge/ui/gtkui/statusbar.py | 83 +++++++---- 7 files changed, 260 insertions(+), 138 deletions(-) create mode 100644 deluge/ui/gtkui/queuedtorrents.py diff --git a/TODO b/TODO index 6e9b9a488..6e590d209 100644 --- a/TODO +++ b/TODO @@ -22,7 +22,5 @@ * Add a health indication to the statusbar * Add sidebar for labels and other things.. Plugins should be able to add their own section to this. -* Have the dbus interface queue up torrents if we're not connected to a host. - Once connected it should prompt the user if they would like to add the - queued torrents. Maybe add an indicator to the status bar that their are - queued torrents. +* Finish queuedtorrents dialog +* Update statusbar to use new statusbaritems diff --git a/deluge/core/torrentmanager.py b/deluge/core/torrentmanager.py index 8d83efbfb..6bde4360b 100644 --- a/deluge/core/torrentmanager.py +++ b/deluge/core/torrentmanager.py @@ -341,7 +341,8 @@ class TorrentManager: """Force a tracker reannounce""" try: self.torrents[torrent_id].handle.force_reannounce() - except: + except Exception, e: + log.debug("Unable to force reannounce: %s", e) return False return True diff --git a/deluge/ui/gtkui/dbusinterface.py b/deluge/ui/gtkui/dbusinterface.py index 719489210..d4699f526 100644 --- a/deluge/ui/gtkui/dbusinterface.py +++ b/deluge/ui/gtkui/dbusinterface.py @@ -52,9 +52,7 @@ from deluge.log import LOG as log class DbusInterface(dbus.service.Object, component.Component): def __init__(self, args, path="/org/deluge_torrent/Deluge"): - component.Component.__init__(self, "DbusInterface", ["StatusBar"]) - self.queue = [] - self.widgets = None + component.Component.__init__(self, "DbusInterface") # Check to see if the daemon is already running and if not, start it bus = dbus.SessionBus() obj = bus.get_object("org.freedesktop.DBus", "/org/freedesktop/DBus") @@ -89,58 +87,6 @@ class DbusInterface(dbus.service.Object, component.Component): bus=dbus.SessionBus()) dbus.service.Object.__init__(self, bus_name, path) - def start(self): - """Called when we connect to a host""" - log.debug("DbusInterface start..") - if len(self.queue) == 0: - return - # Make sure status bar info is showing - self.widgets = None - self.update_status_bar() - - def add_to_queue(self, torrents): - """Adds the list of torrents to the queue""" - # Add to the queue while removing duplicates - self.queue = list(set(self.queue + torrents)) - - # Update the status bar - self.update_status_bar() - - def update_status_bar(self): - """Attempts to update status bar""" - # If there are no queued torrents.. remove statusbar widgets and return - if len(self.queue) == 0: - if self.widgets != None: - for widget in self.widgets: - component.get("StatusBar").remove(widget) - return False - - try: - statusbar = component.get("StatusBar") - except Exception, e: - # The statusbar hasn't been loaded yet, so we'll add a timer to - # update it later. - gobject.timeout_add(100, self.update_status_bar) - return False - - # Set the label text for statusbar - if len(self.queue) > 1: - label = str(len(self.queue)) + _(" Torrents Queued") - else: - label = str(len(self.queue)) + _(" Torrent Queued") - - # Add the statusbar items if needed, or just modify the label if they - # have already been added. - if self.widgets == None: - self.widgets = component.get("StatusBar").add_item( - stock=gtk.STOCK_SORT_DESCENDING, - text=label) - else: - self.widgets[1].set_text(label) - - # We return False so the timer stops - return False - @dbus.service.method("org.deluge_torrent.Deluge", in_signature="as") def process_args(self, args): """Process arguments sent to already running Deluge""" @@ -153,7 +99,7 @@ class DbusInterface(dbus.service.Object, component.Component): if not client.connected(): # We're not connected so add these to the queue log.debug("Not connected to host.. Adding to queue.") - self.add_to_queue(args) + component.get("QueuedTorrents").add_to_queue(args) return for arg in args: diff --git a/deluge/ui/gtkui/glade/queuedtorrents.glade b/deluge/ui/gtkui/glade/queuedtorrents.glade index dc59ada44..2428c89e9 100644 --- a/deluge/ui/gtkui/glade/queuedtorrents.glade +++ b/deluge/ui/gtkui/glade/queuedtorrents.glade @@ -1,14 +1,17 @@ - + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK 5 + Queued Torrents GTK_WIN_POS_CENTER_ON_PARENT + 450 + 300 True - . GDK_WINDOW_TYPE_HINT_DIALOG + False True @@ -23,7 +26,7 @@ True GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - 5 + 10 True @@ -39,6 +42,8 @@ True GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + 0.05000000074505806 + 10 <big><b>Add Queued Torrents</b></big> True @@ -63,11 +68,11 @@ GTK_POLICY_AUTOMATIC GTK_SHADOW_IN - + True True GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - True + False @@ -115,49 +120,17 @@ - + 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 - 11 - - - 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 - Automatically add torrents on connect - 0 - True - - - False - False - - - - - - - - - True - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - Options - - - label_item - - + Automatically add torrents on connect + 0 + True + False + False 3 @@ -172,21 +145,26 @@ 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 + gtk-close True 0 - + True + False True + True + True + True + True True GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK gtk-add diff --git a/deluge/ui/gtkui/gtkui.py b/deluge/ui/gtkui/gtkui.py index 94a2ac5b2..5757b80fb 100644 --- a/deluge/ui/gtkui/gtkui.py +++ b/deluge/ui/gtkui/gtkui.py @@ -52,6 +52,7 @@ from connectionmanager import ConnectionManager from signals import Signals from pluginmanager import PluginManager from dbusinterface import DbusInterface +from queuedtorrents import QueuedTorrents from deluge.configmanager import ConfigManager from deluge.log import LOG as log import deluge.configmanager @@ -87,10 +88,6 @@ DEFAULT_PREFS = { class GtkUI: def __init__(self, args): - # Start the Dbus Interface before anything else.. Just in case we are - # already running. - self.dbusinterface = DbusInterface(args) - # Initialize gettext locale.setlocale(locale.LC_MESSAGES, '') locale.bindtextdomain("deluge", @@ -107,7 +104,12 @@ class GtkUI: # Make sure gtkui.conf has at least the defaults set config = ConfigManager("gtkui.conf", DEFAULT_PREFS) - + + # Start the Dbus Interface before anything else.. Just in case we are + # already running. + self.queuedtorrents = QueuedTorrents() + self.dbusinterface = DbusInterface(args) + # We make sure that the UI components start once we get a core URI client.connect_on_new_core(component.start) client.connect_on_no_core(component.stop) diff --git a/deluge/ui/gtkui/queuedtorrents.py b/deluge/ui/gtkui/queuedtorrents.py new file mode 100644 index 000000000..face40986 --- /dev/null +++ b/deluge/ui/gtkui/queuedtorrents.py @@ -0,0 +1,166 @@ +# +# queuedtorrents.py +# +# Copyright (C) 2007 Andrew Resch ('andar') +# +# Deluge is free software. +# +# You may redistribute it and/or modify it under the terms of the +# GNU General Public License, as published by the Free Software +# Foundation; either version 2 of the License, or (at your option) +# any later version. +# +# deluge is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# See the GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with deluge. If not, write to: +# 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 +# library. +# You must obey the GNU General Public License in all respects for all of +# the code used other than OpenSSL. If you modify file(s) with this +# exception, you may extend this exception to your version of the file(s), +# but you are not obligated to do so. If you do not wish to do so, delete +# 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.path + +import gtk, gtk.glade +import pkg_resources + +import deluge.ui.component as component +import deluge.ui.client as client +import deluge.common +from deluge.log import LOG as log + +class QueuedTorrents(component.Component): + def __init__(self): + component.Component.__init__(self, "QueuedTorrents", ["StatusBar"]) + self.queue = [] + self.status_item = None + + self.glade = gtk.glade.XML( + pkg_resources.resource_filename("deluge.ui.gtkui", + "glade/queuedtorrents.glade")) + + self.dialog = self.glade.get_widget("queued_torrents_dialog") + self.dialog.set_icon(deluge.common.get_logo(32)) + + self.glade.signal_autoconnect({ + "on_button_remove_clicked": self.on_button_remove_clicked, + "on_button_clear_clicked": self.on_button_clear_clicked, + "on_button_close_clicked": self.on_button_close_clicked, + "on_button_add_clicked": self.on_button_add_clicked + }) + + self.treeview = self.glade.get_widget("treeview") + self.treeview.append_column( + gtk.TreeViewColumn(_("Torrent"), gtk.CellRendererText(), text=0)) + + self.liststore = gtk.ListStore(str, str) + self.treeview.set_model(self.liststore) + + def run(self): + self.dialog.set_transient_for(component.get("MainWindow").window) + self.dialog.show() + + def start(self): + if len(self.queue) == 0: + return + # Make sure status bar info is showing + self.status_item = None + self.update_status_bar() + # We only want the add button sensitive if we're connected to a host + self.glade.get_widget("button_add").set_sensitive(True) + self.run() + + def stop(self): + # We only want the add button sensitive if we're connected to a host + self.glade.get_widget("button_add").set_sensitive(False) + + def add_to_queue(self, torrents): + """Adds the list of torrents to the queue""" + # Add to the queue while removing duplicates + self.queue = list(set(self.queue + torrents)) + + # Update the liststore + self.liststore.clear() + for torrent in self.queue: + self.liststore.append([os.path.split(torrent)[1], torrent]) + + # Update the status bar + self.update_status_bar() + + def update_status_bar(self): + """Attempts to update status bar""" + # If there are no queued torrents.. remove statusbar widgets and return + if len(self.queue) == 0: + if self.status_item != None: + component.get("StatusBar").remove_item(self.status_item) + self.status_item = None + return False + + try: + statusbar = component.get("StatusBar") + except Exception, e: + # The statusbar hasn't been loaded yet, so we'll add a timer to + # update it later. + gobject.timeout_add(100, self.update_status_bar) + return False + + # Set the label text for statusbar + if len(self.queue) > 1: + label = str(len(self.queue)) + _(" Torrents Queued") + else: + label = str(len(self.queue)) + _(" Torrent Queued") + + # Add the statusbar items if needed, or just modify the label if they + # have already been added. + if self.status_item == None: + self.status_item = component.get("StatusBar").add_item( + stock=gtk.STOCK_SORT_DESCENDING, + text=label, + callback=self.on_statusbar_click) + else: + self.status_item.set_text(label) + + # We return False so the timer stops + return False + + def on_statusbar_click(self, widget, event): + log.debug("on_statusbar_click") + self.run() + + def on_button_remove_clicked(self, widget): + selected = self.treeview.get_selection().get_selected()[1] + if selected != None: + path = self.liststore.get_value(selected, 1) + self.liststore.remove(selected) + self.queue.remove(path) + self.update_status_bar() + + def on_button_clear_clicked(self, widget): + self.liststore.clear() + self.update_status_bar() + + def on_button_close_clicked(self, widget): + self.dialog.hide() + + def on_button_add_clicked(self, widget): + # Add all the torrents in the liststore + def add_torrent(model, path, iter, data): + torrent_path = model.get_value(iter, 1) + client.add_torrent_file([torrent_path]) + + self.liststore.foreach(add_torrent, None) + del self.queue[:] + self.dialog.hide() + self.update_status_bar() diff --git a/deluge/ui/gtkui/statusbar.py b/deluge/ui/gtkui/statusbar.py index 3914a3075..f83a9ea3a 100644 --- a/deluge/ui/gtkui/statusbar.py +++ b/deluge/ui/gtkui/statusbar.py @@ -38,6 +38,57 @@ import deluge.common import deluge.ui.client as client from deluge.log import LOG as log +class StatusBarItem: + def __init__(self, image=None, stock=None, text=None, callback=None): + self._widgets = [] + self._ebox = gtk.EventBox() + self._hbox = gtk.HBox() + self._image = gtk.Image() + self._label = gtk.Label() + self._hbox.add(self._image) + self._hbox.add(self._label) + self._ebox.add(self._hbox) + + # Add image from file or stock + if image != None or stock != None: + if image != None: + self.set_image_from_file(image) + if stock != None: + self.set_image_from_stock(stock) + + # Add text + if text != None: + self.set_text(text) + + if callback != None: + self.set_callback(callback) + + self.show_all() + + def set_callback(self, callback): + self._ebox.connect("button-press-event", callback) + + def show_all(self): + self._ebox.show() + self._hbox.show() + self._image.show() + self._label.show() + + def set_image_from_file(self, image): + self._image.set_from_file(image) + + def set_image_from_stock(self, stock): + self._image.set_from_stock(stock, gtk.ICON_SIZE_MENU) + + def set_text(self, text): + self._label.set_text(text) + + def get_widgets(self): + return self._widgets() + + def get_eventbox(self): + return self._ebox + class StatusBar(component.Component): def __init__(self): component.Component.__init__(self, "StatusBar") @@ -90,37 +141,17 @@ class StatusBar(component.Component): self.hbox.pack_start(label, expand=False, fill=False) self.statusbar.show_all() - def add_item(self, image=None, stock=None, text=None): + def add_item(self, image=None, stock=None, text=None, callback=None): """Adds an item to the status bar""" # The return tuple.. we return whatever widgets we add - ret = [] - # Add image from file or stock - if image != None or stock != None: - _image = gtk.Image() - if image != None: - _image.set_from_file(image) - if stock != None: - _image.set_from_stock(stock, gtk.ICON_SIZE_MENU) - self.hbox.pack_start(_image, expand=False, fill=False) - ret.append(_image) - - # Add text - if text != None: - label = gtk.Label(text) - self.hbox.pack_start(label, expand=False, fill=False) - ret.append(label) - - # Show the widgets - for widget in ret: - widget.show() - - # Return the widgets - return tuple(ret) + item = StatusBarItem(image, stock, text, callback) + self.hbox.pack_start(item.get_eventbox(), expand=False, fill=False) + return item - def remove_item(self, widget): + def remove_item(self, item): """Removes an item from the statusbar""" try: - self.hbox.remove(widget) + self.hbox.remove(item.get_eventbox()) except Exception, e: log.debug("Unable to remove widget: %s", e)