add torrentdetails state, allow state switching, move some formating to format_utils

This commit is contained in:
Nick 2011-02-01 17:23:15 +01:00
parent 007dd67ea1
commit 5d46d2aee5
6 changed files with 501 additions and 69 deletions

View File

@ -48,6 +48,7 @@ import deluge.component as component
from deluge.ui.client import client from deluge.ui.client import client
import deluge.common import deluge.common
from deluge.ui.coreconfig import CoreConfig from deluge.ui.coreconfig import CoreConfig
from deluge.ui.sessionproxy import SessionProxy
from deluge.ui.console.statusbars import StatusBars from deluge.ui.console.statusbars import StatusBars
from deluge.ui.console.eventlog import EventLog from deluge.ui.console.eventlog import EventLog
import screen import screen
@ -156,7 +157,10 @@ class ConsoleUI(component.Component):
log.debug("Using encoding: %s", self.encoding) log.debug("Using encoding: %s", self.encoding)
# Load all the commands # Load all the commands
self._commands = load_commands(os.path.join(UI_PATH, 'commands')) #self._commands = load_commands(os.path.join(UI_PATH, 'commands'))
# start up the session proxy
self.sessionproxy = SessionProxy()
client.set_disconnect_callback(self.on_client_disconnect) client.set_disconnect_callback(self.on_client_disconnect)
@ -213,9 +217,9 @@ class ConsoleUI(component.Component):
# We want to do an interactive session, so start up the curses screen and # We want to do an interactive session, so start up the curses screen and
# pass it the function that handles commands # pass it the function that handles commands
colors.init_colors() colors.init_colors()
self.statusbars = StatusBars()
from modes.alltorrents import AllTorrents from modes.alltorrents import AllTorrents
self.screen = AllTorrents(stdscr, self.coreconfig, self.encoding) self.screen = AllTorrents(stdscr, self.coreconfig, self.encoding)
self.statusbars = StatusBars()
self.eventlog = EventLog() self.eventlog = EventLog()
self.screen.topbar = "{!status!}Deluge " + deluge.common.get_version() + " Console" self.screen.topbar = "{!status!}Deluge " + deluge.common.get_version() + " Console"
@ -264,6 +268,12 @@ class ConsoleUI(component.Component):
if not batch and self.interactive: if not batch and self.interactive:
self.screen.refresh() self.screen.refresh()
def set_mode(self, mode):
reactor.removeReader(self.screen)
self.screen = mode
self.statusbars.screen = self.screen
reactor.addReader(self.screen)
def write(self, line): def write(self, line):
""" """
Writes a line out depending on if we're in interactive mode or not. Writes a line out depending on if we're in interactive mode or not.

View File

