Add Queue functionality from the plugin to the core. This breaks

torrents.state.
This commit is contained in:
Andrew Resch 2008-03-02 04:47:35 +00:00
commit ea3d25e8e1
9 changed files with 293 additions and 59 deletions

View file

@ -519,45 +519,46 @@ class Core(
self.session.set_ip_filter(self.ip_filter) self.session.set_ip_filter(self.ip_filter)
## Queueing functions ## ## Queueing functions ##
def export_queue_top(self, torrent_id): def export_queue_top(self, torrent_ids):
log.debug("Attempting to queue %s to top", torrent_id) log.debug("Attempting to queue %s to top", torrent_ids)
for torrent_id in torrent_ids:
try: try:
# If the queue method returns True, then we should emit a signal # If the queue method returns True, then we should emit a signal
if self.torrents.queue.top(torrent_id): if self.torrents.queue.top(torrent_id):
self._torrent_queue_changed(torrent_id) self._torrent_queue_changed()
except KeyError: except KeyError:
log.warning("torrent_id: %s does not exist in the queue", log.warning("torrent_id: %s does not exist in the queue", torrent_id)
torrent_id)
def export_queue_up(self, torrent_id): def export_queue_up(self, torrent_ids):
log.debug("Attempting to queue %s to up", torrent_id) log.debug("Attempting to queue %s to up", torrent_ids)
for torrent_id in torrent_ids:
try: try:
# If the queue method returns True, then we should emit a signal # If the queue method returns True, then we should emit a signal
if self.torrents.queue.up(torrent_id): if self.torrents.queue.up(torrent_id):
self._torrent_queue_changed(torrent_id) self._torrent_queue_changed()
except KeyError: except KeyError:
log.warning("torrent_id: %s does not exist in the queue", log.warning("torrent_id: %s does not exist in the queue", torrent_id)
torrent_id)
def export_queue_down(self, torrent_id): def export_queue_down(self, torrent_ids):
log.debug("Attempting to queue %s to down", torrent_id) log.debug("Attempting to queue %s to down", torrent_ids)
for torrent_id in torrent_ids:
try: try:
# If the queue method returns True, then we should emit a signal # If the queue method returns True, then we should emit a signal
if self.torrents.queue.down(torrent_id): if self.torrents.queue.down(torrent_id):
self._torrent_queue_changed(torrent_id) self._torrent_queue_changed()
except KeyError: except KeyError:
log.warning("torrent_id: %s does not exist in the queue", log.warning("torrent_id: %s does not exist in the queue", torrent_id)
torrent_id)
def export_queue_bottom(self, torrent_id): def export_queue_bottom(self, torrent_ids):
log.debug("Attempting to queue %s to bottom", torrent_id) log.debug("Attempting to queue %s to bottom", torrent_ids)
for torrent_id in torrent_ids:
try: try:
# If the queue method returns True, then we should emit a signal # If the queue method returns True, then we should emit a signal
if self.torrents.queue.bottom(torrent_id): if self.torrents.queue.bottom(torrent_id):
self._torrent_queue_changed(torrent_id) self._torrent_queue_changed()
except KeyError: except KeyError:
log.warning("torrent_id: %s does not exist in the queue", log.warning("torrent_id: %s does not exist in the queue", torrent_id)
torrent_id)
# Signals # Signals
def torrent_added(self, torrent_id): def torrent_added(self, torrent_id):
"""Emitted when a new torrent is added to the core""" """Emitted when a new torrent is added to the core"""
@ -597,6 +598,7 @@ class Core(
def _torrent_queue_changed(self): def _torrent_queue_changed(self):
"""Emitted when a torrent queue position is changed""" """Emitted when a torrent queue position is changed"""
log.debug("torrent_queue_changed signal emitted") log.debug("torrent_queue_changed signal emitted")
self.signals.emit("torrent_queue_changed")
# Config set functions # Config set functions
def _on_config_value_change(self, key, value): def _on_config_value_change(self, key, value):

View file

@ -37,6 +37,7 @@ import os
import deluge.libtorrent as lt import deluge.libtorrent as lt
import deluge.common import deluge.common
import deluge.component as component
from deluge.configmanager import ConfigManager from deluge.configmanager import ConfigManager
from deluge.log import LOG as log from deluge.log import LOG as log
@ -50,6 +51,9 @@ class Torrent:
# Get the core config # Get the core config
self.config = ConfigManager("core.conf") self.config = ConfigManager("core.conf")
# Get a reference to the TorrentQueue
self.torrentqueue = component.get("TorrentQueue")
# Set the filename # Set the filename
self.filename = filename self.filename = filename
# Set the libtorrent handle # Set the libtorrent handle
@ -209,6 +213,12 @@ class Torrent:
}) })
return ret return ret
def get_queue_position(self):
# We augment the queue position + 1 so that the user sees a 1 indexed
# list.
return self.torrentqueue[self.torrent_id] + 1
def get_status(self, keys): def get_status(self, keys):
"""Returns the status of the torrent based on the keys provided""" """Returns the status of the torrent based on the keys provided"""
# Create the full dictionary # Create the full dictionary
@ -252,8 +262,7 @@ class Torrent:
"max_upload_speed": self.max_upload_speed, "max_upload_speed": self.max_upload_speed,
"max_download_speed": self.max_download_speed, "max_download_speed": self.max_download_speed,
"prioritize_first_last": self.prioritize_first_last, "prioritize_first_last": self.prioritize_first_last,
"private": self.private, "private": self.private
"queue": 0
} }
fns = { fns = {
@ -264,7 +273,8 @@ class Torrent:
"piece_length": self.torrent_info.piece_length, "piece_length": self.torrent_info.piece_length,
"eta": self.get_eta, "eta": self.get_eta,
"ratio": self.get_ratio, "ratio": self.get_ratio,
"file_progress": self.handle.file_progress "file_progress": self.handle.file_progress,
"queue": self.get_queue_position
} }
self.status = None self.status = None

