deluge/deluge/ui/console/modes/preferences.py
2014-09-19 13:39:41 +01:00

298 lines
11 KiB
Python

# -*- coding: utf-8 -*-
#
# Copyright (C) 2011 Nick Lanham <nick@afternight.org>
#
# This file is part of Deluge and is licensed under GNU General Public License 3.0, or later, with
# the additional special exception to link portions of this program with the OpenSSL library.
# See LICENSE for more details.
#
import logging
from collections import deque
import deluge.component as component
from deluge.ui.client import client
from deluge.ui.console.basemode import BaseMode
from deluge.ui.console.input_popup import Popup, SelectInput
from deluge.ui.console.popup import MessagePopup
from deluge.ui.console.preference_panes import (BandwidthPane, CachePane, ColumnsPane, DaemonPane,
DownloadsPane, InterfacePane, NetworkPane, OtherPane,
ProxyPane, QueuePane)
try:
import curses
except ImportError:
pass
log = logging.getLogger(__name__)
# Big help string that gets displayed when the user hits 'h'
HELP_STR = """This screen lets you view and configure various options in deluge.
There are three main sections to this screen. Only one
section is active at a time. You can switch the active
section by hitting TAB (or Shift-TAB to go back one)
The section on the left displays the various categories
that the settings fall in. You can navigate the list
using the up/down arrows
The section on the right shows the settings for the
selected category. When this section is active
you can navigate the various settings with the up/down
arrows. Special keys for each input type are described
below.
The final section is at the bottom right, the:
[Cancel] [Apply] [OK] buttons. When this section
is active, simply select the option you want using
the arrow keys and press Enter to confim.
Special keys for various input types are as follows:
- For text inputs you can simply type in the value.
- For numeric inputs (indicated by the value being
in []s), you can type a value, or use PageUp and
PageDown to increment/decrement the value.
- For checkbox inputs use the spacebar to toggle
- For checkbox plus something else inputs (the
something else being only visible when you
check the box) you can toggle the check with
space, use the right arrow to edit the other
value, and escape to get back to the check box.
"""
HELP_LINES = HELP_STR.split("\n")
class ZONE:
CATEGORIES = 0
PREFRENCES = 1
ACTIONS = 2
class Preferences(BaseMode):
def __init__(self, parent_mode, core_config, console_config, active_port, status, stdscr, encoding=None):
self.parent_mode = parent_mode
self.categories = [_("Interface"), _("Columns"), _("Downloads"), _("Network"), _("Bandwidth"),
_("Other"), _("Daemon"), _("Queue"), _("Proxy"), _("Cache")] # , _("Plugins")]
self.cur_cat = 0
self.popup = None
self.messages = deque()
self.action_input = None
self.core_config = core_config
self.console_config = console_config
self.active_port = active_port
self.status = status
self.active_zone = ZONE.CATEGORIES
# how wide is the left 'pane' with categories
self.div_off = 15
BaseMode.__init__(self, stdscr, encoding, False)
# create the panes
self.__calc_sizes()
self.action_input = SelectInput(self, None, None, ["Cancel", "Apply", "OK"], [0, 1, 2], 0)
self.refresh()
def __calc_sizes(self):
self.prefs_width = self.cols - self.div_off - 1
self.prefs_height = self.rows - 4
# Needs to be same order as self.categories
self.panes = [
InterfacePane(self.div_off + 2, self, self.prefs_width),
ColumnsPane(self.div_off + 2, self, self.prefs_width),
DownloadsPane(self.div_off + 2, self, self.prefs_width),
NetworkPane(self.div_off + 2, self, self.prefs_width),
BandwidthPane(self.div_off + 2, self, self.prefs_width),
OtherPane(self.div_off + 2, self, self.prefs_width),
DaemonPane(self.div_off + 2, self, self.prefs_width),
QueuePane(self.div_off + 2, self, self.prefs_width),
ProxyPane(self.div_off + 2, self, self.prefs_width),
CachePane(self.div_off + 2, self, self.prefs_width)
]
def __draw_catetories(self):
for i, category in enumerate(self.categories):
if i == self.cur_cat and self.active_zone == ZONE.CATEGORIES:
self.add_string(i + 1, "- {!black,white,bold!}%s" % category, pad=False)
elif i == self.cur_cat:
self.add_string(i + 1, "- {!black,white!}%s" % category, pad=False)
else:
self.add_string(i + 1, "- %s" % category)
self.stdscr.vline(1, self.div_off, "|", self.rows - 2)
def __draw_preferences(self):
self.panes[self.cur_cat].render(self, self.stdscr, self.prefs_width, self.active_zone == ZONE.PREFRENCES)
def __draw_actions(self):
selected = self.active_zone == ZONE.ACTIONS
self.stdscr.hline(self.rows - 3, self.div_off + 1, "_", self.cols)
self.action_input.render(self.stdscr, self.rows - 2, self.cols, selected, self.cols - 22)
def on_resize(self, *args):
BaseMode.on_resize_norefresh(self, *args)
self.__calc_sizes()
#Always refresh Legacy(it will also refresh AllTorrents), otherwise it will bug deluge out
legacy = component.get("LegacyUI")
legacy.on_resize(*args)
self.stdscr.erase()
self.refresh()
def refresh(self):
if self.popup is None and self.messages:
title, msg = self.messages.popleft()
self.popup = MessagePopup(self, title, msg)
self.stdscr.erase()
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.__draw_catetories()
self.__draw_actions()
# do this last since it moves the cursor
self.__draw_preferences()
if component.get("ConsoleUI").screen != self:
return
self.stdscr.noutrefresh()
if self.popup:
self.popup.refresh()
curses.doupdate()
def __category_read(self, c):
# Navigate prefs
if c == curses.KEY_UP:
self.cur_cat = max(0, self.cur_cat - 1)
elif c == curses.KEY_DOWN:
self.cur_cat = min(len(self.categories) - 1, self.cur_cat + 1)
def __prefs_read(self, c):
self.panes[self.cur_cat].handle_read(c)
def __apply_prefs(self):
new_core_config = {}
for pane in self.panes:
if not isinstance(pane, InterfacePane) and not isinstance(pane, ColumnsPane):
pane.add_config_values(new_core_config)
# Apply Core Prefs
if client.connected():
# Only do this if we're connected to a daemon
config_to_set = {}
for key in new_core_config.keys():
# The values do not match so this needs to be updated
if self.core_config[key] != new_core_config[key]:
config_to_set[key] = new_core_config[key]
if config_to_set:
# Set each changed config value in the core
client.core.set_config(config_to_set)
client.force_call(True)
# Update the configuration
self.core_config.update(config_to_set)
# Update Interface Prefs
new_console_config = {}
didupdate = False
for pane in self.panes:
# could just access panes by index, but that would break if panes
# are ever reordered, so do it the slightly slower but safer way
if isinstance(pane, InterfacePane) or isinstance(pane, ColumnsPane):
pane.add_config_values(new_console_config)
for key in new_console_config.keys():
# The values do not match so this needs to be updated
if self.console_config[key] != new_console_config[key]:
self.console_config[key] = new_console_config[key]
didupdate = True
if didupdate:
# changed something, save config and tell alltorrents
self.console_config.save()
self.parent_mode.update_config()
def __update_preferences(self, core_config):
self.core_config = core_config
for pane in self.panes:
pane.update_values(core_config)
def __actions_read(self, c):
self.action_input.handle_read(c)
if c == curses.KEY_ENTER or c == 10:
# take action
if self.action_input.selidx == 0: # Cancel
self.back_to_parent()
elif self.action_input.selidx == 1: # Apply
self.__apply_prefs()
client.core.get_config().addCallback(self.__update_preferences)
elif self.action_input.selidx == 2: # OK
self.__apply_prefs()
self.back_to_parent()
def back_to_parent(self):
self.stdscr.erase()
component.get("ConsoleUI").set_mode(self.parent_mode)
self.parent_mode.resume()
def _doRead(self):
c = self.stdscr.getch()
if self.popup:
if self.popup.handle_read(c):
self.popup = None
self.refresh()
return
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) == "h":
self.popup = Popup(self, "Preferences Help")
for l in HELP_LINES:
self.popup.add_line(l)
if c == 9:
self.active_zone += 1
if self.active_zone > ZONE.ACTIONS:
self.active_zone = ZONE.CATEGORIES
elif c == 27 and self.active_zone == ZONE.CATEGORIES:
self.back_to_parent()
elif c == curses.KEY_BTAB:
self.active_zone -= 1
if self.active_zone < ZONE.CATEGORIES:
self.active_zone = ZONE.ACTIONS
elif c == 114 and isinstance(self.panes[self.cur_cat], CachePane):
client.core.get_cache_status().addCallback(self.panes[self.cur_cat].update_cache_status)
else:
if self.active_zone == ZONE.CATEGORIES:
self.__category_read(c)
elif self.active_zone == ZONE.PREFRENCES:
self.__prefs_read(c)
elif self.active_zone == ZONE.ACTIONS:
self.__actions_read(c)
self.refresh()