commit 2a6916e1fbcc6fc6a60563e969d0ddc448ece1fd Author: Kamran Riaz Khan krkhan@inspirated.com Date: Tue May 31 14:02:49 2011 +0500
Mapped menu items to respective actions.
There are three kinds of menu items: * The ones which are directly mapped to a panel action via Menu._callbackPressKey() * "State-ful" menu items which are enabled/disabled depending on their panel's states. These are taken care of via the Menu._callbackGetEnabled() and Menu._callbackSet() methods. For example, the "Duplicates" submenu in "Logs" changes its state depending on log.showDuplicates. * View menu items, which change controller state. Supported via Menu._callbackView()
Launching a panel action switches view to that panel, e.g., if we're on configuration panel and graph bounds are changed the controller is traversed through pages until one with graph panel is found. Otherwise, an error is logged.
File->Exit and Configuration->Reset Tor items are unimplemented as of yet. Possible approaches include factoring out a handleKey() in controller or duplicating the same code in callbacks. --- src/cli/menu.py | 198 +++++++++++++++++++++++++++++++++++--------------- src/util/menuItem.py | 11 +++- 2 files changed, 149 insertions(+), 60 deletions(-)
diff --git a/src/cli/menu.py b/src/cli/menu.py index 5a51797..9aadf8d 100644 --- a/src/cli/menu.py +++ b/src/cli/menu.py @@ -6,6 +6,8 @@ import curses
import cli.controller import popups + +from cli.graphing.graphPanel import Bounds as GraphBounds from util import log, panel, uiTools, menuItem
PARENTLEVEL, TOPLEVEL = (-1, 0) @@ -15,70 +17,78 @@ class Menu():
def __init__(self, item=None): DEFAULT_ROOT = menuItem.MenuItem(label="Root", children=( - menuItem.MenuItem(label="File" , children=( - menuItem.MenuItem(label="Exit" , callback=self._callbackDefault),)), - menuItem.MenuItem(label="Logs" , children=( - menuItem.MenuItem(label="Events" , callback=self._callbackDefault), - menuItem.MenuItem(label="Clear" , callback=self._callbackDefault), - menuItem.MenuItem(label="Save" , callback=self._callbackDefault), - menuItem.MenuItem(label="Filter" , callback=self._callbackDefault), - menuItem.MenuItem(label="Duplicates" , children=( - menuItem.MenuItem(label="Hidden" , callback=self._callbackDefault), - menuItem.MenuItem(label="Visible" , callback=self._callbackDefault),)) - )), - menuItem.MenuItem(label="View" , children=( - menuItem.MenuItem(label="Graph" , callback=self._callbackDefault), - menuItem.MenuItem(label="Connections" , callback=self._callbackDefault), - menuItem.MenuItem(label="Configuration" , callback=self._callbackDefault), - menuItem.MenuItem(label="Configuration File" , callback=self._callbackDefault),)), - menuItem.MenuItem(label="Graph" , children=( - menuItem.MenuItem(label="Stats" , children=( - menuItem.MenuItem(label="Bandwidth" , callback=self._callbackDefault), - menuItem.MenuItem(label="Connections" , callback=self._callbackDefault), - menuItem.MenuItem(label="Resources" , callback=self._callbackDefault), - )), - menuItem.MenuItem(label="Size" , children=( - menuItem.MenuItem(label="Increase" , callback=self._callbackDefault), - menuItem.MenuItem(label="Decrease" , callback=self._callbackDefault), - )), - menuItem.MenuItem(label="Update Interval" , children=( - menuItem.MenuItem(label="Each second" , callback=self._callbackDefault), - menuItem.MenuItem(label="5 seconds" , callback=self._callbackDefault), - menuItem.MenuItem(label="30 seconds" , callback=self._callbackDefault), - menuItem.MenuItem(label="1 minute" , callback=self._callbackDefault), - menuItem.MenuItem(label="30 minutes" , callback=self._callbackDefault), - menuItem.MenuItem(label="Hourly" , callback=self._callbackDefault), - menuItem.MenuItem(label="Daily" , callback=self._callbackDefault), + menuItem.MenuItem(label="File", children=( + menuItem.MenuItem(label="Exit", + callback=self._callbackDefault),)), + menuItem.MenuItem(label="Logs", children=( + menuItem.MenuItem(label="Events", + callback=lambda item: self._callbackPressKey('log', ord('e'))), + menuItem.MenuItem(label="Clear", + callback=lambda item: self._callbackPressKey('log', ord('c'))), + menuItem.MenuItem(label="Save", + callback=lambda item: self._callbackPressKey('log', ord('a'))), + menuItem.MenuItem(label="Filter", + callback=lambda item: self._callbackPressKey('log', ord('f'))), + menuItem.MenuItem(label="Duplicates", children=( + menuItem.MenuItem(label="Hidden", + callback=lambda item: self._callbackSet('log', 'showDuplicates', False, ord('u')), + enabled=lambda: self._getItemEnabled('log', 'showDuplicates', False)), + menuItem.MenuItem(label="Visible", + callback=lambda item: self._callbackSet('log', 'showDuplicates', True, ord('u')), + enabled=lambda: self._getItemEnabled('log', 'showDuplicates', True)), + )))), + menuItem.MenuItem(label="View", children=( + menuItem.MenuItem(label="Graph", + callback=lambda item: self._callbackView('graph')), + menuItem.MenuItem(label="Connections", + callback=lambda item: self._callbackView('conn')), + menuItem.MenuItem(label="Configuration", + callback=lambda item: self._callbackView('configState')), + menuItem.MenuItem(label="Configuration File", + callback=lambda item: self._callbackView('configFile')),)), + menuItem.MenuItem(label="Graph", children=( + menuItem.MenuItem(label="Stats", + callback=lambda item: self._callbackPressKey('graph', ord('s'))), + menuItem.MenuItem(label="Size", children=( + menuItem.MenuItem(label="Increase", + callback=lambda item: self._callbackPressKey('graph', ord('m'))), + menuItem.MenuItem(label="Decrease", + callback=lambda item: self._callbackPressKey('graph', ord('n'))), )), - menuItem.MenuItem(label="Bounds" , children=( - menuItem.MenuItem(label="Local Max" , callback=self._callbackDefault), - menuItem.MenuItem(label="Global Max" , callback=self._callbackDefault), - menuItem.MenuItem(label="Tight" , callback=self._callbackDefault), + menuItem.MenuItem(label="Update Interval", + callback=lambda item: self._callbackPressKey('graph', ord('i'))), + menuItem.MenuItem(label="Bounds", children=( + menuItem.MenuItem(label="Local Max", + callback=lambda item: self._callbackSet('graph', 'bounds', GraphBounds.LOCAL_MAX, ord('b')), + enabled=lambda: self._getItemEnabled('graph', 'bounds', GraphBounds.LOCAL_MAX)), + menuItem.MenuItem(label="Global Max", + callback=lambda item: self._callbackSet('graph', 'bounds', GraphBounds.GLOBAL_MAX, ord('b')), + enabled=lambda: self._getItemEnabled('graph', 'bounds', GraphBounds.GLOBAL_MAX)), + menuItem.MenuItem(label="Tight", + callback=lambda item: self._callbackSet('graph', 'bounds', GraphBounds.TIGHT, ord('b')), + enabled=lambda: self._getItemEnabled('graph', 'bounds', GraphBounds.TIGHT)), )),)), - menuItem.MenuItem(label="Connections" , children=( - menuItem.MenuItem(label="Identity" , children=( - menuItem.MenuItem(label="IP" , callback=self._callbackDefault), - menuItem.MenuItem(label="Fingerprints" , callback=self._callbackDefault), - menuItem.MenuItem(label="Nicknames" , callback=self._callbackDefault), + menuItem.MenuItem(label="Connections", children=( + menuItem.MenuItem(label="Identity", + callback=lambda item: self._callbackPressKey('conn', ord('l'))), + menuItem.MenuItem(label="Resolver", + callback=lambda item: self._callbackPressKey('conn', ord('u'))), + menuItem.MenuItem(label="Sort Order", + callback=lambda item: self._callbackPressKey('conn', ord('s'))), )), - menuItem.MenuItem(label="Resolver" , children=( - menuItem.MenuItem(label="auto" , callback=self._callbackDefault), - menuItem.MenuItem(label="proc" , callback=self._callbackDefault), - menuItem.MenuItem(label="netstat" , callback=self._callbackDefault), - menuItem.MenuItem(label="ss" , callback=self._callbackDefault), - menuItem.MenuItem(label="lsof" , callback=self._callbackDefault), - menuItem.MenuItem(label="sockstat" , callback=self._callbackDefault), - menuItem.MenuItem(label="sockstat (bsd)" , callback=self._callbackDefault), - menuItem.MenuItem(label="procstat (bsd)" , callback=self._callbackDefault), - )), - menuItem.MenuItem(label="Sort Order" , callback=self._callbackDefault),)), menuItem.MenuItem(label="Configuration" , children=( - menuItem.MenuItem(label="Comments" , children=( - menuItem.MenuItem(label="Hidden" , callback=self._callbackDefault), - menuItem.MenuItem(label="Visible" , callback=self._callbackDefault), + menuItem.MenuItem(label="Comments", children=( + menuItem.MenuItem(label="Hidden", + callback=lambda item: self._callbackSet('configFile', 'stripComments', True, ord('s')), + enabled=lambda: self._getItemEnabled('configFile', 'stripComments', True)), + menuItem.MenuItem(label="Visible", + callback=lambda item: self._callbackSet('configFile', 'stripComments', False, ord('s')), + enabled=lambda: self._getItemEnabled('configFile', 'stripComments', False)), )), - menuItem.MenuItem(label="Reload" , callback=self._callbackDefault), - menuItem.MenuItem(label="Reset Tor" , callback=self._callbackDefault),)) + menuItem.MenuItem(label="Reload", + callback=lambda item: self._callbackPressKey('configFile', ord('r'))), + menuItem.MenuItem(label="Reset Tor", + callback=self._callbackDefault),)) ))
self._first = [0] @@ -111,6 +121,8 @@ class Menu(): elif key == curses.KEY_DOWN: self._showNLevel() break + elif key == 27: + break elif uiTools.isSelectionKey(key): self._handleEvent() break @@ -238,6 +250,9 @@ class Menu():
popup, width, height = popups.init(height=printable+2, width=labelwidth+2, top=2, left=left)
+ while self._getCurrentItem().isEnabled() == False: + self._moveNLevelDown(height) + if popup.win: try: while True: @@ -258,6 +273,10 @@ class Menu(): elif key == curses.KEY_RIGHT: self._showNLevel() break + elif key == 27: + self._first.pop() + self._selection.pop() + break elif uiTools.isSelectionKey(key): self._handleEvent() self._first.pop() @@ -277,6 +296,9 @@ class Menu(): for (index, item) in enumerate(children): labelformat = curses.A_STANDOUT if index == self._selection[PARENTLEVEL] else curses.A_NORMAL
+ if not item.isEnabled(): + labelformat = labelformat | uiTools.getColor('yellow') + popup.addstr(top, left, item.getLabel(), labelformat) top = top + 1
@@ -295,6 +317,9 @@ class Menu(): self._first[PARENTLEVEL] = 0 self._selection[PARENTLEVEL] = 0
+ while self._getCurrentItem().isEnabled() == False: + self._moveNLevelDown(height) + def _moveNLevelUp(self, height): printable = self._calculateNLevelHeights(level=PARENTLEVEL) parent = self._getCurrentItem(level=PARENTLEVEL) @@ -311,6 +336,9 @@ class Menu(): if self._selection[PARENTLEVEL] > printable: self._selection[PARENTLEVEL] = printable - 1
+ while self._getCurrentItem().isEnabled() == False: + self._moveNLevelUp(height) + def _handleEvent(self): item = self._getCurrentItem()
@@ -322,3 +350,55 @@ class Menu(): def _callbackDefault(self, item): log.log(log.NOTICE, "%s selected" % item.getLabel())
+ def _callbackView(self, panelname): + control = cli.controller.getController() + + start = control.getPage() + panels = control.getDisplayPanels(includeSticky=False) + panelnames = [panel.getName() for panel in panels] + while not panelname in panelnames: + control.nextPage() + panels = control.getDisplayPanels(includeSticky=False) + panelnames = [panel.getName() for panel in panels] + + if control.getPage() == start: + log.log(log.ERR, "Panel %s not found" % panelname) + break + + def _getItemEnabled(self, panel, attr, value): + control = cli.controller.getController() + if control: + panel = control.getPanel(panel) + + if panel: + return getattr(panel, attr, None) != value + + return False + + def _callbackSet(self, panel, attr, value, key=None): + self._callbackView(panel) + + control = cli.controller.getController() + panel = control.getPanel(panel) + + panelattr = getattr(panel, attr, None) + + if panelattr != None: + if hasattr(panelattr, '__call__'): + panelattr(value) + elif panelattr != value and key != None: + start = panelattr + while panelattr != value: + panel.handleKey(key) + panelattr = getattr(panel, attr, None) + if panelattr == start: + log.log(log.ERR, "Could not set %s.%s" % (panel, attr)) + break + + def _callbackPressKey(self, panel, key): + self._callbackView(panel) + + control = cli.controller.getController() + panel = control.getPanel(panel) + panel.handleKey(key) + diff --git a/src/util/menuItem.py b/src/util/menuItem.py index 3dbf922..6868db6 100644 --- a/src/util/menuItem.py +++ b/src/util/menuItem.py @@ -5,10 +5,11 @@ Menu Item class, used by the drop-down menus class MenuItem(): """Contains title, callback handler and possible children"""
- def __init__(self, label=None, callback=None, children=[]): + def __init__(self, label=None, callback=None, children=[], enabled=None): self._label = label self._callback = callback self._children = children + self._enabled = enabled
def getLabel(self): return self._label @@ -19,6 +20,14 @@ class MenuItem(): def isParent(self): return self._children != []
+ def isEnabled(self): + if self._enabled == None: + return True + elif hasattr(self._enabled, '__call__'): + return self._enabled() + else: + return self._enabled + def getChildren(self): return self._children
tor-commits@lists.torproject.org