[or-cvs] r23862: {arm} Adding popup for saving custom tor configurations. (in arm/trunk/src: interface util)
Damian Johnson
atagar1 at gmail.com
Sat Nov 27 07:46:34 UTC 2010
Author: atagar
Date: 2010-11-27 07:46:34 +0000 (Sat, 27 Nov 2010)
New Revision: 23862
Modified:
arm/trunk/src/interface/configStatePanel.py
arm/trunk/src/interface/controller.py
arm/trunk/src/util/panel.py
Log:
Adding popup for saving custom tor configurations.
Modified: arm/trunk/src/interface/configStatePanel.py
===================================================================
--- arm/trunk/src/interface/configStatePanel.py 2010-11-26 08:16:32 UTC (rev 23861)
+++ arm/trunk/src/interface/configStatePanel.py 2010-11-27 07:46:34 UTC (rev 23862)
@@ -275,17 +275,17 @@
# border (top)
if width >= len(titleLabel):
self.win.hline(0, len(titleLabel), curses.ACS_HLINE, width - len(titleLabel))
- self.win.vline(0, width, curses.ACS_URCORNER, 1)
+ self.win.addch(0, width, curses.ACS_URCORNER)
# border (sides)
self.win.vline(1, 0, curses.ACS_VLINE, detailPanelHeight - 1)
self.win.vline(1, width, curses.ACS_VLINE, detailPanelHeight - 1)
# border (bottom)
- self.win.vline(detailPanelHeight, 0, curses.ACS_LLCORNER, 1)
- if width >= 2: self.win.vline(detailPanelHeight, 1, curses.ACS_TTEE, 1)
+ self.win.addch(detailPanelHeight, 0, curses.ACS_LLCORNER)
+ if width >= 2: self.win.addch(detailPanelHeight, 1, curses.ACS_TTEE)
if width >= 3: self.win.hline(detailPanelHeight, 2, curses.ACS_HLINE, width - 2)
- self.win.vline(detailPanelHeight, width, curses.ACS_LRCORNER, 1)
+ self.win.addch(detailPanelHeight, width, curses.ACS_LRCORNER)
selectionFormat = curses.A_BOLD | uiTools.getColor(CATEGORY_COLOR[cursorSelection.get(FIELD_CATEGORY)])
Modified: arm/trunk/src/interface/controller.py
===================================================================
--- arm/trunk/src/interface/controller.py 2010-11-26 08:16:32 UTC (rev 23861)
+++ arm/trunk/src/interface/controller.py 2010-11-27 07:46:34 UTC (rev 23862)
@@ -6,6 +6,7 @@
Curses (terminal) interface for the arm relay status monitor.
"""
+import os
import re
import math
import time
@@ -841,7 +842,8 @@
popup.addfstr(2, 41, "<b>page down</b>: scroll down a page")
popup.addfstr(3, 2, "<b>enter</b>: edit configuration option")
- popup.addfstr(3, 41, "<b>s</b>: sort ordering")
+ popup.addfstr(3, 41, "<b>w</b>: save current configuration")
+ popup.addfstr(4, 2, "<b>s</b>: sort ordering")
elif page == 3:
popup.addfstr(1, 2, "<b>up arrow</b>: scroll up a line")
popup.addfstr(1, 41, "<b>down arrow</b>: scroll down a line")
@@ -966,7 +968,7 @@
# gets user input (this blocks monitor updates)
pathInput = panels["control"].getstr(0, 27)
- if pathInput != "":
+ if pathInput:
try:
panels["log"].saveSnapshot(pathInput)
panels["control"].setMsg("Saved: %s" % pathInput, curses.A_STANDOUT)
@@ -1010,10 +1012,10 @@
# gets user input (this blocks monitor updates)
eventsInput = panels["control"].getstr(0, 15)
- eventsInput = eventsInput.replace(' ', '') # strips spaces
+ if eventsInput: eventsInput = eventsInput.replace(' ', '') # strips spaces
# it would be nice to quit on esc, but looks like this might not be possible...
- if eventsInput != "":
+ if eventsInput:
try:
expandedEvents = logPanel.expandEvents(eventsInput)
loggedEvents = setEventListening(expandedEvents, isBlindMode)
@@ -1061,7 +1063,7 @@
# gets user input (this blocks monitor updates)
regexInput = panels["control"].getstr(0, 20)
- if regexInput != "":
+ if regexInput:
try:
panels["log"].setFilter(re.compile(regexInput))
if regexInput in regexFilters: regexFilters.remove(regexInput)
@@ -1447,6 +1449,136 @@
if selection != -1: panels["torrc"].setConfigType(selection)
selectiveRefresh(panels, page)
+ elif page == 2 and (key == ord('w') or key == ord('W')):
+ # display a popup for saving the current configuration
+ panel.CURSES_LOCK.acquire()
+ try:
+ configText = torTools.getConn().getInfo("config-text", "").strip()
+ configLines = configText.split("\n")
+
+ # lists event types
+ popup = panels["popup"]
+ popup.height = len(configLines) + 3
+ popup.recreate(stdscr)
+ displayHeight, displayWidth = panels["popup"].getPreferredSize()
+
+ # displayed options (truncating the labels if there's limited room)
+ if displayWidth >= 30: selectionOptions = ("Save", "Save As...", "Cancel")
+ else: selectionOptions = ("Save", "Save As", "X")
+
+ # checks if we can show options beside the last line of visible content
+ lastIndex = min(displayHeight - 3, len(configLines) - 1)
+ isOptionLineSeparate = displayWidth < (30 + len(configLines[lastIndex]))
+
+ # if we're showing all the content and have room to display selection
+ # options besides the text then shrink the popup by a row
+ if not isOptionLineSeparate and displayHeight == len(configLines) + 3:
+ popup.height -= 1
+ popup.recreate(stdscr)
+
+ key, selection = 0, 2
+ while key not in (curses.KEY_ENTER, 10, ord(' ')):
+ # if the popup has been resized then recreate it (needed for the
+ # proper border height)
+ newHeight, newWidth = panels["popup"].getPreferredSize()
+ if (displayHeight, displayWidth) != (newHeight, newWidth):
+ displayHeight, displayWidth = newHeight, newWidth
+ popup.recreate(stdscr)
+
+ # if there isn't room to display the popup then cancel it
+ if displayHeight <= 2:
+ selection = 2
+ break
+
+ popup.clear()
+ popup.win.box()
+ popup.addstr(0, 0, "Configuration being saved:", curses.A_STANDOUT)
+
+ visibleConfigLines = displayHeight - 3 if isOptionLineSeparate else displayHeight - 2
+ for i in range(visibleConfigLines):
+ line = uiTools.cropStr(configLines[i], displayWidth - 2)
+
+ if " " in line:
+ option, arg = line.split(" ", 1)
+ popup.addstr(i + 1, 1, option, curses.A_BOLD | uiTools.getColor("green"))
+ popup.addstr(i + 1, len(option) + 2, arg, curses.A_BOLD | uiTools.getColor("cyan"))
+ else:
+ popup.addstr(i + 1, 1, line, curses.A_BOLD | uiTools.getColor("green"))
+
+ # draws 'T' between the lower left and the covered panel's scroll bar
+ if displayWidth > 1: popup.win.addch(displayHeight - 1, 1, curses.ACS_TTEE)
+
+ # draws selection options (drawn right to left)
+ drawX = displayWidth - 1
+ for i in range(len(selectionOptions) - 1, -1, -1):
+ optionLabel = selectionOptions[i]
+ drawX -= (len(optionLabel) + 2)
+
+ # if we've run out of room then drop the option (this will only
+ # occure on tiny displays)
+ if drawX < 1: break
+
+ selectionFormat = curses.A_STANDOUT if i == selection else curses.A_NORMAL
+ popup.addstr(displayHeight - 2, drawX, "[")
+ popup.addstr(displayHeight - 2, drawX + 1, optionLabel, selectionFormat | curses.A_BOLD)
+ popup.addstr(displayHeight - 2, drawX + len(optionLabel) + 1, "]")
+
+ drawX -= 1 # space gap between the options
+
+ popup.refresh()
+
+ key = stdscr.getch()
+ if key == curses.KEY_LEFT: selection = max(0, selection - 1)
+ elif key == curses.KEY_RIGHT: selection = min(len(selectionOptions) - 1, selection + 1)
+
+ if selection in (0, 1):
+ loadedTorrc = torConfig.getTorrc()
+ try: configLocation = loadedTorrc.getConfigLocation()
+ except IOError: configLocation = ""
+
+ if selection == 1:
+ # prompts user for a configuration location
+ promptMsg = "Save to (esc to cancel): "
+ panels["control"].setMsg(promptMsg)
+ panels["control"].redraw(True)
+ configLocation = panels["control"].getstr(0, len(promptMsg), configLocation)
+ if configLocation: configLocation = os.path.abspath(configLocation)
+
+ if configLocation:
+ try:
+ # make dir if the path doesn't already exist
+ baseDir = os.path.dirname(configLocation)
+ if not os.path.exists(baseDir): os.makedirs(baseDir)
+
+ # saves the configuration to the file
+ configFile = open(configLocation, "w")
+ configFile.write(configText)
+ configFile.close()
+
+ # reloads the cached torrc if overwriting it
+ if configLocation == loadedTorrc.getConfigLocation():
+ try:
+ loadedTorrc.load()
+ panels["torrc"]._lastContentHeightArgs = None
+ except IOError: pass
+
+ msg = "Saved configuration to %s" % configLocation
+ except (IOError, OSError), exc:
+ msg = "Unable to save configuration (%s)" % sysTools.getFileErrorMsg(exc)
+
+ panels["control"].setMsg(msg, curses.A_STANDOUT)
+ panels["control"].redraw(True)
+ time.sleep(2)
+
+ panels["control"].setMsg(CTL_PAUSED if isPaused else CTL_HELP)
+
+ # reverts popup dimensions
+ popup.height = 9
+ popup.recreate(stdscr, 80)
+ finally:
+ panel.CURSES_LOCK.release()
+
+ panels["config"].redraw(True)
elif page == 2 and (key == ord('s') or key == ord('S')):
# set ordering for config options
titleLabel = "Config Option Ordering:"
@@ -1492,7 +1624,7 @@
newConfigValue = panels["control"].getstr(0, len(titleMsg), initialText)
# it would be nice to quit on esc, but looks like this might not be possible...
- if newConfigValue != initialValue:
+ if newConfigValue != None and newConfigValue != initialValue:
conn = torTools.getConn()
# if the value's a boolean then allow for 'true' and 'false' inputs
Modified: arm/trunk/src/util/panel.py
===================================================================
--- arm/trunk/src/util/panel.py 2010-11-26 08:16:32 UTC (rev 23861)
+++ arm/trunk/src/util/panel.py 2010-11-27 07:46:34 UTC (rev 23862)
@@ -336,8 +336,8 @@
"""
Provides a text field where the user can input a string, blocking until
they've done so and returning the result. If the user presses escape then
- this terminates and provides back the initial value. This should only be
- called from the context of a panel's draw method.
+ this terminates and provides back None. This should only be called from
+ the context of a panel's draw method.
Arguments:
y - vertical location
@@ -360,14 +360,14 @@
# text panel and returns userInput to the initial text if the user presses
# escape.
textbox = curses.textpad.Textbox(inputSubwindow, True)
- userInput = textbox.edit(lambda key: _textboxValidate(textbox, key))
- if textbox.lastcmd == curses.ascii.BEL: userInput = initialText
+ userInput = textbox.edit(lambda key: _textboxValidate(textbox, key)).strip()
+ if textbox.lastcmd == curses.ascii.BEL: userInput = None
# reverts visability settings
try: curses.curs_set(previousCursorState)
except curses.error: pass
- return userInput.strip()
+ return userInput
def addScrollBar(self, top, bottom, size, drawTop = 0, drawBottom = -1):
"""
@@ -490,7 +490,7 @@
elif key == curses.KEY_RIGHT and x >= msgLen - 1:
# don't move the cursor if there's no content after it
return None
- elif key == -1:
+ elif key == 410:
# if we're resizing the display during text entry then cancel it
# (otherwise the input field is filled with nonprintable characters)
return curses.ascii.BEL
More information about the tor-commits
mailing list