[Author Prev][Author Next][Thread Prev][Thread Next][Author Index][Thread Index]
[or-cvs] r23744: {arm} Making the config sort order configurable via the armrc (sti (in arm/trunk: . src/interface src/util)
Author: atagar
Date: 2010-11-04 17:18:58 +0000 (Thu, 04 Nov 2010)
New Revision: 23744
Modified:
arm/trunk/armrc.sample
arm/trunk/src/interface/configStatePanel.py
arm/trunk/src/interface/controller.py
arm/trunk/src/util/conf.py
Log:
Making the config sort order configurable via the armrc (still working on the sort dialog)
change: dropping the argument type from the main panel to make more room for the description
fix: making the default runlevel for config type errors NOTICE (was accidently lowered to INFO)
Modified: arm/trunk/armrc.sample
===================================================================
--- arm/trunk/armrc.sample 2010-11-03 16:51:12 UTC (rev 23743)
+++ arm/trunk/armrc.sample 2010-11-04 17:18:58 UTC (rev 23744)
@@ -58,6 +58,10 @@
# ---------------------------
# type
# 0 -> tor state, 1 -> torrc, 2 -> arm state, 3 -> armrc
+# order
+# three comma separated configuration attributes, options including:
+# 0 -> Category, 1 -> Option Name, 2 -> Value, 3 -> Arg Type,
+# 4 -> Arg Usage, 5 -> Description, 6 -> Is Default
# colWidth.*
# maximum column content width
# showScrollbars
@@ -72,6 +76,7 @@
# values or being setable themselves
features.config.type 0
+features.config.order 0, 1, 6
features.config.state.colWidth.option 25
features.config.state.colWidth.value 15
features.config.file.showScrollbars true
Modified: arm/trunk/src/interface/configStatePanel.py
===================================================================
--- arm/trunk/src/interface/configStatePanel.py 2010-11-03 16:51:12 UTC (rev 23743)
+++ arm/trunk/src/interface/configStatePanel.py 2010-11-04 17:18:58 UTC (rev 23744)
@@ -6,12 +6,13 @@
import curses
import threading
-from util import conf, panel, torTools, torConfig, uiTools
+from util import conf, log, panel, torTools, torConfig, uiTools
DEFAULT_CONFIG = {"features.config.showPrivateOptions": False,
"features.config.showVirtualOptions": False,
"features.config.state.colWidth.option": 25,
- "features.config.state.colWidth.value": 15}
+ "features.config.state.colWidth.value": 15,
+ "log.configEntryTypeError": log.NOTICE}
TOR_STATE, ARM_STATE = range(1, 3) # state to be presented
@@ -26,13 +27,15 @@
torConfig.UNKNOWN: "black"}
# attributes of a ConfigEntry
-FIELD_CATEGORY, FIELD_OPTION, FIELD_VALUE, FIELD_TYPE, FIELD_ARG_USAGE, FIELD_DESCRIPTION, FIELD_IS_DEFAULT = range(1, 8)
-FIELD_STR = {FIELD_CATEGORY: "Category",
- FIELD_OPTION: "Option Name",
- FIELD_TYPE: "Arg Type",
- FIELD_ARG_USAGE: "Arg Usage",
- FIELD_DESCRIPTION: "Description",
- FIELD_IS_DEFAULT: "Is Default"}
+FIELD_CATEGORY, FIELD_OPTION, FIELD_VALUE, FIELD_TYPE, FIELD_ARG_USAGE, FIELD_DESCRIPTION, FIELD_IS_DEFAULT = range(7)
+DEFAULT_SORT_ORDER = (FIELD_CATEGORY, FIELD_OPTION, FIELD_IS_DEFAULT)
+FIELD_ATTR = {FIELD_CATEGORY: ("Category", "red"),
+ FIELD_OPTION: ("Option Name", "blue"),
+ FIELD_VALUE: ("Value", "cyan"),
+ FIELD_TYPE: ("Arg Type", "green"),
+ FIELD_ARG_USAGE: ("Arg Usage", "yellow"),
+ FIELD_DESCRIPTION: ("Description", "white"),
+ FIELD_IS_DEFAULT: ("Is Default", "magenta")}
class ConfigEntry():
"""
@@ -98,10 +101,35 @@
def __init__(self, stdscr, configType, config=None):
panel.Panel.__init__(self, stdscr, "configState", 0)
+ self.sortOrdering = DEFAULT_SORT_ORDER
self._config = dict(DEFAULT_CONFIG)
- if config: config.update(self._config, {
- "features.config.state.colWidth.option": 5,
- "features.config.state.colWidth.value": 5})
+ if config:
+ config.update(self._config, {
+ "features.config.state.colWidth.option": 5,
+ "features.config.state.colWidth.value": 5})
+
+ # overrides the initial sort orderting if set
+ confSortOrder = config.get("features.config.order")
+ if confSortOrder:
+ # validates the input, setting the errorMsg if there's a problem
+ confSortOrderComp, errorMsg = confSortOrder.split(","), None
+ defaultOrderStr = ", ".join([str(i) for i in self.sortOrdering])
+ baseErrorMsg = "config entry 'features.config.order' is expected to %%s, defaulting to '%s'" % defaultOrderStr
+
+ if len(confSortOrderComp) != 3:
+ # checks that we got three comma separated values
+ errorMsg = baseErrorMsg % "be three comma separated values"
+ else:
+ # checks that values are numeric and in the right range
+ for val in confSortOrderComp:
+ val = val.strip()
+ if not val.isdigit() or int(val) < 0 or int(val) > 6:
+ errorMsg = baseErrorMsg % "only have numeric entries ranging 0-6"
+ break
+
+ if errorMsg: log.log(self._config["log.configEntryTypeError"], errorMsg)
+ else:
+ self.sortOrdering = [int(val.strip()) for val in confSortOrderComp]
self.configType = configType
self.confContents = []
@@ -139,21 +167,40 @@
self.confContents.append(ConfigEntry(cat, confOption, confType, arg, desc, not confOption in setOptions))
- self.confContents.sort(key=lambda i: (i.getAttr([FIELD_CATEGORY, FIELD_OPTION, FIELD_IS_DEFAULT])))
+
+ self.setSortOrder() # initial sorting of the contents
elif self.configType == ARM_STATE:
# loaded via the conf utility
armConf = conf.getConfig("arm")
for key in armConf.getKeys():
self.confContents.append(ConfigEntry("", key, ", ".join(armConf.getValue(key, [], True)), "", "", True))
-
- #self.confContents.sort() # TODO: make contents sortable?
+ def setSortOrder(self, ordering = None):
+ """
+ Sets the configuration attributes we're sorting by and resorts the
+ contents. If the ordering isn't defined then this resorts based on the
+ last set ordering.
+ """
+
+ self.valsLock.acquire()
+ if ordering: self.sortOrdering = ordering
+ self.confContents.sort(key=lambda i: (i.getAttr(self.sortOrdering)))
+ self.valsLock.release()
+
+ def getSortOrder(self):
+ """
+ Provides the current configuration attributes we're sorting by.
+ """
+
+ return self.sortOrdering
+
def handleKey(self, key):
self.valsLock.acquire()
if uiTools.isScrollKey(key):
pageHeight = self.getPreferredSize()[0] - 1
isChanged = self.scroller.handleKey(key, self.confContents, pageHeight)
if isChanged: self.redraw(True)
+ self.valsLock.release()
def draw(self, subwindow, width, height):
self.valsLock.acquire()
@@ -172,7 +219,7 @@
self.addScrollBar(scrollLoc, scrollLoc + height - 1, len(self.confContents), 1)
# determines the width for the columns
- optionColWidth, valueColWidth, typeColWidth = 0, 0, 0
+ optionColWidth, valueColWidth = 0, 0
# constructs a mapping of entries to their current values
entryToValues = {}
@@ -180,11 +227,10 @@
entryToValues[entry] = entry.get(FIELD_VALUE)
optionColWidth = max(optionColWidth, len(entry.get(FIELD_OPTION)))
valueColWidth = max(valueColWidth, len(entryToValues[entry]))
- typeColWidth = max(typeColWidth, len(entry.get(FIELD_TYPE)))
optionColWidth = min(self._config["features.config.state.colWidth.option"], optionColWidth)
valueColWidth = min(self._config["features.config.state.colWidth.value"], valueColWidth)
- descriptionColWidth = max(0, width - scrollOffset - optionColWidth - valueColWidth - typeColWidth - 3)
+ descriptionColWidth = max(0, width - scrollOffset - optionColWidth - valueColWidth - 2)
for lineNum in range(scrollLoc, len(self.confContents)):
entry = self.confContents[lineNum]
@@ -200,8 +246,8 @@
#lineFormat = uiTools.getColor("green") if entry.isDefault else curses.A_BOLD | uiTools.getColor("yellow")
if entry == cursorSelection: lineFormat |= curses.A_STANDOUT
- lineTextLayout = "%%-%is %%-%is %%-%is %%-%is" % (optionColWidth, valueColWidth, typeColWidth, descriptionColWidth)
- lineText = lineTextLayout % (optionLabel, valueLabel, entry.get(FIELD_TYPE), descriptionLabel)
+ lineTextLayout = "%%-%is %%-%is %%-%is" % (optionColWidth, valueColWidth, descriptionColWidth)
+ lineText = lineTextLayout % (optionLabel, valueLabel, descriptionLabel)
self.addstr(drawLine, scrollOffset, lineText, lineFormat)
if drawLine >= height: break
Modified: arm/trunk/src/interface/controller.py
===================================================================
--- arm/trunk/src/interface/controller.py 2010-11-03 16:51:12 UTC (rev 23743)
+++ arm/trunk/src/interface/controller.py 2010-11-04 17:18:58 UTC (rev 23744)
@@ -1484,6 +1484,77 @@
if selection != -1: panels["torrc"].setConfigType(selection)
selectiveRefresh(panels, page)
+ elif page == 2 and (key == ord('s') or key == ord('S')):
+ # set ordering for config options
+ panel.CURSES_LOCK.acquire()
+ try:
+ setPauseState(panels, isPaused, page, True)
+ curses.cbreak() # wait indefinitely for key presses (no timeout)
+
+ # lists event types
+ popup = panels["popup"]
+ selections = [] # new ordering
+ cursorLoc = 0 # index of highlighted option
+
+ # listing of inital ordering
+ prevOrdering = "<b>Current Order: "
+ for sortType in panels["torrc"].sortOrdering:
+ sortStr, colorStr = configStatePanel.FIELD_ATTR[sortType]
+ prevOrdering += "<%s>%s</%s>, " % (colorStr, sortStr, colorStr)
+ prevOrdering = prevOrdering[:-2] + "</b>"
+
+ # Makes listing of all options
+ options = []
+ for sortType in range(7): options.append(configStatePanel.FIELD_ATTR[sortType][0])
+ options.append("Cancel")
+
+ while len(selections) < 3:
+ popup.clear()
+ popup.win.box()
+ popup.addstr(0, 0, "Config Option Ordering:", curses.A_STANDOUT)
+ popup.addfstr(1, 2, prevOrdering)
+
+ # provides new ordering
+ newOrdering = "<b>New Order: "
+ if selections:
+ for sortType in selections:
+ sortStr, colorStr = configStatePanel.FIELD_ATTR[sortType]
+ prevOrdering += "<%s>%s</%s>, " % (colorStr, sortStr, colorStr)
+ newOrdering = newOrdering[:-2] + "</b>"
+ else: newOrdering += "</b>"
+ popup.addfstr(2, 2, newOrdering)
+
+ row, col, index = 4, 0, 0
+ for option in options:
+ popup.addstr(row, col * 19 + 2, option, curses.A_STANDOUT if cursorLoc == index else curses.A_NORMAL)
+ col += 1
+ index += 1
+ if col == 4: row, col = row + 1, 0
+
+ popup.refresh()
+
+ key = stdscr.getch()
+ if key == curses.KEY_LEFT: cursorLoc = max(0, cursorLoc - 1)
+ elif key == curses.KEY_RIGHT: cursorLoc = min(len(options) - 1, cursorLoc + 1)
+ elif key == curses.KEY_UP: cursorLoc = max(0, cursorLoc - 4)
+ elif key == curses.KEY_DOWN: cursorLoc = min(len(options) - 1, cursorLoc + 4)
+ elif key in (curses.KEY_ENTER, 10, ord(' ')):
+ # selected entry (the ord of '10' seems needed to pick up enter)
+ selection = options[cursorLoc]
+ if selection == "Cancel": break
+ else:
+ options.remove(selection)
+ cursorLoc = min(cursorLoc, len(options) - 1)
+ elif key == 27: break # esc - cancel
+
+ if len(selections) == 3:
+ panels["torrc"].setSortOrder(selections)
+
+ setPauseState(panels, isPaused, page)
+ curses.halfdelay(REFRESH_RATE * 10) # reset normal pausing behavior
+ panels["torrc"].redraw(True)
+ finally:
+ panel.CURSES_LOCK.release()
elif page == 0:
panels["log"].handleKey(key)
elif page == 1:
Modified: arm/trunk/src/util/conf.py
===================================================================
--- arm/trunk/src/util/conf.py 2010-11-03 16:51:12 UTC (rev 23743)
+++ arm/trunk/src/util/conf.py 2010-11-04 17:18:58 UTC (rev 23744)
@@ -21,7 +21,7 @@
CONFS = {} # mapping of identifier to singleton instances of configs
CONFIG = {"log.configEntryNotFound": None,
- "log.configEntryTypeError": log.INFO}
+ "log.configEntryTypeError": log.NOTICE}
def loadConfig(config):
config.update(CONFIG)