View file

@ -43,6 +43,7 @@ import deluge.libtorrent as lt
import deluge.common import deluge.common
import deluge.component as component import deluge.component as component
from deluge.core.torrentqueue import TorrentQueue
from deluge.configmanager import ConfigManager from deluge.configmanager import ConfigManager
from deluge.core.torrent import Torrent from deluge.core.torrent import Torrent
from deluge.log import LOG as log from deluge.log import LOG as log
@ -62,12 +63,14 @@ class TorrentState:
max_download_speed, max_download_speed,
prioritize_first_last, prioritize_first_last,
private, private,
file_priorities file_priorities,
queue
): ):
self.torrent_id = torrent_id self.torrent_id = torrent_id
self.filename = filename self.filename = filename
self.total_uploaded = total_uploaded self.total_uploaded = total_uploaded
self.trackers = trackers self.trackers = trackers
self.queue = queue
# Options # Options
self.compact = compact self.compact = compact
@ -99,6 +102,8 @@ class TorrentManager(component.Component):
self.alerts = alerts self.alerts = alerts
# Get the core config # Get the core config
self.config = ConfigManager("core.conf") self.config = ConfigManager("core.conf")
# Create the TorrentQueue object
self.queue = TorrentQueue()
# Create the torrents dict { torrent_id: Torrent } # Create the torrents dict { torrent_id: Torrent }
self.torrents = {} self.torrents = {}
@ -157,7 +162,7 @@ class TorrentManager(component.Component):
return self.torrents.keys() return self.torrents.keys()
def add(self, filename, filedump=None, options=None, total_uploaded=0, def add(self, filename, filedump=None, options=None, total_uploaded=0,
trackers=None, save_state=True): trackers=None, queue=-1, save_state=True):
"""Add a torrent to the manager and returns it's torrent_id""" """Add a torrent to the manager and returns it's torrent_id"""
log.info("Adding torrent: %s", filename) log.info("Adding torrent: %s", filename)
log.debug("options: %s", options) log.debug("options: %s", options)
@ -246,6 +251,9 @@ class TorrentManager(component.Component):
# Add the torrent object to the dictionary # Add the torrent object to the dictionary
self.torrents[torrent.torrent_id] = torrent self.torrents[torrent.torrent_id] = torrent
# Add the torrent to the queue
self.queue.insert(queue, torrent.torrent_id)
# Set per-torrent options # Set per-torrent options
torrent.set_max_connections(options["max_connections_per_torrent"]) torrent.set_max_connections(options["max_connections_per_torrent"])
torrent.set_max_upload_slots(options["max_upload_slots_per_torrent"]) torrent.set_max_upload_slots(options["max_upload_slots_per_torrent"])
@ -420,6 +428,10 @@ class TorrentManager(component.Component):
# Try to add the torrents in the state to the session # Try to add the torrents in the state to the session
add_paused = {} add_paused = {}
# First lets clear the queue and make it the correct length.. This will
# help with inserting values at the right position.
self.queue.set_size(len(state.torrents))
for torrent_state in state.torrents: for torrent_state in state.torrents:
try: try:
options = { options = {
@ -441,9 +453,12 @@ class TorrentManager(component.Component):
options=options, options=options,
total_uploaded=torrent_state.total_uploaded, total_uploaded=torrent_state.total_uploaded,
trackers=torrent_state.trackers, trackers=torrent_state.trackers,
queue=torrent_state.queue,
save_state=False) save_state=False)
except AttributeError, e: except AttributeError, e:
log.error("Torrent state file is either corrupt or incompatible!") log.error("Torrent state file is either corrupt or incompatible!")
add_paused = {}
break break
# Run the post_session_load plugin hooks # Run the post_session_load plugin hooks
@ -473,7 +488,8 @@ class TorrentManager(component.Component):
torrent.max_download_speed, torrent.max_download_speed,
torrent.prioritize_first_last, torrent.prioritize_first_last,
torrent.private, torrent.private,
torrent.file_priorities torrent.file_priorities,
torrent.get_status(["queue"])["queue"] - 1 # We subtract 1 due to augmentation
) )
state.torrents.append(torrent_state) state.torrents.append(torrent_state)