@ -46,7 +46,9 @@ from deluge.ui.sessionproxy import SessionProxy
from popup import Popup,SelectablePopup,MessagePopup from popup import Popup,SelectablePopup,MessagePopup
from add_util import add_torrent from add_util import add_torrent
from input_popup import InputPopup from input_popup import InputPopup
from torrentdetail import TorrentDetail
import format_utils
try: try:
import curses import curses
@ -146,7 +148,7 @@ class StateUpdater(component.Component):
self._status_cb(state,refresh) self._status_cb(state,refresh)
class AllTorrents(BaseMode, component.Component): class AllTorrents(BaseMode):
def __init__(self, stdscr, coreconfig, encoding=None): def __init__(self, stdscr, coreconfig, encoding=None):
self.formatted_rows = None self.formatted_rows = None
self.cursel = 1 self.cursel = 1
@ -166,7 +168,6 @@ class AllTorrents(BaseMode, component.Component):
BaseMode.__init__(self, stdscr, encoding) BaseMode.__init__(self, stdscr, encoding)
curses.curs_set(0) curses.curs_set(0)
self.stdscr.notimeout(0) self.stdscr.notimeout(0)
self.sessionproxy = SessionProxy()
self._status_fields = ["queue","name","total_wanted","state","progress","num_seeds","total_seeds", self._status_fields = ["queue","name","total_wanted","state","progress","num_seeds","total_seeds",
"num_peers","total_peers","download_payload_rate", "upload_payload_rate"] "num_peers","total_peers","download_payload_rate", "upload_payload_rate"]
@ -180,21 +181,21 @@ class AllTorrents(BaseMode, component.Component):
self._info_fields = [ self._info_fields = [
("Name",None,("name",)), ("Name",None,("name",)),
("State", None, ("state",)), ("State", None, ("state",)),
("Down Speed", self._format_speed, ("download_payload_rate",)), ("Down Speed", format_utils.format_speed, ("download_payload_rate",)),
("Up Speed", self._format_speed, ("upload_payload_rate",)), ("Up Speed", format_utils.format_speed, ("upload_payload_rate",)),
("Progress", self._format_progress, ("progress",)), ("Progress", format_utils.format_progress, ("progress",)),
("ETA", deluge.common.ftime, ("eta",)), ("ETA", deluge.common.ftime, ("eta",)),
("Path", None, ("save_path",)), ("Path", None, ("save_path",)),
("Downloaded",deluge.common.fsize,("all_time_download",)), ("Downloaded",deluge.common.fsize,("all_time_download",)),
("Uploaded", deluge.common.fsize,("total_uploaded",)), ("Uploaded", deluge.common.fsize,("total_uploaded",)),
("Share Ratio", lambda x:x < 0 and "" or "%.3f"%x, ("ratio",)), ("Share Ratio", lambda x:x < 0 and "" or "%.3f"%x, ("ratio",)),
("Seeders",self._format_seeds_peers,("num_seeds","total_seeds")), ("Seeders",format_utils.format_seeds_peers,("num_seeds","total_seeds")),
("Peers",self._format_seeds_peers,("num_peers","total_peers")), ("Peers",format_utils.format_seeds_peers,("num_peers","total_peers")),
("Active Time",deluge.common.ftime,("active_time",)), ("Active Time",deluge.common.ftime,("active_time",)),
("Seeding Time",deluge.common.ftime,("seeding_time",)), ("Seeding Time",deluge.common.ftime,("seeding_time",)),
("Date Added",deluge.common.fdate,("time_added",)), ("Date Added",deluge.common.fdate,("time_added",)),
("Availability", lambda x:x < 0 and "" or "%.3f"%x, ("distributed_copies",)), ("Availability", lambda x:x < 0 and "" or "%.3f"%x, ("distributed_copies",)),
("Pieces", self._format_pieces, ("num_pieces","piece_length")), ("Pieces", format_utils.format_pieces, ("num_pieces","piece_length")),
] ]
self._status_keys = ["name","state","download_payload_rate","upload_payload_rate", self._status_keys = ["name","state","download_payload_rate","upload_payload_rate",
@ -203,6 +204,11 @@ class AllTorrents(BaseMode, component.Component):
"seeding_time","time_added","distributed_copies", "num_pieces", "seeding_time","time_added","distributed_copies", "num_pieces",
"piece_length","save_path"] "piece_length","save_path"]
def resume(self):
component.start(["AllTorrentsStateUpdater"])
self.refresh()
def _update_columns(self): def _update_columns(self):
self.column_widths = [5,-1,15,13,10,10,10,15,15] self.column_widths = [5,-1,15,13,10,10,10,15,15]
req = sum(filter(lambda x:x >= 0,self.column_widths)) req = sum(filter(lambda x:x >= 0,self.column_widths))
@ -220,18 +226,6 @@ class AllTorrents(BaseMode, component.Component):
self.column_string = "{!header!}%s"%("".join(["%s%s"%(self.column_names[i]," "*(self.column_widths[i]-len(self.column_names[i]))) for i in range(0,len(self.column_names))])) self.column_string = "{!header!}%s"%("".join(["%s%s"%(self.column_names[i]," "*(self.column_widths[i]-len(self.column_names[i]))) for i in range(0,len(self.column_names))]))
def _trim_string(self, string, w):
return "%s... "%(string[0:w-4])
def _format_column(self, col, lim):
size = len(col)
if (size >= lim - 1):
return self._trim_string(col,lim)
else:
return "%s%s"%(col," "*(lim-size))
def _format_row(self, row):
return "".join([self._format_column(row[i],self.column_widths[i]) for i in range(0,len(row))])
def set_state(self, state, refresh): def set_state(self, state, refresh):
self.curstate = state # cache in case we change sort order self.curstate = state # cache in case we change sort order
@ -239,16 +233,16 @@ class AllTorrents(BaseMode, component.Component):
self._sorted_ids = self._sort_torrents(self.curstate) self._sorted_ids = self._sort_torrents(self.curstate)
for torrent_id in self._sorted_ids: for torrent_id in self._sorted_ids:
ts = self.curstate[torrent_id] ts = self.curstate[torrent_id]
newrows.append((self._format_row([self._format_queue(ts["queue"]), newrows.append((format_utils.format_row([self._format_queue(ts["queue"]),
ts["name"], ts["name"],
"%s"%deluge.common.fsize(ts["total_wanted"]), "%s"%deluge.common.fsize(ts["total_wanted"]),
ts["state"], ts["state"],
self._format_progress(ts["progress"]), format_utils.format_progress(ts["progress"]),
self._format_seeds_peers(ts["num_seeds"],ts["total_seeds"]), format_utils.format_seeds_peers(ts["num_seeds"],ts["total_seeds"]),
self._format_seeds_peers(ts["num_peers"],ts["total_peers"]), format_utils.format_seeds_peers(ts["num_peers"],ts["total_peers"]),
self._format_speed(ts["download_payload_rate"]), format_utils.format_speed(ts["download_payload_rate"]),
self._format_speed(ts["upload_payload_rate"]) format_utils.format_speed(ts["upload_payload_rate"])
]),ts["state"])) ],self.column_widths),ts["state"]))
self.numtorrents = len(state) self.numtorrents = len(state)
self.formatted_rows = newrows self.formatted_rows = newrows
if refresh: if refresh:
@ -328,27 +322,12 @@ class AllTorrents(BaseMode, component.Component):
"sorts by queue #" "sorts by queue #"
return sorted(state,cmp=self._queue_sort,key=lambda s:state.get(s)["queue"]) return sorted(state,cmp=self._queue_sort,key=lambda s:state.get(s)["queue"])
def _format_speed(self, speed):
if (speed > 0):
return deluge.common.fspeed(speed)
else:
return "-"
def _format_queue(self, qnum): def _format_queue(self, qnum):
if (qnum >= 0): if (qnum >= 0):
return "%d"%(qnum+1) return "%d"%(qnum+1)
else: else:
return "" return ""
def _format_seeds_peers(self, num, total):
return "%d (%d)"%(num,total)
def _format_pieces(self, num, size):
return "%d (%s)"%(num,deluge.common.fsize(size))
def _format_progress(self, perc):
return "%.2f%%"%perc
def _action_error(self, error): def _action_error(self, error):
rerr = error.value rerr = error.value
self.report_message("An Error Occurred","%s got error %s: %s"%(rerr.method,rerr.exception_type,rerr.exception_msg)) self.report_message("An Error Occurred","%s got error %s: %s"%(rerr.method,rerr.exception_type,rerr.exception_msg))
@ -475,6 +454,9 @@ class AllTorrents(BaseMode, component.Component):
self.messages.append((title,message)) self.messages.append((title,message))
def refresh(self,lines=None): def refresh(self,lines=None):
#log.error("ref")
#import traceback
#traceback.print_stack()
# Something has requested we scroll to the top of the list # Something has requested we scroll to the top of the list
if self._go_top: if self._go_top:
self.cursel = 1 self.cursel = 1
@ -491,12 +473,12 @@ class AllTorrents(BaseMode, component.Component):
# Update the status bars # Update the status bars
if self._curr_filter == None: if self._curr_filter == None:
self.add_string(0,self.topbar) self.add_string(0,self.statusbars.topbar)
else: else:
self.add_string(0,"%s {!filterstatus!}Current filter: %s"%(self.topbar,self._curr_filter)) self.add_string(0,"%s {!filterstatus!}Current filter: %s"%(self.statusbars.topbar,self._curr_filter))
self.add_string(1,self.column_string) self.add_string(1,self.column_string)
hstr = "%sPress [h] for help"%(" "*(self.cols - len(self.bottombar) - 10)) hstr = "%sPress [h] for help"%(" "*(self.cols - len(self.statusbars.bottombar) - 10))
self.add_string(self.rows - 1, "%s%s"%(self.bottombar,hstr)) self.add_string(self.rows - 1, "%s%s"%(self.statusbars.bottombar,hstr))
# add all the torrents # add all the torrents
if self.formatted_rows == []: if self.formatted_rows == []:
@ -621,6 +603,15 @@ class AllTorrents(BaseMode, component.Component):
elif c == curses.KEY_NPAGE: elif c == curses.KEY_NPAGE:
self._scroll_down(int(self.rows/2)) self._scroll_down(int(self.rows/2))
elif c == curses.KEY_RIGHT:
# We enter a new mode for the selected torrent here
if not self.marked:
component.stop(["AllTorrentsStateUpdater"])
self.stdscr.clear()
td = TorrentDetail(self,self._current_torrent_id(),self.stdscr,self.encoding)
component.get("ConsoleUI").set_mode(td)
return
# Enter Key # Enter Key
elif c == curses.KEY_ENTER or c == 10: elif c == curses.KEY_ENTER or c == 10:
self.marked.append(self.cursel) self.marked.append(self.cursel)

