deluge/deluge/ui/console/modes/preferences.py
2011-02-15 19:10:57 +01:00

289 lines
9.9 KiB
Python

# -*- coding: utf-8 -*-
#
# preferences.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 deluge.ui.client import client
from basemode import BaseMode
from input_popup import Popup,SelectInput
from preference_panes import DownloadsPane,NetworkPane,BandwidthPane,InterfacePane
from preference_panes import OtherPane,DaemonPane,QueuePane,ProxyPane,CachePane
from collections import deque
try:
import curses
except ImportError:
pass
import logging
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, active_port, status, stdscr, encoding=None):
self.parent_mode = parent_mode
self.categories = [_("Downloads"), _("Network"), _("Bandwidth"),
_("Interface"), _("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.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.prefs_width = self.cols-self.div_off-1
self.panes = [
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),
InterfacePane(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)
]
self.action_input = SelectInput(self,None,None,["Cancel","Apply","OK"],[0,1,2],0)
self.refresh()
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 refresh(self):
if self.popup == None and self.messages:
title,msg = self.messages.popleft()
self.popup = MessagePopup(self,title,msg)
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.__draw_catetories()
self.__draw_actions()
# do this last since it moves the cursor
self.__draw_preferences()
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:
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)
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.clear()
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 == 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()