From 5d46d2aee507db12e0827955223409d13c454572 Mon Sep 17 00:00:00 2001 From: Nick Date: Tue, 1 Feb 2011 17:23:15 +0100 Subject: [PATCH] add torrentdetails state, allow state switching, move some formating to format_utils --- deluge/ui/console/main.py | 14 +- deluge/ui/console/modes/alltorrents.py | 89 +++--- deluge/ui/console/modes/basemode.py | 13 +- deluge/ui/console/modes/format_utils.py | 70 +++++ deluge/ui/console/modes/torrentdetail.py | 357 +++++++++++++++++++++++ deluge/ui/console/statusbars.py | 27 +- 6 files changed, 501 insertions(+), 69 deletions(-) create mode 100644 deluge/ui/console/modes/format_utils.py create mode 100644 deluge/ui/console/modes/torrentdetail.py diff --git a/deluge/ui/console/main.py b/deluge/ui/console/main.py index a0090ef15..3829e3d8f 100644 --- a/deluge/ui/console/main.py +++ b/deluge/ui/console/main.py @@ -48,6 +48,7 @@ import deluge.component as component from deluge.ui.client import client import deluge.common from deluge.ui.coreconfig import CoreConfig +from deluge.ui.sessionproxy import SessionProxy from deluge.ui.console.statusbars import StatusBars from deluge.ui.console.eventlog import EventLog import screen @@ -156,7 +157,10 @@ class ConsoleUI(component.Component): log.debug("Using encoding: %s", self.encoding) # 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) @@ -213,9 +217,9 @@ class ConsoleUI(component.Component): # We want to do an interactive session, so start up the curses screen and # pass it the function that handles commands colors.init_colors() + self.statusbars = StatusBars() from modes.alltorrents import AllTorrents self.screen = AllTorrents(stdscr, self.coreconfig, self.encoding) - self.statusbars = StatusBars() self.eventlog = EventLog() self.screen.topbar = "{!status!}Deluge " + deluge.common.get_version() + " Console" @@ -264,6 +268,12 @@ class ConsoleUI(component.Component): if not batch and self.interactive: 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): """ Writes a line out depending on if we're in interactive mode or not. diff --git a/deluge/ui/console/modes/alltorrents.py b/deluge/ui/console/modes/alltorrents.py index 8e64e436b..f2f264225 100644 --- a/deluge/ui/console/modes/alltorrents.py +++ b/deluge/ui/console/modes/alltorrents.py @@ -46,7 +46,9 @@ from deluge.ui.sessionproxy import SessionProxy from popup import Popup,SelectablePopup,MessagePopup from add_util import add_torrent from input_popup import InputPopup +from torrentdetail import TorrentDetail +import format_utils try: import curses @@ -146,7 +148,7 @@ class StateUpdater(component.Component): self._status_cb(state,refresh) -class AllTorrents(BaseMode, component.Component): +class AllTorrents(BaseMode): def __init__(self, stdscr, coreconfig, encoding=None): self.formatted_rows = None self.cursel = 1 @@ -166,7 +168,6 @@ class AllTorrents(BaseMode, component.Component): BaseMode.__init__(self, stdscr, encoding) curses.curs_set(0) self.stdscr.notimeout(0) - self.sessionproxy = SessionProxy() self._status_fields = ["queue","name","total_wanted","state","progress","num_seeds","total_seeds", "num_peers","total_peers","download_payload_rate", "upload_payload_rate"] @@ -180,21 +181,21 @@ class AllTorrents(BaseMode, component.Component): self._info_fields = [ ("Name",None,("name",)), ("State", None, ("state",)), - ("Down Speed", self._format_speed, ("download_payload_rate",)), - ("Up Speed", self._format_speed, ("upload_payload_rate",)), - ("Progress", self._format_progress, ("progress",)), + ("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",self._format_seeds_peers,("num_seeds","total_seeds")), - ("Peers",self._format_seeds_peers,("num_peers","total_peers")), + ("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", 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", @@ -203,6 +204,11 @@ class AllTorrents(BaseMode, component.Component): "seeding_time","time_added","distributed_copies", "num_pieces", "piece_length","save_path"] + def resume(self): + component.start(["AllTorrentsStateUpdater"]) + self.refresh() + + def _update_columns(self): self.column_widths = [5,-1,15,13,10,10,10,15,15] 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))])) - 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): 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) for torrent_id in self._sorted_ids: ts = self.curstate[torrent_id] - newrows.append((self._format_row([self._format_queue(ts["queue"]), - ts["name"], - "%s"%deluge.common.fsize(ts["total_wanted"]), - ts["state"], - self._format_progress(ts["progress"]), - self._format_seeds_peers(ts["num_seeds"],ts["total_seeds"]), - self._format_seeds_peers(ts["num_peers"],ts["total_peers"]), - self._format_speed(ts["download_payload_rate"]), - self._format_speed(ts["upload_payload_rate"]) - ]),ts["state"])) + newrows.append((format_utils.format_row([self._format_queue(ts["queue"]), + ts["name"], + "%s"%deluge.common.fsize(ts["total_wanted"]), + ts["state"], + format_utils.format_progress(ts["progress"]), + format_utils.format_seeds_peers(ts["num_seeds"],ts["total_seeds"]), + format_utils.format_seeds_peers(ts["num_peers"],ts["total_peers"]), + format_utils.format_speed(ts["download_payload_rate"]), + format_utils.format_speed(ts["upload_payload_rate"]) + ],self.column_widths),ts["state"])) self.numtorrents = len(state) self.formatted_rows = newrows if refresh: @@ -328,27 +322,12 @@ class AllTorrents(BaseMode, component.Component): "sorts by 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): if (qnum >= 0): return "%d"%(qnum+1) else: 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): rerr = error.value 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)) def refresh(self,lines=None): + #log.error("ref") + #import traceback + #traceback.print_stack() # Something has requested we scroll to the top of the list if self._go_top: self.cursel = 1 @@ -491,12 +473,12 @@ class AllTorrents(BaseMode, component.Component): # Update the status bars if self._curr_filter == None: - self.add_string(0,self.topbar) + self.add_string(0,self.statusbars.topbar) 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) - hstr = "%sPress [h] for help"%(" "*(self.cols - len(self.bottombar) - 10)) - self.add_string(self.rows - 1, "%s%s"%(self.bottombar,hstr)) + hstr = "%sPress [h] for help"%(" "*(self.cols - len(self.statusbars.bottombar) - 10)) + self.add_string(self.rows - 1, "%s%s"%(self.statusbars.bottombar,hstr)) # add all the torrents if self.formatted_rows == []: @@ -621,6 +603,15 @@ class AllTorrents(BaseMode, component.Component): elif c == curses.KEY_NPAGE: 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 elif c == curses.KEY_ENTER or c == 10: self.marked.append(self.cursel) diff --git a/deluge/ui/console/modes/basemode.py b/deluge/ui/console/modes/basemode.py index d02b2d25d..b32857ae6 100644 --- a/deluge/ui/console/modes/basemode.py +++ b/deluge/ui/console/modes/basemode.py @@ -43,6 +43,7 @@ try: except ImportError: pass +import deluge.component as component import deluge.ui.console.colors as colors try: import signal @@ -98,8 +99,7 @@ class BaseMode(CursesStdIO): self.stdscr.nodelay(1) # Strings for the 2 status bars - self.topbar = "" - self.bottombar = "" + self.statusbars = component.get("StatusBars") # Keep track of the screen size self.rows, self.cols = self.stdscr.getmaxyx() @@ -182,6 +182,10 @@ class BaseMode(CursesStdIO): screen.addstr(row, col, s, color) 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): """ Refreshes the screen. @@ -189,10 +193,9 @@ class BaseMode(CursesStdIO): attribute and the status bars. """ self.stdscr.clear() - + self.draw_statusbars() # 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.stdscr.redrawwin() diff --git a/deluge/ui/console/modes/format_utils.py b/deluge/ui/console/modes/format_utils.py new file mode 100644 index 000000000..f3c49d6a5 --- /dev/null +++ b/deluge/ui/console/modes/format_utils.py @@ -0,0 +1,70 @@ +# format_utils.py +# +# Copyright (C) 2011 Nick Lanham +# +# 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))]) diff --git a/deluge/ui/console/modes/torrentdetail.py b/deluge/ui/console/modes/torrentdetail.py new file mode 100644 index 000000000..5f144f69d --- /dev/null +++ b/deluge/ui/console/modes/torrentdetail.py @@ -0,0 +1,357 @@ +# -*- coding: utf-8 -*- +# +# torrentdetail.py +# +# Copyright (C) 2011 Nick Lanham +# +# 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() diff --git a/deluge/ui/console/statusbars.py b/deluge/ui/console/statusbars.py index 44be33cf0..9d7a09fec 100644 --- a/deluge/ui/console/statusbars.py +++ b/deluge/ui/console/statusbars.py @@ -41,7 +41,6 @@ class StatusBars(component.Component): def __init__(self): component.Component.__init__(self, "StatusBars", 2, depend=["CoreConfig"]) self.config = component.get("CoreConfig") - self.screen = component.get("ConsoleUI").screen # Hold some values we get from the core self.connections = 0 @@ -49,6 +48,10 @@ class StatusBars(component.Component): self.upload = "" 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): self.update() @@ -77,30 +80,28 @@ class StatusBars(component.Component): def update_statusbars(self): # 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(): 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: - self.screen.topbar += "Not Connected" + self.topbar += "Not Connected" # 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: - 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: - 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: - 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"]: - self.screen.bottombar += " DHT: %s" % self.dht - - self.screen.refresh() + self.bottombar += " DHT: %s" % self.dht