View File

@ -43,6 +43,7 @@ try:
except ImportError: except ImportError:
pass pass
import deluge.component as component
import deluge.ui.console.colors as colors import deluge.ui.console.colors as colors
try: try:
import signal import signal
@ -98,8 +99,7 @@ class BaseMode(CursesStdIO):
self.stdscr.nodelay(1) self.stdscr.nodelay(1)
# Strings for the 2 status bars # Strings for the 2 status bars
self.topbar = "" self.statusbars = component.get("StatusBars")
self.bottombar = ""
# Keep track of the screen size # Keep track of the screen size
self.rows, self.cols = self.stdscr.getmaxyx() self.rows, self.cols = self.stdscr.getmaxyx()
@ -182,6 +182,10 @@ class BaseMode(CursesStdIO):
screen.addstr(row, col, s, color) screen.addstr(row, col, s, color)
col += len(s) col += len(s)
def draw_statusbars(self):
self.add_string(0, self.statusbars.topbar)
self.add_string(self.rows - 1, self.statusbars.bottombar)
def refresh(self): def refresh(self):
""" """
Refreshes the screen. Refreshes the screen.
@ -189,10 +193,9 @@ class BaseMode(CursesStdIO):
attribute and the status bars. attribute and the status bars.
""" """
self.stdscr.clear() self.stdscr.clear()
self.draw_statusbars()
# Update the status bars # Update the status bars
self.add_string(0, self.topbar)
self.add_string(self.rows - 1, self.bottombar)
self.add_string(1,"{!info!}Base Mode (or subclass hasn't overridden refresh)") self.add_string(1,"{!info!}Base Mode (or subclass hasn't overridden refresh)")
self.stdscr.redrawwin() self.stdscr.redrawwin()