168
deluge/core/torrentqueue.py Normal file
View file

@ -0,0 +1,168 @@
#
# torrentqueue.py
#
# Copyright (C) 2007,2008 Andrew Resch ('andar') <andrewresch@gmail.com>
#
# 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 deluge.component as component
import deluge.common
from deluge.log import LOG as log
class TorrentQueue(component.Component):
def __init__(self):
component.Component.__init__(self, "TorrentQueue", depend=["TorrentManager"])
# This is a list of torrent_ids in the queueing order
self.queue = []
def set_size(self, size):
"""Clear and set the self.queue list to the length of size"""
log.debug("Setting queue size to %s..", size)
self.queue = [None] * size
def __getitem__(self, torrent_id):
"""Return the queue position of the torrent_id"""
try:
return self.queue.index(torrent_id)
except ValueError:
return None
def append(self, torrent_id):
"""Append torrent_id to the bottom of the queue"""
log.debug("Append torrent %s to queue..", torrent_id)
self.queue.append(torrent_id)
return self.queue.index(torrent_id)
def prepend(self, torrent_id):
"""Prepend torrent_id to the top of the queue"""
log.debug("Prepend torrent %s to queue..", torrent_id)
self.queue.insert(0, torrent_id)
return self.queue.index(torrent_id)
def insert(self, position, torrent_id):
"""Inserts torrent_id at position in queue."""
log.debug("Inserting torrent %s at position %s..", torrent_id, position)
if position < 0:
for q in self.queue:
if q == None:
self.queue[self.queue.index(q)] = torrent_id
break
else:
if self.queue[position] == None:
self.queue[position] = torrent_id
else:
self.queue.insert(position, torrent_id)
try:
return self.queue.index(torrent_id)
except ValueError:
self.queue.append(torrent_id)
return self.queue.index(torrent_id)
def remove(self, torrent_id):
"""Removes torrent_id from the list"""
log.debug("Remove torrent %s from queue..", torrent_id)
self.queue.remove(torrent_id)
def up(self, torrent_id):
"""Move torrent_id up one in the queue"""
if torrent_id not in self.queue:
# Raise KeyError if the torrent_id is not in the queue
raise KeyError
log.debug("Move torrent %s up..", torrent_id)
# Get the index of the torrent_id
index = self.queue.index(torrent_id)
# Can't queue up if torrent is already at top
if index is 0:
return False
# Pop and insert the torrent_id at index - 1
self.queue.insert(index - 1, self.queue.pop(index))
return True
def top(self, torrent_id):
"""Move torrent_id to top of the queue"""
if torrent_id not in self.queue:
# Raise KeyError if the torrent_id is not in the queue
raise KeyError
log.debug("Move torrent %s to top..", torrent_id)
# Get the index of the torrent_id
index = self.queue.index(torrent_id)
# Can't queue up if torrent is already at top
if index is 0:
return False
self.queue.insert(0, self.queue.pop(index))
return True
def down(self, torrent_id):
"""Move torrent_id down one in the queue"""
if torrent_id not in self.queue:
# Raise KeyError if torrent_id is not in the queue
raise KeyError
log.debug("Move torrent %s down..", torrent_id)
# Get the index of the torrent_id
index = self.queue.index(torrent_id)
# Can't queue down of torrent_id is at bottom
if index is len(self.queue) - 1:
return False
# Pop and insert the torrent_id at index + 1
self.queue.insert(index + 1, self.queue.pop(index))
return True
def bottom(self, torrent_id):
"""Move torrent_id to bottom of the queue"""
if torrent_id not in self.queue:
# Raise KeyError if torrent_id is not in the queue
raise KeyError
log.debug("Move torrent %s to bottom..", torrent_id)
# Get the index of the torrent_id
index = self.queue.index(torrent_id)
# Can't queue down of torrent_id is at bottom
if index is len(self.queue) - 1:
return False
# Pop and append the torrent_id
self.append(self.queue.pop(index))
return True

