[tor-commits] [arm/release] Binding handlers for the log submenu
atagar at torproject.org
atagar at torproject.org
Sun Jul 17 06:08:24 UTC 2011
commit 62c76582c3816e58f1108ffd095ca8aae92105fb
Author: Damian Johnson <atagar at torproject.org>
Date: Sun Jun 12 13:18:36 2011 -0700
Binding handlers for the log submenu
---
src/cli/controller.py | 19 ++++-
src/cli/graphing/graphPanel.py | 11 +---
src/cli/logPanel.py | 160 +++++++++++++++++++++++++++-------------
src/cli/menu/actions.py | 56 +++++++++++----
src/cli/menu/menu.py | 4 +-
5 files changed, 168 insertions(+), 82 deletions(-)
diff --git a/src/cli/controller.py b/src/cli/controller.py
index cf17da3..6158ade 100644
--- a/src/cli/controller.py
+++ b/src/cli/controller.py
@@ -288,12 +288,27 @@ class Controller:
return allPanels
- def requestRedraw(self):
+ def requestRedraw(self, immediate = False):
"""
Requests that all content is redrawn when the interface is next rendered.
+
+ Arguments:
+ immediate - redraws now if true, otherwise waits for when next normally
+ drawn
"""
- self._forceRedraw = True
+ if immediate:
+ displayPanels = self.getDisplayPanels()
+
+ occupiedContent = 0
+ for panelImpl in displayPanels:
+ panelImpl.setTop(occupiedContent)
+ occupiedContent += panelImpl.getHeight()
+
+ for panelImpl in displayPanels:
+ panelImpl.redraw(True)
+ else:
+ self._forceRedraw = True
def isRedrawRequested(self, clearFlag = False):
"""
diff --git a/src/cli/graphing/graphPanel.py b/src/cli/graphing/graphPanel.py
index 69b9121..8c3adf7 100644
--- a/src/cli/graphing/graphPanel.py
+++ b/src/cli/graphing/graphPanel.py
@@ -307,16 +307,7 @@ class GraphPanel(panel.Panel):
panel.CURSES_LOCK.acquire()
try:
while True:
- # redraws the resized panels
- displayPanels = control.getDisplayPanels()
-
- occupiedContent = 0
- for panelImpl in displayPanels:
- panelImpl.setTop(occupiedContent)
- occupiedContent += panelImpl.getHeight()
-
- for panelImpl in displayPanels:
- panelImpl.redraw(True)
+ control.requestRedraw(True)
msg = "press the down/up to resize the graph, and enter when done"
control.setMsg(msg, curses.A_BOLD, True)
diff --git a/src/cli/logPanel.py b/src/cli/logPanel.py
index 6d54ab4..ef372ab 100644
--- a/src/cli/logPanel.py
+++ b/src/cli/logPanel.py
@@ -13,6 +13,7 @@ import threading
from TorCtl import TorCtl
import popups
+import cli.controller
from version import VERSION
from util import conf, log, panel, sysTools, torTools, uiTools
@@ -668,6 +669,17 @@ class LogPanel(panel.Panel, threading.Thread):
log.log(self._config["log.logPanel.logFileWriteFailed"], "Unable to write to log file: %s" % sysTools.getFileErrorMsg(exc))
self.logFile = None
+ def setDuplicateVisability(self, isVisible):
+ """
+ Sets if duplicate log entries are collaped or expanded.
+
+ Arguments:
+ isVisible - if true all log entries are shown, otherwise they're
+ deduplicated
+ """
+
+ self.showDuplicates = isVisible
+
def registerEvent(self, event):
"""
Notes event and redraws log. If paused it's held in a temporary buffer.
@@ -728,6 +740,13 @@ class LogPanel(panel.Panel, threading.Thread):
self.redraw(True)
self.valsLock.release()
+ def getFilter(self):
+ """
+ Provides our currently selected regex filter.
+ """
+
+ return self.filterOptions[0] if self.regexFilter else None
+
def setFilter(self, logFilter):
"""
Filters log entries according to the given regular expression.
@@ -744,6 +763,90 @@ class LogPanel(panel.Panel, threading.Thread):
self.redraw(True)
self.valsLock.release()
+ def makeFilterSelection(self, selectedOption):
+ """
+ Makes the given filter selection, applying it to the log and reorganizing
+ our filter selection.
+
+ Arguments:
+ selectedOption - regex filter we've already added, None if no filter
+ should be applied
+ """
+
+ if selectedOption:
+ try:
+ self.setFilter(re.compile(selectedOption))
+
+ # move selection to top
+ self.filterOptions.remove(selectedOption)
+ self.filterOptions.insert(0, selectedOption)
+ except re.error, exc:
+ # shouldn't happen since we've already checked validity
+ msg = "Invalid regular expression ('%s': %s) - removing from listing" % (selectedOption, exc)
+ log.log(log.WARN, msg)
+ self.filterOptions.remove(selectedOption)
+ else: self.setFilter(None)
+
+ def showFilterPrompt(self):
+ """
+ Prompts the user to add a new regex filter.
+ """
+
+ cli.controller.getController().requestRedraw(True)
+ regexInput = popups.inputPrompt("Regular expression: ")
+
+ if regexInput:
+ try:
+ self.setFilter(re.compile(regexInput))
+ if regexInput in self.filterOptions: self.filterOptions.remove(regexInput)
+ self.filterOptions.insert(0, regexInput)
+ except re.error, exc:
+ popups.showMsg("Unable to compile expression: %s" % exc, 2)
+
+ def showEventSelectionPrompt(self):
+ """
+ Prompts the user to select the events being listened for.
+ """
+
+ # allow user to enter new types of events to log - unchanged if left blank
+ cli.controller.getController().requestRedraw(True)
+ popup, width, height = popups.init(11, 80)
+
+ if popup:
+ try:
+ # displays the available flags
+ popup.win.box()
+ popup.addstr(0, 0, "Event Types:", curses.A_STANDOUT)
+ eventLines = EVENT_LISTING.split("\n")
+
+ for i in range(len(eventLines)):
+ popup.addstr(i + 1, 1, eventLines[i][6:])
+
+ popup.win.refresh()
+
+ userInput = popups.inputPrompt("Events to log: ")
+ if userInput:
+ userInput = userInput.replace(' ', '') # strips spaces
+ try: self.setLoggedEvents(expandEvents(userInput))
+ except ValueError, exc:
+ popups.showMsg("Invalid flags: %s" % str(exc), 2)
+ finally: popups.finalize()
+
+ def showSnapshotPrompt(self):
+ """
+ Lets user enter a path to take a snapshot, canceling if left blank.
+ """
+
+ cli.controller.getController().requestRedraw(True)
+ pathInput = popups.inputPrompt("Path to save log snapshot: ")
+
+ if pathInput:
+ try:
+ self.saveSnapshot(pathInput)
+ popups.showMsg("Saved: %s" % pathInput, 2)
+ except IOError, exc:
+ popups.showMsg("Unable to save snapshot: %s" % sysTools.getFileErrorMsg(exc), 2)
+
def clear(self):
"""
Clears the contents of the event log.
@@ -817,66 +920,17 @@ class LogPanel(panel.Panel, threading.Thread):
self.setFilter(None)
elif selection == len(options) - 1:
# selected 'New...' option - prompt user to input regular expression
- regexInput = popups.inputPrompt("Regular expression: ")
-
- if regexInput:
- try:
- self.setFilter(re.compile(regexInput))
- if regexInput in self.filterOptions: self.filterOptions.remove(regexInput)
- self.filterOptions.insert(0, regexInput)
- except re.error, exc:
- popups.showMsg("Unable to compile expression: %s" % exc, 2)
+ self.showFilterPrompt()
elif selection != -1:
- selectedOption = self.filterOptions[selection - 1]
-
- try:
- self.setFilter(re.compile(selectedOption))
-
- # move selection to top
- self.filterOptions.remove(selectedOption)
- self.filterOptions.insert(0, selectedOption)
- except re.error, exc:
- # shouldn't happen since we've already checked validity
- msg = "Invalid regular expression ('%s': %s) - removing from listing" % (selectedOption, exc)
- log.log(log.WARN, msg)
- self.filterOptions.remove(selectedOption)
+ self.makeFilterSelection(self.filterOptions[selection - 1])
finally:
panel.CURSES_LOCK.release()
if len(self.filterOptions) > MAX_REGEX_FILTERS: del self.filterOptions[MAX_REGEX_FILTERS:]
elif key == ord('e') or key == ord('E'):
- # allow user to enter new types of events to log - unchanged if left blank
- popup, width, height = popups.init(11, 80)
-
- if popup:
- try:
- # displays the available flags
- popup.win.box()
- popup.addstr(0, 0, "Event Types:", curses.A_STANDOUT)
- eventLines = EVENT_LISTING.split("\n")
-
- for i in range(len(eventLines)):
- popup.addstr(i + 1, 1, eventLines[i][6:])
-
- popup.win.refresh()
-
- userInput = popups.inputPrompt("Events to log: ")
- if userInput:
- userInput = userInput.replace(' ', '') # strips spaces
- try: self.setLoggedEvents(expandEvents(userInput))
- except ValueError, exc:
- popups.showMsg("Invalid flags: %s" % str(exc), 2)
- finally: popups.finalize()
+ self.showEventSelectionPrompt()
elif key == ord('a') or key == ord('A'):
- # lets user enter a path to take a snapshot, canceling if left blank
- pathInput = popups.inputPrompt("Path to save log snapshot: ")
-
- if pathInput:
- try:
- self.saveSnapshot(pathInput)
- popups.showMsg("Saved: %s" % pathInput, 2)
- except IOError, exc:
- popups.showMsg("Unable to save snapshot: %s" % sysTools.getFileErrorMsg(exc), 2)
+ self.showSnapshotPrompt()
else: isKeystrokeConsumed = False
return isKeystrokeConsumed
diff --git a/src/cli/menu/actions.py b/src/cli/menu/actions.py
index 9d69cb4..c8b8da3 100644
--- a/src/cli/menu/actions.py
+++ b/src/cli/menu/actions.py
@@ -24,18 +24,8 @@ def makeMenu():
for pagePanel in control.getDisplayPanels(includeSticky = False):
if pagePanel.getName() == "graph":
baseMenu.add(makeGraphMenu(pagePanel))
-
- logsMenu = cli.menu.item.Submenu("Logs")
- logsMenu.add(cli.menu.item.MenuItem("Events", None))
- logsMenu.add(cli.menu.item.MenuItem("Clear", None))
- logsMenu.add(cli.menu.item.MenuItem("Save", None))
- logsMenu.add(cli.menu.item.MenuItem("Filter", None))
-
- duplicatesSubmenu = cli.menu.item.Submenu("Duplicates")
- duplicatesSubmenu.add(cli.menu.item.MenuItem("Hidden", None))
- duplicatesSubmenu.add(cli.menu.item.MenuItem("Visible", None))
- logsMenu.add(duplicatesSubmenu)
- baseMenu.add(logsMenu)
+ elif pagePanel.getName() == "log":
+ baseMenu.add(makeLogMenu(pagePanel))
connectionsMenu = cli.menu.item.Submenu("Connections")
connectionsMenu.add(cli.menu.item.MenuItem("Identity", None))
@@ -117,7 +107,7 @@ def makeGraphMenu(graphPanel):
[X] <Stat 1>
[ ] <Stat 2>
[ ] <Stat 2>
- Resize
+ Resize...
Interval (Submenu)
Bounds (Submenu)
@@ -138,7 +128,7 @@ def makeGraphMenu(graphPanel):
graphMenu.add(cli.menu.item.SelectionMenuItem(label, statGroup, statKey))
# resizing option
- graphMenu.add(cli.menu.item.MenuItem("Resize", graphPanel.resizeGraph))
+ graphMenu.add(cli.menu.item.MenuItem("Resize...", graphPanel.resizeGraph))
# interval submenu
intervalMenu = cli.menu.item.Submenu("Interval")
@@ -162,3 +152,41 @@ def makeGraphMenu(graphPanel):
return graphMenu
+def makeLogMenu(logPanel):
+ """
+ Submenu for the log panel, consisting of...
+ Events...
+ Snapshot...
+ Clear
+ Show / Hide Duplicates
+ Filter (Submenu)
+
+ Arguments:
+ logPanel - instance of the log panel
+ """
+
+ logMenu = cli.menu.item.Submenu("Log")
+
+ logMenu.add(cli.menu.item.MenuItem("Events...", logPanel.showEventSelectionPrompt))
+ logMenu.add(cli.menu.item.MenuItem("Snapshot...", logPanel.showSnapshotPrompt))
+ logMenu.add(cli.menu.item.MenuItem("Clear", logPanel.clear))
+
+ if logPanel.showDuplicates: label, arg = "Hide", False
+ else: label, arg = "Show", True
+ logMenu.add(cli.menu.item.MenuItem("%s Duplicates" % label, functools.partial(logPanel.setDuplicateVisability, arg)))
+
+ # filter submenu
+ filterMenu = cli.menu.item.Submenu("Filter")
+ filterGroup = cli.menu.item.SelectionGroup(logPanel.makeFilterSelection, logPanel.getFilter())
+
+ filterMenu.add(cli.menu.item.SelectionMenuItem("None", filterGroup, None))
+
+ for option in logPanel.filterOptions:
+ filterMenu.add(cli.menu.item.SelectionMenuItem(option, filterGroup, option))
+
+ filterMenu.add(cli.menu.item.MenuItem("New...", logPanel.showFilterPrompt))
+ logMenu.add(filterMenu)
+
+ return logMenu
+
+
diff --git a/src/cli/menu/menu.py b/src/cli/menu/menu.py
index e0728e8..b411a9c 100644
--- a/src/cli/menu/menu.py
+++ b/src/cli/menu/menu.py
@@ -110,9 +110,7 @@ def showMenu():
cursor.handleKey(key)
# redraws the rest of the interface if we're rendering on it again
- if not cursor.isDone():
- for panelImpl in control.getDisplayPanels():
- panelImpl.redraw(True)
+ if not cursor.isDone(): control.requestRedraw(True)
finally:
control.setMsg()
cli.popups.finalize()
More information about the tor-commits
mailing list