View File

@ -0,0 +1,70 @@
# format_utils.py
#
# Copyright (C) 2011 Nick Lanham <nick@afternight.org>
#
# 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 3 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.common
def format_speed(speed):
if (speed > 0):
return deluge.common.fspeed(speed)
else:
return "-"
def format_seeds_peers(num, total):
return "%d (%d)"%(num,total)
def format_progress(perc):
return "%.2f%%"%perc
def format_pieces(num, size):
return "%d (%s)"%(num,deluge.common.fsize(size))
def format_priority(prio):
pstring = deluge.common.FILE_PRIORITY[prio]
if prio > 0:
return pstring[:pstring.index("Priority")-1]
else:
return pstring
def trim_string(string, w):
return "%s... "%(string[0:w-4])
def format_column(col, lim):
size = len(col)
if (size >= lim - 1):
return trim_string(col,lim)
else:
return "%s%s"%(col," "*(lim-size))
def format_row(row,column_widths):
return "".join([format_column(row[i],column_widths[i]) for i in range(0,len(row))])

View File

@ -0,0 +1,357 @@
# -*- coding: utf-8 -*-
#
# torrentdetail.py
#
# Copyright (C) 2011 Nick Lanham <nick@afternight.org>
#
# 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 3 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
from basemode import BaseMode
import deluge.common
from deluge.ui.client import client
from sys import maxint
from deluge.ui.sessionproxy import SessionProxy
from popup import Popup,SelectablePopup,MessagePopup
from add_util import add_torrent
from input_popup import InputPopup
import format_utils
try:
import curses
except ImportError:
pass
import logging
log = logging.getLogger(__name__)
class TorrentDetail(BaseMode, component.Component):
def __init__(self, alltorrentmode, torrentid, stdscr, encoding=None):
self.alltorrentmode = alltorrentmode
self.torrentid = torrentid
self.torrent_state = None
self._status_keys = ["files", "name","state","download_payload_rate","upload_payload_rate",
"progress","eta","all_time_download","total_uploaded", "ratio",
"num_seeds","total_seeds","num_peers","total_peers", "active_time",
"seeding_time","time_added","distributed_copies", "num_pieces",
"piece_length","save_path","file_progress","file_priorities"]
self._info_fields = [
("Name",None,("name",)),
("State", None, ("state",)),
("Down Speed", format_utils.format_speed, ("download_payload_rate",)),
("Up Speed", format_utils.format_speed, ("upload_payload_rate",)),
("Progress", format_utils.format_progress, ("progress",)),
("ETA", deluge.common.ftime, ("eta",)),
("Path", None, ("save_path",)),
("Downloaded",deluge.common.fsize,("all_time_download",)),
("Uploaded", deluge.common.fsize,("total_uploaded",)),
("Share Ratio", lambda x:x < 0 and "" or "%.3f"%x, ("ratio",)),
("Seeders",format_utils.format_seeds_peers,("num_seeds","total_seeds")),
("Peers",format_utils.format_seeds_peers,("num_peers","total_peers")),
("Active Time",deluge.common.ftime,("active_time",)),
("Seeding Time",deluge.common.ftime,("seeding_time",)),
("Date Added",deluge.common.fdate,("time_added",)),
("Availability", lambda x:x < 0 and "" or "%.3f"%x, ("distributed_copies",)),
("Pieces", format_utils.format_pieces, ("num_pieces","piece_length")),
]
self.file_list = None
self.current_file = None
self.current_file_idx = 0
self.file_limit = maxint
self.file_off = 0
self.more_to_draw = False
self.column_string = ""
BaseMode.__init__(self, stdscr, encoding)
component.Component.__init__(self, "TorrentDetail", 1, depend=["SessionProxy"])
self.column_names = ["Filename", "Size", "Progress", "Priority"]
self._update_columns()
component.start(["TorrentDetail"])
curses.curs_set(0)
self.stdscr.notimeout(0)
# component start/update
def start(self):
component.get("SessionProxy").get_torrent_status(self.torrentid, self._status_keys).addCallback(self.set_state)
def update(self):
component.get("SessionProxy").get_torrent_status(self.torrentid, self._status_keys).addCallback(self.set_state)
def set_state(self, state):
log.debug("got state")
if not self.file_list:
# don't keep getting the files once we've got them once
self.file_list,self.file_dict = self.build_file_list(state["files"],state["file_progress"],state["file_priorities"])
self._status_keys.remove("files")
self._fill_progress(self.file_list,state["file_progress"])
for i,prio in enumerate(state["file_priorities"]):
self.file_dict[i][6] = format_utils.format_priority(prio)
del state["file_progress"]
del state["file_priorities"]
self.torrent_state = state
self.refresh()
# split file list into directory tree. this function assumes all files in a
# particular directory are returned together. it won't work otherwise.
# returned list is a list of lists of the form:
# [file/dir_name,index,size,children,expanded,progress,priority]
# for directories index will be -1, for files the value returned in the
# state object for use with other libtorrent calls (i.e. setting prio)
#
# Also returns a dictionary that maps index values to the file leaves
# for fast updating of progress and priorities
def build_file_list(self, file_tuples,prog,prio):
ret = []
retdict = {}
for f in file_tuples:
cur = ret
ps = f["path"].split("/")
fin = ps[-1]
for p in ps:
if not cur or p != cur[-1][0]:
cl = []
if p == fin:
ent = [p,f["index"],f["size"],cl,False,
format_utils.format_progress(prog[f["index"]]*100),
format_utils.format_priority(prio[f["index"]])]
retdict[f["index"]] = ent
else:
ent = [p,-1,-1,cl,False,"-","-"]
cur.append(ent)
cur = cl
else:
cur = cur[-1][3]
self._build_sizes(ret)
self._fill_progress(ret,prog)
return (ret,retdict)
# fill in the sizes of the directory entries based on their children
def _build_sizes(self, fs):
ret = 0
for f in fs:
if f[2] == -1:
val = self._build_sizes(f[3])
ret += val
f[2] = val
else:
ret += f[2]
return ret
# fills in progress fields in all entries based on progs
# returns the # of bytes complete in all the children of fs
def _fill_progress(self,fs,progs):
tb = 0
for f in fs:
if f[3]: # dir, has some children
bd = self._fill_progress(f[3],progs)
f[5] = format_utils.format_progress((bd/f[2])*100)
else: # file, update own prog and add to total
bd = f[2]*progs[f[1]]
f[5] = format_utils.format_progress(progs[f[1]]*100)
tb += bd
return tb
def _update_columns(self):
self.column_widths = [-1,15,15,20]
req = sum(filter(lambda x:x >= 0,self.column_widths))
if (req > self.cols): # can't satisfy requests, just spread out evenly
cw = int(self.cols/len(self.column_names))
for i in range(0,len(self.column_widths)):
self.column_widths[i] = cw
else:
rem = self.cols - req
var_cols = len(filter(lambda x: x < 0,self.column_widths))
vw = int(rem/var_cols)
for i in range(0, len(self.column_widths)):
if (self.column_widths[i] < 0):
self.column_widths[i] = vw
self.column_string = "{!header!}%s"%("".join(["%s%s"%(self.column_names[i]," "*(self.column_widths[i]-len(self.column_names[i]))) for i in range(0,len(self.column_names))]))
def draw_files(self,files,depth,off,idx):
for fl in files:
# kick out if we're going to draw too low on the screen
if (off >= self.rows-1):
self.more_to_draw = True
return -1,-1
self.file_limit = idx
if idx >= self.file_off:
# set fg/bg colors based on if we are selected or not
if idx == self.current_file_idx:
self.current_file = fl
fc = "{!black,white!}"
else:
fc = "{!white,black!}"
#actually draw the dir/file string
if fl[3] and fl[4]: # this is an expanded directory
xchar = 'v'
elif fl[3]: # collapsed directory
xchar = '>'
else: # file
xchar = '-'
r = format_utils.format_row(["%s%s %s"%(" "*depth,xchar,fl[0]),
deluge.common.fsize(fl[2]),fl[5],fl[6]],
self.column_widths)
self.add_string(off,"%s%s"%(fc,r),trim=False)
off += 1
if fl[3] and fl[4]:
# recurse if we have children and are expanded
off,idx = self.draw_files(fl[3],depth+1,off,idx+1)
if off < 0: return (off,idx)
else:
idx += 1
return (off,idx)
def refresh(self,lines=None):
# Update the status bars
self.stdscr.clear()
self.add_string(0,self.statusbars.topbar)
hstr = "%sPress [h] for help"%(" "*(self.cols - len(self.statusbars.bottombar) - 10))
self.add_string(self.rows - 1, "%s%s"%(self.statusbars.bottombar,hstr))
self.stdscr.hline((self.rows/2)-1,0,"_",self.cols)
off = 1
if self.torrent_state:
for f in self._info_fields:
if off >= (self.rows/2): break
if f[1] != None:
args = []
try:
for key in f[2]:
args.append(self.torrent_state[key])
except:
log.debug("Could not get info field: %s",e)
continue
info = f[1](*args)
else:
info = self.torrent_state[f[2][0]]
self.add_string(off,"{!info!}%s: {!input!}%s"%(f[0],info))
off += 1
else:
self.add_string(1, "Waiting for torrent state")
off = self.rows/2
self.add_string(off,self.column_string)
if self.file_list:
off += 1
self.more_to_draw = False
self.draw_files(self.file_list,0,off,0)
#self.stdscr.redrawwin()
self.stdscr.noutrefresh()
curses.doupdate()
# expand or collapse the current file
def expcol_cur_file(self):
self.current_file[4] = not self.current_file[4]
self.refresh()
def file_list_down(self):
if (self.current_file_idx + 1) > self.file_limit:
if self.more_to_draw:
self.current_file_idx += 1
self.file_off += 1
else:
return
else:
self.current_file_idx += 1
self.refresh()
def file_list_up(self):
self.current_file_idx = max(0,self.current_file_idx-1)
self.file_off = min(self.file_off,self.current_file_idx)
self.refresh()
def back_to_overview(self):
component.stop(["TorrentDetail"])
component.deregister("TorrentDetail")
self.stdscr.clear()
component.get("ConsoleUI").set_mode(self.alltorrentmode)
self.alltorrentmode.resume()
def _doRead(self):
c = self.stdscr.getch()
if c > 31 and c < 256:
if chr(c) == 'Q':
from twisted.internet import reactor
if client.connected():
def on_disconnect(result):
reactor.stop()
client.disconnect().addCallback(on_disconnect)
else:
reactor.stop()
return
elif chr(c) == 'q':
self.back_to_overview()
return
if c == 27:
self.back_to_overview()
return
# Navigate the torrent list
if c == curses.KEY_UP:
self.file_list_up()
elif c == curses.KEY_PPAGE:
pass
elif c == curses.KEY_DOWN:
self.file_list_down()
elif c == curses.KEY_NPAGE:
pass
# Enter Key
elif c == curses.KEY_ENTER or c == 10:
pass
# space
elif c == 32:
self.expcol_cur_file()
self.refresh()