View file

@ -319,43 +319,43 @@
<property name="visible">True</property> <property name="visible">True</property>
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property> <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
<child> <child>
<widget class="GtkImageMenuItem" id="menuitem_queuetop"> <widget class="GtkImageMenuItem" id="menuitem_queue_top">
<property name="visible">True</property> <property name="visible">True</property>
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property> <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
<property name="label" translatable="yes">gtk-goto-top</property> <property name="label" translatable="yes">gtk-goto-top</property>
<property name="use_underline">True</property> <property name="use_underline">True</property>
<property name="use_stock">True</property> <property name="use_stock">True</property>
<signal name="activate" handler="on_menuitem_queuetop_activate"/> <signal name="activate" handler="on_menuitem_queue_top_activate"/>
</widget> </widget>
</child> </child>
<child> <child>
<widget class="GtkImageMenuItem" id="menuitem_queueup"> <widget class="GtkImageMenuItem" id="menuitem_queue_up">
<property name="visible">True</property> <property name="visible">True</property>
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property> <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
<property name="label" translatable="yes">gtk-go-up</property> <property name="label" translatable="yes">gtk-go-up</property>
<property name="use_underline">True</property> <property name="use_underline">True</property>
<property name="use_stock">True</property> <property name="use_stock">True</property>
<signal name="activate" handler="on_menuitem_queueup_activate"/> <signal name="activate" handler="on_menuitem_queue_up_activate"/>
</widget> </widget>
</child> </child>
<child> <child>
<widget class="GtkImageMenuItem" id="menuitem_queuedown"> <widget class="GtkImageMenuItem" id="menuitem_queue_down">
<property name="visible">True</property> <property name="visible">True</property>
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property> <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
<property name="label" translatable="yes">gtk-go-down</property> <property name="label" translatable="yes">gtk-go-down</property>
<property name="use_underline">True</property> <property name="use_underline">True</property>
<property name="use_stock">True</property> <property name="use_stock">True</property>
<signal name="activate" handler="on_menuitem_queuedown_activate"/> <signal name="activate" handler="on_menuitem_queue_down_activate"/>
</widget> </widget>
</child> </child>
<child> <child>
<widget class="GtkImageMenuItem" id="menuitem_queuebottom"> <widget class="GtkImageMenuItem" id="menuitem_queue_bottom">
<property name="visible">True</property> <property name="visible">True</property>
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property> <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
<property name="label" translatable="yes">gtk-goto-bottom</property> <property name="label" translatable="yes">gtk-goto-bottom</property>
<property name="use_underline">True</property> <property name="use_underline">True</property>
<property name="use_stock">True</property> <property name="use_stock">True</property>
<signal name="activate" handler="on_menuitem_queuebottom_activate"/> <signal name="activate" handler="on_menuitem_queue_bottom_activate"/>
</widget> </widget>
</child> </child>
</widget> </widget>

View file

