From c5d76cf8ee3b6b8b0164c4bfb63960769b238d25 Mon Sep 17 00:00:00 2001 From: Andrew Resch Date: Wed, 29 Aug 2007 08:00:19 +0000 Subject: [PATCH] State saving and loading in core and TorrentQueue. GtkUI now requests a 'session_state' on start-up to populate it's listview. GtkUI can now shutdown core. --- deluge/core/core.py | 22 +- deluge/core/pluginmanager.py | 11 + deluge/core/torrentmanager.py | 56 +- deluge/core/torrentmanagerstate.py | 43 -- deluge/plugins/queue/queue/core.py | 28 +- deluge/plugins/queue/queue/gtkui.py | 64 +- deluge/plugins/queue/queue/torrentqueue.py | 32 +- deluge/ui/functions.py | 19 +- deluge/ui/gtkui/glade/main_window.glade | 823 +++++++++++---------- deluge/ui/gtkui/listview.py | 3 +- deluge/ui/gtkui/menubar.py | 32 +- deluge/ui/gtkui/torrentview.py | 11 +- 12 files changed, 628 insertions(+), 516 deletions(-) delete mode 100644 deluge/core/torrentmanagerstate.py diff --git a/deluge/core/core.py b/deluge/core/core.py index 9661cb737..73271f7bb 100644 --- a/deluge/core/core.py +++ b/deluge/core/core.py @@ -90,6 +90,10 @@ class Core(dbus.service.Object): """Shutdown the core""" log.info("Shutting down core..") self.loop.quit() + del self.torrents + self.plugins.shutdown() + del self.plugins + del self.session @dbus.service.method(dbus_interface="org.deluge_torrent.Deluge", in_signature="say", out_signature="") @@ -97,7 +101,6 @@ class Core(dbus.service.Object): """Adds a torrent file to the libtorrent session This requires the torrents filename and a dump of it's content """ - log.info("Adding torrent: %s", filename) torrent_id = self.torrents.add(filename, filedump) # Run the plugin hooks for 'post_torrent_add' @@ -149,6 +152,23 @@ class Core(dbus.service.Object): status.update(self.plugins.get_status(torrent_id, leftover_fields)) status = pickle.dumps(status) return status + + @dbus.service.method(dbus_interface="org.deluge_torrent.Deluge", + in_signature="", + out_signature="ay") + def get_session_state(self): + """Returns a list of torrent_ids in the session.""" + # Get the torrent list from the TorrentManager + torrent_list = self.torrents.get_torrent_list() + # Pickle the list and send it + session_state = pickle.dumps(torrent_list) + return session_state + + @dbus.service.method(dbus_interface="org.deluge_torrent.Deluge") + def save_state(self): + """Save the current session state to file.""" + # Have the TorrentManager save it's state + self.torrents.save_state() # Signals @dbus.service.signal(dbus_interface="org.deluge_torrent.Deluge", diff --git a/deluge/core/pluginmanager.py b/deluge/core/pluginmanager.py index 7b8b840cb..8c4079a7f 100644 --- a/deluge/core/pluginmanager.py +++ b/deluge/core/pluginmanager.py @@ -71,6 +71,17 @@ class PluginManager: self.plugins[name] = instance log.info("Load plugin %s", name) + def shutdown(self): + log.debug("PluginManager shutting down..") + # Del all plugins to allow them to deconstruct properly + for plugin in self.plugins.values(): + plugin.core.shutdown() + # del plugin + #while plugin is not None: + # del plugin + + del self.plugins + def __getitem__(self, key): return self.plugins[key] diff --git a/deluge/core/torrentmanager.py b/deluge/core/torrentmanager.py index 3cb01d978..aeeeb7cf8 100644 --- a/deluge/core/torrentmanager.py +++ b/deluge/core/torrentmanager.py @@ -41,9 +41,17 @@ import deluge.libtorrent as lt import deluge.common from deluge.config import Config from deluge.core.torrent import Torrent -from deluge.core.torrentmanagerstate import TorrentManagerState, TorrentState from deluge.log import LOG as log +class TorrentState: + def __init__(self, torrent_id, filename): + self.torrent_id = torrent_id + self.filename = filename + +class TorrentManagerState: + def __init__(self): + self.torrents = [] + class TorrentManager: """TorrentManager contains a list of torrents in the current libtorrent session. This object is also responsible for saving the state of the @@ -55,24 +63,40 @@ class TorrentManager: self.session = session # Create the torrents dict { torrent_id: Torrent } self.torrents = {} - + # Try to load the state from file + self.load_state() + + def __del__(self): + log.debug("TorrentManager shutting down..") + # Save state on shutdown + self.save_state() + def __getitem__(self, torrent_id): """Return the Torrent with torrent_id""" return self.torrents[torrent_id] + def get_torrent_list(self): + """Returns a list of torrent_ids""" + return self.torrents.keys() + def add(self, filename, filedump=None): """Add a torrent to the manager and returns it's torrent_id""" + log.info("Adding torrent: %s", filename) # Get the core config config = Config("core.conf") - + + # Make sure 'filename' is a python string + filename = str(filename) + # Convert the filedump data array into a string of bytes if filedump is not None: filedump = "".join(chr(b) for b in filedump) else: # Get the data from the file try: + log.debug("Attempting to open %s for add.", filename) filedump = open(os.path.join(config["torrentfiles_location"], - filename, "rb")).read() + filename), "rb").read() except IOError: log.warning("Unable to open %s", filename) return None @@ -104,10 +128,13 @@ class TorrentManager: except IOError: log.warning("Unable to save torrent file: %s", filename) + log.debug("Torrent %s added.", handle.info_hash()) # Create a Torrent object torrent = Torrent(filename, handle) # Add the torrent object to the dictionary self.torrents[torrent.torrent_id] = torrent + # Save the session state + self.save_state() return torrent.torrent_id def remove(self, torrent_id): @@ -123,6 +150,8 @@ class TorrentManager: del self.torrents[torrent_id] except KeyError, ValueError: return False + # Save the session state + self.save_state() return True def pause(self, torrent_id): @@ -142,13 +171,30 @@ class TorrentManager: return False return True + + def load_state(self): + """Load the state of the TorrentManager from the torrents.state file""" + state = TorrentManagerState() + try: + log.debug("Opening torrent state file for load.") + state_file = open(deluge.common.get_config_dir("torrents.state"), + "rb") + state = pickle.load(state_file) + state_file.close() + except IOError: + log.warning("Unable to load state file.") + + # Try to add the torrents in the state to the session + for torrent_state in state.torrents: + self.add(torrent_state.filename) + def save_state(self): """Save the state of the TorrentManager to the torrents.state file""" state = TorrentManagerState() # Create the state for each Torrent and append to the list for torrent in self.torrents.values(): - torrent_state = TorrentState(torrent.get_state()) + torrent_state = TorrentState(*torrent.get_state()) state.torrents.append(torrent_state) # Pickle the TorrentManagerState object diff --git a/deluge/core/torrentmanagerstate.py b/deluge/core/torrentmanagerstate.py deleted file mode 100644 index 5a7d0b1b9..000000000 --- a/deluge/core/torrentmanagerstate.py +++ /dev/null @@ -1,43 +0,0 @@ -# -# torrentmanagerstate.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. - -from deluge.log import LOG as log - -class TorrentState: - def __init__(self, torrent_id, filename): - self.torrent_id = torrent_id - self.filename = filename - -class TorrentManagerState: - def __init__(self): - self.torrents = [] diff --git a/deluge/plugins/queue/queue/core.py b/deluge/plugins/queue/queue/core.py index 0f6d5c32e..568da2e62 100644 --- a/deluge/plugins/queue/queue/core.py +++ b/deluge/plugins/queue/queue/core.py @@ -31,25 +31,13 @@ # 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 logging - -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): - import dbus.glib - elif dbus_version >= (0,80,0): - from dbus.mainloop.glib import DBusGMainLoop - DBusGMainLoop(set_as_default=True) - else: - pass -except: dbus_imported = False -else: dbus_imported = True +import dbus +import dbus.service +from dbus.mainloop.glib import DBusGMainLoop +DBusGMainLoop(set_as_default=True) from torrentqueue import TorrentQueue - -# Get the logger -log = logging.getLogger("deluge") +from deluge.log import LOG as log class Core(dbus.service.Object): def __init__(self, plugin, path="/org/deluge_torrent/Plugin/Queue"): @@ -62,7 +50,7 @@ class Core(dbus.service.Object): dbus.service.Object.__init__(self, bus_name, path) - # Instantiate the TorrentQueue object + # Instantiate the TorrentQueue object self.queue = TorrentQueue() # Register core hooks @@ -75,6 +63,10 @@ class Core(dbus.service.Object): log.info("Queue Core plugin initialized..") + def shutdown(self): + # Save the queue state + self.queue.save_state() + ## Hooks for core ## def post_torrent_add(self, torrent_id): if torrent_id is not None: diff --git a/deluge/plugins/queue/queue/gtkui.py b/deluge/plugins/queue/queue/gtkui.py index c9cff5f26..448d2d3c2 100644 --- a/deluge/plugins/queue/queue/gtkui.py +++ b/deluge/plugins/queue/queue/gtkui.py @@ -66,7 +66,17 @@ class GtkUI: menu_glade = gtk.glade.XML(pkg_resources.resource_filename("queue", "glade/queuemenu.glade")) - menu = menu_glade.get_widget("menu_queue") + menu_glade.signal_autoconnect({ + "on_menuitem_queuetop_activate": \ + self.on_menuitem_queuetop_activate, + "on_menuitem_queueup_activate": self.on_menuitem_queueup_activate, + "on_menuitem_queuedown_activate": \ + self.on_menuitem_queuedown_activate, + "on_menuitem_queuebottom_activate": \ + self.on_menuitem_queuebottom_activate + }) + + menu = menu_glade.get_widget("menu_queue") # Connect to the 'torrent_queue_changed' signal self.core.connect_to_signal("torrent_queue_changed", @@ -79,17 +89,20 @@ class GtkUI: col_type=int, position=0, status_field=["queue"]) + # Update the new column right away + self.torrentview.update(["#"]) + # Add a toolbar buttons self.plugin.get_toolbar().add_separator() self.plugin.get_toolbar().add_toolbutton(stock="gtk-go-up", label="Queue Up", tooltip="Queue selected torrents up", - callback=self.on_queueup_toolbutton_clicked) + callback=self.on_toolbutton_queueup_clicked) self.plugin.get_toolbar().add_toolbutton(stock="gtk-go-down", label="Queue Down", tooltip="Queue selected torrents down", - callback=self.on_queuedown_toolbutton_clicked) + callback=self.on_toolbutton_queuedown_clicked) # Add the queue menu to the torrent menu queue_menuitem = gtk.ImageMenuItem("Queue") @@ -98,23 +111,58 @@ class GtkUI: queue_menuitem.set_image(queue_image) queue_menuitem.set_submenu(menu) self.plugin.get_torrentmenu().append(queue_menuitem) - - def on_queuedown_toolbutton_clicked(self, widget): - log.debug("Queue down toolbutton clicked.") + + ## Menu callbacks ## + def on_menuitem_queuetop_activate(self, data=None): + log.debug("on_menuitem_queuetop_activate") + # Get the selected torrents + torrent_ids = self.plugin.get_selected_torrents() + for torrent_id in torrent_ids: + self.core.queue_top(torrent_id) + return + + def on_menuitem_queueup_activate(self, data=None): + log.debug("on_menuitem_queueup_activate") + # Get the selected torrents + torrent_ids = self.plugin.get_selected_torrents() + for torrent_id in torrent_ids: + self.core.queue_up(torrent_id) + return + + def on_menuitem_queuedown_activate(self, data=None): + log.debug("on_menuitem_queuedown_activate") + # Get the selected torrents + torrent_ids = self.plugin.get_selected_torrents() + for torrent_id in torrent_ids: + self.core.queue_down(torrent_id) + return + + def on_menuitem_queuebottom_activate(self, data=None): + log.debug("on_menuitem_queuebottom_activate") + # Get the selected torrents + torrent_ids = self.plugin.get_selected_torrents() + for torrent_id in torrent_ids: + self.core.queue_bottom(torrent_id) + return + + ## Toolbutton callbacks ## + def on_toolbutton_queuedown_clicked(self, widget): + log.debug("on_toolbutton_queuedown_clicked") # Get the selected torrents torrent_ids = self.plugin.get_selected_torrents() for torrent_id in torrent_ids: self.core.queue_down(torrent_id) return - def on_queueup_toolbutton_clicked(self, widget): - log.debug("Queue Up toolbutton clicked.") + def on_toolbutton_queueup_clicked(self, widget): + log.debug("on_toolbutton_queueup_clicked") # Get the selected torrents torrent_ids = self.plugin.get_selected_torrents() for torrent_id in torrent_ids: self.core.queue_up(torrent_id) return + ## Signals ## def torrent_queue_changed_signal(self): """This function is called whenever we receive a 'torrent_queue_changed' signal from the core plugin. diff --git a/deluge/plugins/queue/queue/torrentqueue.py b/deluge/plugins/queue/queue/torrentqueue.py index 5ce3a2ed8..9a5e6de52 100644 --- a/deluge/plugins/queue/queue/torrentqueue.py +++ b/deluge/plugins/queue/queue/torrentqueue.py @@ -31,19 +31,45 @@ # 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 logging +import pickle -# Get the logger -log = logging.getLogger("deluge") +import deluge.common +from deluge.log import LOG as log class TorrentQueue: def __init__(self): self.queue = [] + # Try to load the queue state from file + self.load_state() def __getitem__(self, torrent_id): """Return the queue position of the torrent_id""" return self.queue.index(torrent_id) + def load_state(self): + """Load the queue state""" + try: + log.debug("Opening queue state file for load.") + state_file = open(deluge.common.get_config_dir("queue.state"), + "rb") + state = pickle.load(state_file) + state_file.close() + self.queue = state + except IOError: + log.warning("Unable to load queue state file.") + + + def save_state(self): + """Save the queue state""" + try: + log.debug("Saving queue state file.") + state_file = open(deluge.common.get_config_dir("queue.state"), + "wb") + pickle.dump(self.queue, state_file) + state_file.close() + except IOError: + log.warning("Unable to save queue state file.") + def append(self, torrent_id): """Append torrent_id to the bottom of the queue""" log.debug("Append torrent %s to queue..", torrent_id) diff --git a/deluge/ui/functions.py b/deluge/ui/functions.py index fde7f6a13..c40e84a06 100644 --- a/deluge/ui/functions.py +++ b/deluge/ui/functions.py @@ -63,7 +63,13 @@ def get_core_plugin(plugin): "/org/deluge_torrent/Plugin/" + plugin) core = dbus.Interface(proxy, "org.deluge_torrent.Deluge." + plugin) return core - + +def shutdown(): + """Shutdown the core daemon""" + core = get_core() + core.shutdown() + return + def add_torrent_file(torrent_files): """Adds torrent files to the core Expects a list of torrent files @@ -118,3 +124,14 @@ def get_torrent_status(core, torrent_id, keys): # De-serialize the object status = pickle.loads(status) return status + +def get_session_state(core=None): + # Get the core if not supplied + if core is None: + core = get_core() + state = core.get_session_state() + # Join the array of bytes into a string for pickle to read + state = "".join(chr(b) for b in state) + # De-serialize the object + state = pickle.loads(state) + return state diff --git a/deluge/ui/gtkui/glade/main_window.glade b/deluge/ui/gtkui/glade/main_window.glade index cdfa9f306..0433e3af4 100644 --- a/deluge/ui/gtkui/glade/main_window.glade +++ b/deluge/ui/gtkui/glade/main_window.glade @@ -68,6 +68,7 @@ GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK Quit & Shutdown Daemon True + gtk-quit @@ -343,253 +344,6 @@ 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 - 6 - 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>Next Announce:</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 Status:</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 - 0 - 1 - <b>Tracker:</b> - True - - - - - 3 - 4 - 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>Pieces:</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>Total Size:</b> - True - - - - - 1 - 2 - 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 - - - - - - True - 0 - - - 1 - 2 - 1 - 2 - - - - - - True - 0 - - - 1 - 2 - 2 - 3 - - - - - - True - 0 - True - PANGO_WRAP_WORD_CHAR - - - 1 - 2 - 3 - 4 - - - - - - True - 0 - - - 1 - 2 - 4 - 5 - - - - - - True - 0 - - - 1 - 2 - 5 - 6 - - - - - - - - - - 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 @@ -622,36 +376,175 @@ 4 5 - + True - 15 - 5 - - - True - 0 - <b>ETA:</b> - True - - + 0 - 2 - 3 + 1 + 2 + + + + + True + 0 + + + 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>Peers:</b> + <b>Rate:</b> True @@ -659,8 +552,6 @@ 2 3 - 2 - 3 @@ -685,15 +576,15 @@ - + True 15 5 - + True 0 - <b>Rate:</b> + <b>Peers:</b> True @@ -701,168 +592,31 @@ 2 3 - - - - - True - 5 - - - True - 0 - <b>Share Ratio:</b> - True - - - - - 3 - 4 - - - - - True - 5 - - - True - 0 - <b>Seeders:</b> - True - - - - 2 3 - + True + 15 5 - + True 0 - <b>Uploaded:</b> + <b>ETA:</b> True - 1 - 2 - - - - - True - 5 - - - True - 0 - <b>Downloaded:</b> - True - - - - - - - True - 0 - - - 3 - 4 + 2 + 3 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 - - False @@ -890,6 +644,253 @@ 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 + 6 + 2 + 2 + + + True + 0 + + + 1 + 2 + 5 + 6 + + + + + + True + 0 + + + 1 + 2 + 4 + 5 + + + + + + True + 0 + True + PANGO_WRAP_WORD_CHAR + + + 1 + 2 + 3 + 4 + + + + + + True + 0 + + + 1 + 2 + 2 + 3 + + + + + + True + 0 + + + 1 + 2 + 1 + 2 + + + + + + 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 + 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>Total Size:</b> + True + + + + + 1 + 2 + 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>Pieces:</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 + 0 + 1 + <b>Tracker:</b> + True + + + + + 3 + 4 + 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 + + + + + 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>Next Announce:</b> + True + + + + + 5 + 6 + 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 + + diff --git a/deluge/ui/gtkui/listview.py b/deluge/ui/gtkui/listview.py index 1b670a52d..ea7a99d1a 100644 --- a/deluge/ui/gtkui/listview.py +++ b/deluge/ui/gtkui/listview.py @@ -185,11 +185,12 @@ class ListView: # being the new liststore and the columns list def copy_row(model, path, row, user_data): new_list, columns = user_data + new_row = new_list.append() for column in range(model.get_n_columns()): # Get the current value of the column for this row value = model.get_value(row, column) # Set the value of this row and column in the new liststore - new_list.set_value(row, column, value) + new_list.set_value(new_row, column, value) # Do the actual row copy if self.liststore is not None: diff --git a/deluge/ui/gtkui/menubar.py b/deluge/ui/gtkui/menubar.py index e5509d671..56682196b 100644 --- a/deluge/ui/gtkui/menubar.py +++ b/deluge/ui/gtkui/menubar.py @@ -66,6 +66,8 @@ class MenuBar: "on_menuitem_addurl_activate": self.on_menuitem_addurl_activate, "on_menuitem_clear_activate": \ self.on_menuitem_clear_activate, + "on_menuitem_quitdaemon_activate": \ + self.on_menuitem_quitdaemon_activate, "on_menuitem_quit_activate": self.on_menuitem_quit_activate, ## Edit Menu @@ -90,13 +92,7 @@ class MenuBar: "on_menuitem_edittrackers_activate": \ self.on_menuitem_edittrackers_activate, "on_menuitem_remove_activate": self.on_menuitem_remove_activate, - "on_menuitem_queuetop_activate": \ - self.on_menuitem_queuetop_activate, - "on_menuitem_queueup_activate": self.on_menuitem_queueup_activate, - "on_menuitem_queuedown_activate": \ - self.on_menuitem_queuedown_activate, - "on_menuitem_queuebottom_activate": \ - self.on_menuitem_queuebottom_activate + }) ### Callbacks ### @@ -112,6 +108,12 @@ class MenuBar: def on_menuitem_clear_activate(self, data=None): log.debug("on_menuitem_clear_activate") + + def on_menuitem_quitdaemon_activate(self, data=None): + log.debug("on_menuitem_quitdaemon_activate") + # Tell the core to shutdown + functions.shutdown() + self.window.quit() def on_menuitem_quit_activate(self, data=None): log.debug("on_menuitem_quit_activate") @@ -145,22 +147,6 @@ class MenuBar: log.debug("on_menuitem_remove_activate") functions.remove_torrent( self.window.torrentview.get_selected_torrents()) - - def on_menuitem_queuetop_activate(self, data=None): - log.debug("on_menuitem_queuetop_activate") - functions.queue_top(self.window.torrentview.get_selected_torrents()) - - def on_menuitem_queueup_activate(self, data=None): - log.debug("on_menuitem_queueup_activate") - functions.queue_up(self.window.torrentview.get_selected_torrents()) - - def on_menuitem_queuedown_activate(self, data=None): - log.debug("on_menuitem_queuedown_activate") - functions.queue_down(self.window.torrentview.get_selected_torrents()) - - def on_menuitem_queuebottom_activate(self, data=None): - log.debug("on_menuitem_queuebottom_activate") - functions.queue_bottom(self.window.torrentview.get_selected_torrents()) ## View Menu ## def on_menuitem_toolbar_toggled(self, data=None): diff --git a/deluge/ui/gtkui/torrentview.py b/deluge/ui/gtkui/torrentview.py index d7723703e..fe74236b9 100644 --- a/deluge/ui/gtkui/torrentview.py +++ b/deluge/ui/gtkui/torrentview.py @@ -97,6 +97,13 @@ class TorrentView(listview.ListView): # changes. self.treeview.get_selection().connect("changed", self.on_selection_changed) + + # 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(self.core) + print "session_state:", 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 @@ -165,6 +172,7 @@ class TorrentView(listview.ListView): """Adds a new torrent row to the treeview""" # Insert a new row to the liststore row = self.liststore.append() + print "columnid:", self.columns["torrent_id"].column_indices[0] # Store the torrent id self.liststore.set_value( row, @@ -206,8 +214,7 @@ class TorrentView(listview.ListView): # We only care about right-clicks if event.button == 3: # Show the Torrent menu from the MenuBar - torrentmenu = self.window.menubar.torrentmenu.get_widget( - "torrent_menu") + torrentmenu = self.window.menubar.torrentmenu torrentmenu.popup(None, None, None, event.button, event.time) def on_selection_changed(self, treeselection):