View File

@ -41,7 +41,6 @@ class StatusBars(component.Component):
def __init__(self): def __init__(self):
component.Component.__init__(self, "StatusBars", 2, depend=["CoreConfig"]) component.Component.__init__(self, "StatusBars", 2, depend=["CoreConfig"])
self.config = component.get("CoreConfig") self.config = component.get("CoreConfig")
self.screen = component.get("ConsoleUI").screen
# Hold some values we get from the core # Hold some values we get from the core
self.connections = 0 self.connections = 0
@ -49,6 +48,10 @@ class StatusBars(component.Component):
self.upload = "" self.upload = ""
self.dht = 0 self.dht = 0
# Default values
self.topbar = "{!status!}Deluge %s Console - " % deluge.common.get_version()
self.bottombar = "{!status!}C: %s" % self.connections
def start(self): def start(self):
self.update() self.update()
@ -77,30 +80,28 @@ class StatusBars(component.Component):
def update_statusbars(self): def update_statusbars(self):
# Update the topbar string # Update the topbar string
self.screen.topbar = "{!status!}Deluge %s Console - " % deluge.common.get_version() self.topbar = "{!status!}Deluge %s Console - " % deluge.common.get_version()
if client.connected(): if client.connected():
info = client.connection_info() info = client.connection_info()
self.screen.topbar += "%s@%s:%s" % (info[2], info[0], info[1]) self.topbar += "%s@%s:%s" % (info[2], info[0], info[1])
else: else:
self.screen.topbar += "Not Connected" self.topbar += "Not Connected"
# Update the bottombar string # Update the bottombar string
self.screen.bottombar = "{!status!}C: %s" % self.connections self.bottombar = "{!status!}C: %s" % self.connections
if self.config["max_connections_global"] > -1: if self.config["max_connections_global"] > -1:
self.screen.bottombar += " (%s)" % self.config["max_connections_global"] self.bottombar += " (%s)" % self.config["max_connections_global"]
self.screen.bottombar += " D: %s/s" % self.download self.bottombar += " D: %s/s" % self.download
if self.config["max_download_speed"] > -1: if self.config["max_download_speed"] > -1:
self.screen.bottombar += " (%s KiB/s)" % self.config["max_download_speed"] self.bottombar += " (%s KiB/s)" % self.config["max_download_speed"]
self.screen.bottombar += " U: %s/s" % self.upload self.bottombar += " U: %s/s" % self.upload
if self.config["max_upload_speed"] > -1: if self.config["max_upload_speed"] > -1:
self.screen.bottombar += " (%s KiB/s)" % self.config["max_upload_speed"] self.bottombar += " (%s KiB/s)" % self.config["max_upload_speed"]
if self.config["dht"]: if self.config["dht"]:
self.screen.bottombar += " DHT: %s" % self.dht self.bottombar += " DHT: %s" % self.dht
self.screen.refresh()