@ -144,7 +144,12 @@ class MenuBar(component.Component):
"on_menuitem_recheck_activate": self.on_menuitem_recheck_activate, "on_menuitem_recheck_activate": self.on_menuitem_recheck_activate,
"on_menuitem_open_folder": self.on_menuitem_open_folder_activate, "on_menuitem_open_folder": self.on_menuitem_open_folder_activate,
"on_menuitem_move_activate": self.on_menuitem_move_activate "on_menuitem_move_activate": self.on_menuitem_move_activate,
"on_menuitem_queue_top_activate": self.on_menuitem_queue_top_activate,
"on_menuitem_queue_up_activate": self.on_menuitem_queue_up_activate,
"on_menuitem_queue_down_activate": self.on_menuitem_queue_down_activate,
"on_menuitem_queue_bottom_activate": self.on_menuitem_queue_bottom_activate,
}) })
self.change_sensitivity = [ self.change_sensitivity = [
@ -298,6 +303,22 @@ class MenuBar(component.Component):
component.get("TorrentView").get_selected_torrents(), result) component.get("TorrentView").get_selected_torrents(), result)
chooser.destroy() chooser.destroy()
def on_menuitem_queue_top_activate(self, value):
log.debug("on_menuitem_queue_top_activate")
client.queue_top(None, component.get("TorrentView").get_selected_torrents())
def on_menuitem_queue_up_activate(self, value):
log.debug("on_menuitem_queue_up_activate")
client.queue_up(None, component.get("TorrentView").get_selected_torrents())
def on_menuitem_queue_down_activate(self, value):
log.debug("on_menuitem_queue_down_activate")
client.queue_down(None, component.get("TorrentView").get_selected_torrents())
def on_menuitem_queue_bottom_activate(self, value):
log.debug("on_menuitem_queue_bottom_activate")
client.queue_bottom(None, component.get("TorrentView").get_selected_torrents())
## View Menu ## ## View Menu ##
def on_menuitem_toolbar_toggled(self, value): def on_menuitem_toolbar_toggled(self, value):
log.debug("on_menuitem_toolbar_toggled") log.debug("on_menuitem_toolbar_toggled")

View file

@ -63,7 +63,7 @@ class Preferences(component.Component):
# Add the default categories # Add the default categories
i = 0 i = 0
for category in ["Downloads", "Network", "Bandwidth", "Interface", for category in ["Downloads", "Network", "Bandwidth", "Interface",
"Other", "Daemon", "Plugins"]: "Other", "Daemon", "Plugins", "Queue"]:
self.liststore.append([i, category]) self.liststore.append([i, category])
i += 1 i += 1

View file

@ -59,6 +59,8 @@ class Signals(component.Component):
self.torrent_all_resumed) self.torrent_all_resumed)
self.receiver.connect_to_signal("config_value_changed", self.receiver.connect_to_signal("config_value_changed",
self.config_value_changed) self.config_value_changed)
self.receiver.connect_to_signal("torrent_queue_changed",
self.torrent_queue_changed)
def stop(self): def stop(self):
try: try:
@ -108,3 +110,8 @@ class Signals(component.Component):
log.debug("config_value_changed signal received..") log.debug("config_value_changed signal received..")
component.get("StatusBar").config_value_changed(key, value) component.get("StatusBar").config_value_changed(key, value)
component.get("SystemTray").config_value_changed(key, value) component.get("SystemTray").config_value_changed(key, value)
def torrent_queue_changed(self):
log.debug("torrent_queue_changed signal received..")
component.get("TorrentView").update()

View file

@ -56,7 +56,9 @@ class ToolBar(component.Component):
"on_toolbutton_preferences_clicked": \ "on_toolbutton_preferences_clicked": \
self.on_toolbutton_preferences_clicked, self.on_toolbutton_preferences_clicked,
"on_toolbutton_connectionmanager_clicked": \ "on_toolbutton_connectionmanager_clicked": \
self.on_toolbutton_connectionmanager_clicked self.on_toolbutton_connectionmanager_clicked,
"on_toolbutton_queue_up_clicked": self.on_toolbutton_queue_up_clicked,
"on_toolbutton_queue_down_clicked": self.on_toolbutton_queue_down_clicked
}) })
self.change_sensitivity = [ self.change_sensitivity = [
"toolbutton_add", "toolbutton_add",
@ -154,6 +156,14 @@ class ToolBar(component.Component):
# Use the menubar's callbacks # Use the menubar's callbacks
component.get("MenuBar").on_menuitem_connectionmanager_activate(data) component.get("MenuBar").on_menuitem_connectionmanager_activate(data)
def on_toolbutton_queue_up_clicked(self, data):
log.debug("on_toolbutton_queue_up_clicked")
component.get("MenuBar").on_menuitem_queue_up_activate(data)
def on_toolbutton_queue_down_clicked(self, data):
log.debug("on_toolbutton_queue_down_clicked")
component.get("MenuBar").on_menuitem_queue_down_activate(data)
def update_buttons(self, action=None, torrent_id=None): def update_buttons(self, action=None, torrent_id=None):
if action == None: if action == None:
# If all the selected torrents are paused, then disable the 'Pause' # If all the selected torrents are paused, then disable the 'Pause'