[#637] Add a Moving storage state along with progress

Uses attr Torrent.moving_storage for now but can be replaced with
future lt1.0 status field.
Refactored the code to use the common.TORRENT_STATE list.
Added a translating dict to ui.common to aid translation of state text.
This commit is contained in:
Calum Lind 2014-07-16 17:35:55 +01:00
parent bd119bccf4
commit 62cca045be
11 changed files with 94 additions and 56 deletions

View File

@ -99,7 +99,8 @@ TORRENT_STATE = [
"Seeding",
"Paused",
"Error",
"Queued"
"Queued",
"Moving"
]
FILE_PRIORITY = {

View File

@ -36,11 +36,12 @@
import logging
import copy
import deluge.component as component
STATE_SORT = ["All", "Downloading", "Seeding", "Active", "Paused", "Queued"]
from deluge.common import TORRENT_STATE
log = logging.getLogger(__name__)
STATE_SORT = ["All", "Active"] + TORRENT_STATE
# Special purpose filters:
def filter_keywords(torrent_ids, values):
@ -249,15 +250,12 @@ class FilterManager(component.Component):
return sorted_items
def _init_state_tree(self):
return {"All": len(self.torrents.get_torrent_list()),
"Downloading": 0,
"Seeding": 0,
"Paused": 0,
"Checking": 0,
"Queued": 0,
"Error": 0,
"Active": len(self.filter_state_active(self.torrents.get_torrent_list()))
}
init_state = {}
init_state["All"] = len(self.torrents.get_torrent_list())
for state in TORRENT_STATE:
init_state[state] = 0
init_state["Active"] = len(self.filter_state_active(self.torrents.get_torrent_list()))
return init_state
def register_filter(self, id, filter_func, filter_value=None):
self.registered_filters[id] = filter_func

View File

@ -197,6 +197,8 @@ class Torrent(object):
self.statusmsg = "OK"
self.state = None
self.moving_storage = False
self.moving_storage_dest_path = None
self.tracker_status = ""
self.tracker_host = None
self.forcing_recheck = False
@ -571,6 +573,10 @@ class Torrent(object):
else:
self.set_status_message("OK")
if self.moving_storage:
self.state = "Moving"
return
if ltstate in (LTSTATE["Queued"], LTSTATE["Checking"]):
self.state = "Checking"
if status.paused:
@ -788,6 +794,21 @@ class Torrent(object):
"""Returns a magnet uri for this torrent"""
return lt.make_magnet_uri(self.handle)
def get_progress(self):
def get_size(files, path):
"""Returns total size of 'files' currently located in 'path'"""
files = [os.path.join(path, f) for f in files]
return sum(os.stat(f).st_size for f in files if os.path.exists(f))
if self.moving_storage:
torrent_status = self.get_status(["files", "total_done"])
torrent_files = [f['path'] for f in torrent_status["files"]]
dest_path_size = get_size(torrent_files, self.moving_storage_dest_path)
progress = dest_path_size / torrent_status["total_done"] * 100
else:
progress = self.status.progress * 100
return progress
def get_status(self, keys, diff=False, update=False, all_keys=False):
"""Returns the status of the torrent based on the keys provided
@ -889,7 +910,7 @@ class Torrent(object):
"paused": lambda: self.status.paused,
"prioritize_first_last": lambda: self.options["prioritize_first_last_pieces"],
"sequential_download": lambda: self.options["sequential_download"],
"progress": lambda: self.status.progress * 100,
"progress": self.get_progress,
"shared": lambda: self.options["shared"],
"remove_at_ratio": lambda: self.options["remove_at_ratio"],
"save_path": lambda: self.options["download_location"], # Deprecated, use download_location
@ -1013,6 +1034,7 @@ class Torrent(object):
Returns:
bool: True if successful, otherwise False
"""
dest = decode_string(dest)
if not os.path.exists(dest):
@ -1034,6 +1056,9 @@ class Torrent(object):
except RuntimeError, ex:
log.error("Error calling libtorrent move_storage: %s", ex)
return False
self.moving_storage = True
self.moving_storage_dest_path = dest
self.update_state()
return True
def save_resume_data(self, flush_disk_cache=False):

View File

@ -245,6 +245,7 @@ class TorrentManager(component.Component):
def update(self):
for torrent_id, torrent in self.torrents.items():
# XXX: Should the state check be those that _can_ be stopped at ratio
if torrent.options["stop_at_ratio"] and torrent.state not in (
"Checking", "Allocating", "Paused", "Queued"):
# If the global setting is set, but the per-torrent isn't...
@ -1066,6 +1067,8 @@ class TorrentManager(component.Component):
return
torrent.set_download_location(os.path.normpath(alert.handle.save_path()))
torrent.set_move_completed(False)
torrent.moving_storage = False
torrent.update_state()
if torrent in self.waiting_on_finish_moving:
self.waiting_on_finish_moving.remove(torrent_id)
@ -1080,8 +1083,10 @@ class TorrentManager(component.Component):
except (RuntimeError, KeyError):
return
# Set an Error message and pause the torrent
torrent.moving_storage = False
torrent.set_status_message("Error: moving storage location failed")
torrent.pause()
torrent.update_state()
if torrent in self.waiting_on_finish_moving:
self.waiting_on_finish_moving.remove(torrent_id)

View File

@ -51,6 +51,24 @@ import deluge.configmanager
log = logging.getLogger(__name__)
# Dummy tranlation dict so Torrent states text is available for Translators
# All entries in deluge.common.TORRENT_STATE should be here. It does not need importing
# as the string matches the translation text so using the _() function is enough.
def _(message): return message
STATE_TRANSLATION = {
"All": _("All"),
"Active": _("Active"),
"Allocating": _("Allocating"),
"Checking": _("Checking"),
"Downloading": _("Downloading"),
"Seeding": _("Seeding"),
"Paused": _("Paused"),
"Checking": _("Checking"),
"Queued": _("Queued"),
"Error": _("Error"),
}
del _
class TorrentInfo(object):
"""
Collects information about a torrent file.

View File

@ -79,7 +79,8 @@ state_color = {
"Paused": "{!white,black!}",
"Checking": "{!green,black!}",
"Queued": "{!yellow,black!}",
"Error": "{!red,black,bold!}"
"Error": "{!red,black,bold!}",
"Moving": "{!green,black,bold}"
}
type_color = {

View File

@ -36,7 +36,7 @@ from optparse import make_option
from twisted.internet import defer
from deluge.ui.console.main import BaseCommand
from deluge.ui.client import client
import deluge.common
from deluge.common import fspeed, TORRENT_STATE
import deluge.component as component
@ -98,23 +98,22 @@ class Command(BaseCommand):
self.console.write("{!info!}Total upload: %f" % self.status["payload_upload_rate"])
self.console.write("{!info!}Total download: %f" % self.status["payload_download_rate"])
else:
self.console.write("{!info!}Total upload: %s" % deluge.common.fspeed(self.status["payload_upload_rate"]))
self.console.write("{!info!}Total download: %s" %
deluge.common.fspeed(self.status["payload_download_rate"]))
self.console.write("{!info!}Total upload: %s" % fspeed(self.status["payload_upload_rate"]))
self.console.write("{!info!}Total download: %s" % fspeed(self.status["payload_download_rate"]))
self.console.write("{!info!}DHT Nodes: %i" % self.status["dht_nodes"])
self.console.write("{!info!}Total connections: %i" % self.connections)
if self.torrents == -1:
self.console.write("{!error!}Error getting torrent info")
elif self.torrents != -2:
self.console.write("{!info!}Total torrents: %i" % len(self.torrents))
states = ["Downloading", "Seeding", "Paused", "Checking", "Error", "Queued"]
state_counts = {}
for state in states:
for state in TORRENT_STATE:
state_counts[state] = 0
for t in self.torrents:
s = self.torrents[t]
state_counts[s["state"]] += 1
for state in states:
for state in TORRENT_STATE:
self.console.write("{!info!} %s: %i" % (state, state_counts[state]))
self.console.set_batch_write(False)

View File

@ -144,6 +144,8 @@ class FILTER:
CHECKING=5
ERROR=6
QUEUED=7
ALLOCATING=8
MOVING=9
DEFAULT_PREFS = {
"show_queue": True,
@ -703,6 +705,13 @@ class AllTorrents(BaseMode, component.Component):
elif data==FILTER.QUEUED:
self.__status_dict = {"state":"Queued"}
self._curr_filter = "Queued"
elif data==FILTER.ALLOCATING:
self.__status_dict = {"state":"Allocating"}
self._curr_filter = "Allocating"
elif data==FILTER.MOVING:
self.__status_dict = {"state":"Moving"}
self._curr_filter = "Moving"
self._go_top = True
return True
@ -716,6 +725,8 @@ class AllTorrents(BaseMode, component.Component):
self.popup.add_line("_Error",data=FILTER.ERROR,foreground="red")
self.popup.add_line("_Checking",data=FILTER.CHECKING,foreground="blue")
self.popup.add_line("Q_ueued",data=FILTER.QUEUED,foreground="yellow")
self.popup.add_line("A_llocating",data=FILTER.ALLOCATING,foreground="yellow")
self.popup.add_line("_Moving",data=FILTER.MOVING,foreground="green")
def _report_add_status(self, succ_cnt, fail_cnt, fail_msgs):
if fail_cnt == 0:
@ -951,6 +962,8 @@ class AllTorrents(BaseMode, component.Component):
fg = "yellow"
elif row[1] == "Checking":
fg = "blue"
elif row[1] == "Moving":
fg = "green"
if self.entering_search and len(self.search_string) > 1:
lcase_name = self.torrent_names[tidx-1].lower()

View File

@ -41,7 +41,7 @@ import warnings
from gobject import GError
import deluge.component as component
import deluge.common
from deluge.common import resource_filename, get_pixmap, TORRENT_STATE
from deluge.ui.client import client
from deluge.configmanager import ConfigManager
@ -55,7 +55,9 @@ STATE_PIX = {
"Checking": "checking",
"Queued": "queued",
"Error": "alert",
"Active": "active"
"Active": "active",
"Allocating": "checking",
"Moving": "checking"
}
TRACKER_PIX = {
@ -85,9 +87,7 @@ class FilterTreeView(component.Component):
#menu
builder = gtk.Builder()
builder.add_from_file(deluge.common.resource_filename(
"deluge.ui.gtkui", os.path.join("glade", "filtertree_menu.ui")
))
builder.add_from_file(resource_filename("deluge.ui.gtkui", os.path.join("glade", "filtertree_menu.ui")))
self.menu = builder.get_object("filtertree_menu")
builder.connect_signals({
"select_all": self.on_select_all,
@ -141,12 +141,8 @@ class FilterTreeView(component.Component):
#initial order of state filter:
self.cat_nodes["state"] = self.treestore.append(None, ["cat", "state", _("States"), 0, None, False])
self.update_row("state", "All" , 0, _("All"))
self.update_row("state", "Downloading" , 0, _("Downloading"))
self.update_row("state", "Seeding" , 0, _("Seeding"))
self.update_row("state", "Active" , 0, _("Active"))
self.update_row("state", "Paused" , 0, _("Paused"))
self.update_row("state", "Queued" , 0, _("Queued"))
for state in ["All", "Active"] + TORRENT_STATE:
self.update_row("state", state, 0, _(state))
self.cat_nodes["tracker_host"] = self.treestore.append(None, ["cat", "tracker_host", _("Trackers"), 0, None, False])
self.update_row("tracker_host", "All" , 0, _("All"))
@ -274,7 +270,7 @@ class FilterTreeView(component.Component):
if pix:
try:
return gtk.gdk.pixbuf_new_from_file(deluge.common.get_pixmap("%s16.png" % pix))
return gtk.gdk.pixbuf_new_from_file(get_pixmap("%s16.png" % pix))
except GError, e:
log.warning(e)
return self.get_transparent_pix(16, 16)

View File

@ -42,7 +42,6 @@ import logging
import deluge.component as component
from deluge.ui.client import client
from deluge.common import TORRENT_STATE
from deluge.configmanager import ConfigManager
log = logging.getLogger(__name__)

View File

@ -48,7 +48,7 @@ icon_alert = gtk.gdk.pixbuf_new_from_file(common.get_pixmap("alert16.png"))
icon_queued = gtk.gdk.pixbuf_new_from_file(common.get_pixmap("queued16.png"))
icon_checking = gtk.gdk.pixbuf_new_from_file(common.get_pixmap("checking16.png"))
# Holds the info for which status icon to display based on state
# Holds the info for which status icon to display based on TORRENT_STATE
ICON_STATE = {
"Allocating": icon_checking,
"Checking": icon_checking,
@ -57,27 +57,9 @@ ICON_STATE = {
"Paused": icon_inactive,
"Error": icon_alert,
"Queued": icon_queued,
"Checking Resume Data": icon_checking
"Moving": icon_checking
}
def _(message): return message
TRANSLATE = {
"Downloading": _("Downloading"),
"Seeding": _("Seeding"),
"Paused": _("Paused"),
"Checking": _("Checking"),
"Queued": _("Queued"),
"Error": _("Error"),
}
del _
def _t(text):
if text in TRANSLATE:
text = TRANSLATE[text]
return _(text)
# Cache the key used to calculate the current value set for the specific cell
# renderer. This is much cheaper than fetch the current value and test if
# it's equal.
@ -169,9 +151,10 @@ def cell_data_progress(column, cell, model, row, data):
func_last_value["cell_data_progress"][0] = value
cell.set_property("value", value)
textstr = _t(state_str)
# Marked for translate states text are in filtertreeview
textstr = _(state_str)
if state_str != "Seeding" and value < 100:
textstr = textstr + " %.2f%%" % value
textstr = "%s %.2f%%" % (textstr, value)
if func_last_value["cell_data_progress"][1] != textstr:
func_last_value["cell_data_progress"][1] = textstr