aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJonathan McCrohan <jmccrohan@gmail.com>2012-09-10 20:29:30 +0100
committerJonathan McCrohan <jmccrohan@gmail.com>2012-09-10 20:29:30 +0100
commit8f7692d8ad892e73b9b0013cb107e66fb371dbc1 (patch)
tree26641a1ed93b18137380512ab493852f8eb91601
parenta8e991445ba757834bf2619f1194839ed8b37fb0 (diff)
downloadtransmission-remote-cli-8f7692d8ad892e73b9b0013cb107e66fb371dbc1.tar.gz
Imported Upstream version 1.4.1upstream/1.4.1
Diffstat (limited to '')
-rw-r--r--NEWS6
-rwxr-xr-xtransmission-remote-cli91
2 files changed, 51 insertions, 46 deletions
diff --git a/NEWS b/NEWS
index 1e5054d..46326f7 100644
--- a/NEWS
+++ b/NEWS
@@ -1,3 +1,9 @@
+1.4.1 2012-09-05
+ BUGFIXES:
+ - Indices of sorted file lists are now pointing to the correct files
+ - Fix crash in terminals without colors
+
+
1.4 2012-07-30
BUGFIXES:
- Fix crash upon opening help window for small terminals
diff --git a/transmission-remote-cli b/transmission-remote-cli
index 4bfe38d..8cd5dbf 100755
--- a/transmission-remote-cli
+++ b/transmission-remote-cli
@@ -16,7 +16,7 @@
# http://www.gnu.org/licenses/gpl-3.0.txt #
########################################################################
-VERSION = '1.4'
+VERSION = '1.4.1'
TRNSM_VERSION_MIN = '1.90'
TRNSM_VERSION_MAX = '2.61'
@@ -138,8 +138,16 @@ config.set('Colors', 'file_prio_off', 'bg:blue,fg:black')
class ColorManager:
def __init__(self, config):
self.config = dict()
+ self.term_has_colors = curses.has_colors()
+ curses.start_color()
+ if self.term_has_colors:
+ curses.use_default_colors()
for name in config.keys():
self.config[name] = self._parse_color_pair(config[name])
+ if self.term_has_colors:
+ curses.init_pair(self.config[name]['id'],
+ self.config[name]['fg'],
+ self.config[name]['bg'])
def _parse_color_pair(self, pair):
# BG and FG are intentionally switched here because colors are always
@@ -151,10 +159,7 @@ class ColorManager:
'bg': eval('curses.COLOR_' + bg_name),
'fg': eval('curses.COLOR_' + fg_name) }
- def get_id(self, name): return self.config[name]['id']
- def get_bg(self, name): return self.config[name]['bg']
- def get_fg(self, name): return self.config[name]['fg']
- def get_names(self): return self.config.keys()
+ def id(self, name): return self.config[name]['id']
class Normalizer:
@@ -803,6 +808,7 @@ class Interface:
self.details_category_focus = 0 # overview/files/peers/tracker in details
self.focus_detaillist = -1 # same as focus but for details
self.selected_files = [] # marked files in details
+ self.file_index_map = {} # Maps local torrent's file indices to server file indices
self.scrollpos_detaillist = 0 # same as scrollpos but for details
self.compact_torrentlist = False # draw only one line for each torrent in compact mode
self.exit_now = False
@@ -897,17 +903,7 @@ class Interface:
hide_cursor()
- # enable colors if available
- try:
- curses.start_color()
- curses.use_default_colors()
- self.colors = ColorManager(dict(config.items('Colors')))
- for name in sorted(self.colors.get_names()):
- curses.init_pair(self.colors.get_id(name),
- self.colors.get_fg(name),
- self.colors.get_bg(name))
- except:
- pass
+ self.colors = ColorManager(dict(config.items('Colors')))
# http://bugs.python.org/issue2675
try:
@@ -1398,10 +1394,10 @@ class Interface:
if self.details_category_focus == 1 and \
(self.selected_files or self.focus_detaillist > -1):
if self.selected_files:
- files = set(self.selected_files)
+ files = set([self.file_index_map[index] for index in self.selected_files])
server.increase_file_priority(files)
elif self.focus_detaillist > -1:
- server.increase_file_priority([self.focus_detaillist])
+ server.increase_file_priority([self.file_index_map[self.focus_detaillist]])
else:
self.scrollpos_detaillist = 0
self.next_details()
@@ -1409,10 +1405,10 @@ class Interface:
if self.details_category_focus == 1 and \
(self.selected_files or self.focus_detaillist > -1):
if self.selected_files:
- files = set(self.selected_files)
+ files = set([self.file_index_map[index] for index in self.selected_files])
server.decrease_file_priority(files)
elif self.focus_detaillist > -1:
- server.decrease_file_priority([self.focus_detaillist])
+ server.decrease_file_priority([self.file_index_map[self.focus_detaillist]])
else:
self.scrollpos_detaillist = 0
self.prev_details()
@@ -1594,24 +1590,24 @@ class Interface:
self.pad.addch(curses.ACS_DARROW, (0,curses.A_BOLD)[torrent['downloadLimited']])
rate = ('',scale_bytes(torrent['rateDownload']))[torrent['rateDownload']>0]
self.pad.addstr(rate.rjust(self.rateDownload_width),
- curses.color_pair(self.colors.get_id('download_rate')) + curses.A_BOLD + curses.A_REVERSE)
+ curses.color_pair(self.colors.id('download_rate')) + curses.A_BOLD + curses.A_REVERSE)
def draw_uploadrate(self, torrent, ypos):
self.pad.move(ypos, self.width-self.rateUpload_width-1)
self.pad.addch(curses.ACS_UARROW, (0,curses.A_BOLD)[torrent['uploadLimited']])
rate = ('',scale_bytes(torrent['rateUpload']))[torrent['rateUpload']>0]
self.pad.addstr(rate.rjust(self.rateUpload_width),
- curses.color_pair(self.colors.get_id('upload_rate')) + curses.A_BOLD + curses.A_REVERSE)
+ curses.color_pair(self.colors.id('upload_rate')) + curses.A_BOLD + curses.A_REVERSE)
def draw_ratio(self, torrent, ypos):
self.pad.addch(ypos+1, self.width-self.rateUpload_width-1, curses.ACS_DIAMOND,
(0,curses.A_BOLD)[torrent['uploadRatio'] < 1 and torrent['uploadRatio'] >= 0])
self.pad.addstr(ypos+1, self.width-self.rateUpload_width,
num2str(torrent['uploadRatio'], '%.02f').rjust(self.rateUpload_width),
- curses.color_pair(self.colors.get_id('eta+ratio')) + curses.A_BOLD + curses.A_REVERSE)
+ curses.color_pair(self.colors.id('eta+ratio')) + curses.A_BOLD + curses.A_REVERSE)
def draw_eta(self, torrent, ypos):
self.pad.addch(ypos+1, self.width-self.rateDownload_width-self.rateUpload_width-3, curses.ACS_PLMINUS)
self.pad.addstr(ypos+1, self.width-self.rateDownload_width-self.rateUpload_width-2,
scale_time(torrent['eta']).rjust(self.rateDownload_width),
- curses.color_pair(self.colors.get_id('eta+ratio')) + curses.A_BOLD + curses.A_REVERSE)
+ curses.color_pair(self.colors.id('eta+ratio')) + curses.A_BOLD + curses.A_REVERSE)
def draw_torrentlist_title(self, torrent, focused, width, ypos):
@@ -1632,18 +1628,18 @@ class Interface:
if torrent['status'] == Transmission.STATUS_SEED or \
torrent['status'] == Transmission.STATUS_SEED_WAIT:
- color = curses.color_pair(self.colors.get_id('title_seed'))
+ color = curses.color_pair(self.colors.id('title_seed'))
elif torrent['status'] == Transmission.STATUS_STOPPED:
- color = curses.color_pair(self.colors.get_id('title_paused'))
+ color = curses.color_pair(self.colors.id('title_paused'))
elif torrent['status'] == Transmission.STATUS_CHECK or \
torrent['status'] == Transmission.STATUS_CHECK_WAIT:
- color = curses.color_pair(self.colors.get_id('title_verify'))
+ color = curses.color_pair(self.colors.id('title_verify'))
elif torrent['status'] == Transmission.STATUS_ISOLATED:
- color = curses.color_pair(self.colors.get_id('title_error'))
+ color = curses.color_pair(self.colors.id('title_error'))
elif torrent['rateDownload'] == 0:
- color = curses.color_pair(self.colors.get_id('title_idle'))
+ color = curses.color_pair(self.colors.id('title_idle'))
elif torrent['percentDone'] < 100:
- color = curses.color_pair(self.colors.get_id('title_download'))
+ color = curses.color_pair(self.colors.id('title_download'))
else:
color = 0
@@ -1938,16 +1934,16 @@ class Interface:
for part in re.split('(high|normal|low|off)', line[0:30], 1):
if part == 'high':
self.pad.addstr(ypos, xpos, self.enc(part),
- curses_tags + curses.color_pair(self.colors.get_id('file_prio_high')))
+ curses_tags + curses.color_pair(self.colors.id('file_prio_high')))
elif part == 'normal':
self.pad.addstr(ypos, xpos, self.enc(part),
- curses_tags + curses.color_pair(self.colors.get_id('file_prio_normal')))
+ curses_tags + curses.color_pair(self.colors.id('file_prio_normal')))
elif part == 'low':
self.pad.addstr(ypos, xpos, self.enc(part),
- curses_tags + curses.color_pair(self.colors.get_id('file_prio_low')))
+ curses_tags + curses.color_pair(self.colors.id('file_prio_low')))
elif part == 'off':
self.pad.addstr(ypos, xpos, self.enc(part),
- curses_tags + curses.color_pair(self.colors.get_id('file_prio_off')))
+ curses_tags + curses.color_pair(self.colors.id('file_prio_off')))
else:
self.pad.addstr(ypos, xpos, self.enc(part), curses_tags)
xpos += len(part)
@@ -1958,13 +1954,16 @@ class Interface:
def create_filelist(self):
filelist = []
- files = self.torrent_details['files']
+ files = sorted(self.torrent_details['files'], cmp=lambda x,y: cmp(x['name'], y['name']))
current_folder = []
current_depth = 0
index = 0
pos = 0
pos_before_focus = 0
+ # Build new mapping between sorted local files and transmission-daemon's unsorted files
+ self.file_index_map = {}
for file in files:
+ self.file_index_map[index] = self.torrent_details['files'].index(file)
f = file['name'].split('/')
f_len = len(f) - 1
if f[:f_len] != current_folder:
@@ -2024,7 +2023,7 @@ class Interface:
def create_filelist_line(self, name, index, percent, length, current_depth):
line = "%s %6.1f%%" % (str(index+1).rjust(3), percent) + \
' '+scale_bytes(length).rjust(5) + \
- ' '+server.get_file_priority(self.torrent_details['id'], index).center(8) + \
+ ' '+server.get_file_priority(self.torrent_details['id'], self.file_index_map[index]).center(8) + \
" %s| %s" % (' '*current_depth, name[0:self.width-31-current_depth])
if index == self.focus_detaillist:
line = '_F' + line
@@ -2330,7 +2329,7 @@ class Interface:
if self.filter_list:
self.screen.addstr("Filter:", curses.A_REVERSE)
self.screen.addstr("%s%s" % (('','not ')[self.filter_inverse], self.filter_list),
- curses.color_pair(self.colors.get_id('filter_status'))
+ curses.color_pair(self.colors.id('filter_status'))
+ curses.A_REVERSE)
# show last sort order (if terminal size permits it)
@@ -2339,7 +2338,7 @@ class Interface:
self.screen.addstr(" Sort by:", curses.A_REVERSE)
name = [name[1] for name in self.sort_options if name[0] == self.sort_orders[-1]['name']][0]
name = name.replace('_', '').lower()
- curses_tags = curses.color_pair(self.colors.get_id('filter_status')) + curses.A_REVERSE
+ curses_tags = curses.color_pair(self.colors.id('filter_status')) + curses.A_REVERSE
if self.sort_orders[-1]['reverse']:
self.screen.addch(curses.ACS_DARROW, curses_tags)
else:
@@ -2370,14 +2369,14 @@ class Interface:
self.screen.move(self.height - 1, self.width - rates_width - limits_width)
self.screen.addch(curses.ACS_DARROW, curses.A_REVERSE)
self.screen.addstr(scale_bytes(self.stats['downloadSpeed']).rjust(self.rateDownload_width),
- curses.color_pair(self.colors.get_id('download_rate'))
+ curses.color_pair(self.colors.id('download_rate'))
+ curses.A_REVERSE + curses.A_BOLD)
self.screen.addstr(limits['dn_limit'], curses.A_REVERSE)
self.screen.addch(' ', curses.A_REVERSE)
self.screen.addch(curses.ACS_UARROW, curses.A_REVERSE)
self.screen.insstr(limits['up_limit'], curses.A_REVERSE)
self.screen.insstr(scale_bytes(self.stats['uploadSpeed']).rjust(self.rateUpload_width),
- curses.color_pair(self.colors.get_id('upload_rate'))
+ curses.color_pair(self.colors.id('upload_rate'))
+ curses.A_REVERSE + curses.A_BOLD)
@@ -2533,10 +2532,10 @@ class Interface:
win.keypad(True)
if important:
- win.bkgd(' ', curses.color_pair(self.colors.get_id('dialog_important'))
+ win.bkgd(' ', curses.color_pair(self.colors.id('dialog_important'))
+ curses.A_REVERSE)
- focus_tags = curses.color_pair(self.colors.get_id('button_focused'))
+ focus_tags = curses.color_pair(self.colors.id('button_focused'))
unfocus_tags = 0
input = False
@@ -2587,8 +2586,8 @@ class Interface:
displaytext = input[textwidth*page:textwidth*(page + 1)]
displayindex = index - textwidth*page
- color = (curses.color_pair(self.colors.get_id('dialog_important')) if self.highlight_dialog
- else curses.color_pair(self.colors.get_id('dialog')))
+ color = (curses.color_pair(self.colors.id('dialog_important')) if self.highlight_dialog
+ else curses.color_pair(self.colors.id('dialog')))
win.addstr(height - 2, 2, displaytext.ljust(textwidth), color)
win.move(height - 2, displayindex + 2)
c = win.getch()
@@ -2664,7 +2663,7 @@ class Interface:
win.addstr(height-4, 2, "leave empty for default")
while True:
- win.addstr(height-2, 2, input.ljust(width-4), curses.color_pair(self.colors.get_id('dialog')))
+ win.addstr(height-2, 2, input.ljust(width-4), curses.color_pair(self.colors.id('dialog')))
win.move(height - 2, len(input) + 2)
c = win.getch()
if c == 27 or c == ord('q') or c == curses.KEY_BREAK:
@@ -2752,7 +2751,7 @@ class Interface:
i = 1
for option in options:
title = option[1].split('_')
- if i == focus: tag = curses.color_pair(self.colors.get_id('dialog'))
+ if i == focus: tag = curses.color_pair(self.colors.id('dialog'))
else: tag = 0
win.addstr(i,2, title[0], tag)
win.addstr(title[1][0], tag + curses.A_UNDERLINE)