[tor-commits] [arm/release] Moving Kamran's menu to avoid namespace conflicts

atagar at torproject.org atagar at torproject.org
Sun Jul 17 06:08:22 UTC 2011


commit 856226d684220b746b44c2f44a1c3d3d03f8384b
Author: Damian Johnson <atagar at torproject.org>
Date:   Sat Jun 4 14:05:23 2011 -0700

    Moving Kamran's menu to avoid namespace conflicts
    
    My 'src/cli/menu' module was conflicting with his 'src/cli/menu.py' class so
    I've moved his implementation to 'src/cli/menu_alt'.
---
 src/cli/__init__.py          |    2 +-
 src/cli/controller.py        |    6 +-
 src/cli/menu.py              |  438 -----------------------------------------
 src/cli/menu_alt/__init__.py |    6 +
 src/cli/menu_alt/menu.py     |  439 ++++++++++++++++++++++++++++++++++++++++++
 src/cli/menu_alt/menuItem.py |   41 ++++
 src/util/menuItem.py         |   41 ----
 7 files changed, 490 insertions(+), 483 deletions(-)

diff --git a/src/cli/__init__.py b/src/cli/__init__.py
index 81fabeb..1564f68 100644
--- a/src/cli/__init__.py
+++ b/src/cli/__init__.py
@@ -2,5 +2,5 @@
 Panels, popups, and handlers comprising the arm user interface.
 """
 
-__all__ = ["configPanel", "controller", "descriptorPopup", "headerPanel", "logPanel", "menu", "popups", "torrcPanel"]
+__all__ = ["configPanel", "controller", "descriptorPopup", "headerPanel", "logPanel", "popups", "torrcPanel"]
 
diff --git a/src/cli/controller.py b/src/cli/controller.py
index fac43a4..997d9d3 100644
--- a/src/cli/controller.py
+++ b/src/cli/controller.py
@@ -7,8 +7,8 @@ import time
 import curses
 import threading
 
-import cli.menu
 import cli.menu.menu
+import cli.menu_alt.menu
 import cli.popups
 import cli.headerPanel
 import cli.logPanel
@@ -512,10 +512,10 @@ def drawTorMonitor(stdscr, startTime):
     elif key == ord('p') or key == ord('P'):
       control.setPaused(not control.isPaused())
     elif key == ord('n') or key == ord('N'):
-      menu = cli.menu.Menu()
+      menu = cli.menu_alt.menu.Menu()
       menuKeys = menu.showMenu(keys=menuKeys)
       if menuKeys != []:
-        for key in (ord('m'), ord('q'), ord('x')):
+        for key in (ord('n'), ord('q'), ord('x')):
           if key in menuKeys:
             menuKeys.remove(key)
             overrideKey = key
diff --git a/src/cli/menu.py b/src/cli/menu.py
deleted file mode 100644
index 47e8d09..0000000
--- a/src/cli/menu.py
+++ /dev/null
@@ -1,438 +0,0 @@
-"""
-A drop-down menu for sending actions to panels.
-"""
-
-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)
-
-class Menu():
-  """Displays a popup menu and sends keys to appropriate panels"""
-
-  def __init__(self, item=None):
-    DEFAULT_ROOT = menuItem.MenuItem(label="Root", children=(
-      menuItem.MenuItem(label="File", children=(
-        menuItem.MenuItem(label="Exit",
-                          callback=lambda item: self._callbackReturnKey(ord('q'))),)),
-      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="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",
-                            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="Configuration" , children=(
-        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=lambda item: self._callbackPressKey('configFile', ord('r'))),
-        menuItem.MenuItem(label="Reset Tor",
-                          callback=lambda item: self._callbackReturnKey(ord('x'))),))
-      ))
-
-    self._first = [0]
-    self._selection = [0]
-
-    if item and item.isParent():
-      self._rootItem = item
-    else:
-      self._rootItem = DEFAULT_ROOT
-
-  def showMenu(self, keys=[]):
-    keys.reverse()
-    returnkeys = []
-
-    popup, width, height = popups.init(height=3)
-    if popup:
-      try:
-        while True:
-          popup.win.erase()
-          popup.win.box()
-
-          self._drawTopLevel(popup, width, height)
-
-          popup.win.refresh()
-
-          control = cli.controller.getController()
-
-          if keys == []:
-            key = control.getScreen().getch()
-          else:
-            key = keys.pop()
-
-          if key == curses.KEY_RIGHT:
-            self._moveTopLevelRight(width)
-          elif key == curses.KEY_LEFT:
-            self._moveTopLevelLeft(width)
-          elif key == curses.KEY_DOWN:
-            cascaded, returnkeys = self._cascadeNLevel()
-            break
-          elif key == 27:
-            break
-          elif uiTools.isSelectionKey(key):
-            self._handleEvent()
-            break
-
-      finally:
-        popups.finalize()
-
-    return returnkeys
-
-  def _appendLevel(self):
-    self._first.append(0)
-    self._selection.append(0)
-
-  def _removeLevel(self):
-    self._first.pop()
-    self._selection.pop()
-
-  def _getCurrentTopLevelItem(self):
-    index = self._first[TOPLEVEL] + self._selection[TOPLEVEL]
-    return self._rootItem.getChildren()[index]
-
-  def _getCurrentItem(self, level=0):
-    item = self._rootItem
-    if level == 0:
-      sums = [sum(values) for values in zip(self._first, self._selection)]
-    else:
-      sums = [sum(values) for values in zip(self._first[:level], self._selection[:level])]
-
-    for index in sums:
-      if item.isParent():
-        item = item.getChildren()[index]
-      else:
-        break
-
-    return item
-
-  def _calculateTopLevelWidths(self, width=0):
-    labels = [menuItem.getLabel() for menuItem in self._rootItem.getChildren()]
-
-    # width per label is set according to the longest label
-    labelwidth = max(map(len, labels)) + 2
-
-    # total number of labels that can be printed in supplied width
-    printable = min(width / labelwidth - 1, self._rootItem.getChildrenCount())
-
-    return (labelwidth, printable)
-
-  def _calculateNLevelWidths(self, level=0):
-    parent = self._getCurrentItem(level)
-
-    if parent.isLeaf():
-      return 0
-
-    labels = [menuItem.getLabel() for menuItem in parent.getChildren()]
-
-    labelwidth = max(map(len, labels))
-
-    return labelwidth
-
-  def _calculateNLevelHeights(self, height=0, level=0):
-    control = cli.controller.getController()
-    height, _ = control.getScreen().getmaxyx()
-    topSize = sum(stickyPanel.getHeight() for stickyPanel in control.getStickyPanels())
-    height = height - topSize
-
-    parent = self._getCurrentItem(level)
-
-    if parent.isLeaf():
-      return 0
-
-    printable = min(height - 4, parent.getChildrenCount())
-
-    return printable if printable else parent.getChildrenCount()
-
-  def _moveTopLevelRight(self, width):
-    _, printable = self._calculateTopLevelWidths(width)
-
-    if self._selection[TOPLEVEL] < printable - 1:
-      self._selection[TOPLEVEL] = self._selection[TOPLEVEL] + 1
-    else:
-      self._selection[TOPLEVEL] = 0
-      if printable < self._rootItem.getChildrenCount():
-        self._first[TOPLEVEL] = (self._first[TOPLEVEL] + printable) % self._rootItem.getChildrenCount()
-
-    if self._first[TOPLEVEL] + self._selection[TOPLEVEL] == self._rootItem.getChildrenCount():
-      self._first[TOPLEVEL] = 0
-      self._selection[TOPLEVEL] = 0
-
-  def _moveTopLevelLeft(self, width):
-    _, printable = self._calculateTopLevelWidths(width)
-
-    if self._selection[TOPLEVEL] > 0:
-      self._selection[TOPLEVEL] = self._selection[TOPLEVEL] - 1
-    else:
-      if self._first[TOPLEVEL] == 0:
-        self._first[TOPLEVEL] = ((self._rootItem.getChildrenCount() / printable) * printable) % self._rootItem.getChildrenCount()
-      else:
-        self._first[TOPLEVEL] = abs(self._first[TOPLEVEL] - printable) % self._rootItem.getChildrenCount()
-      self._selection[TOPLEVEL] = self._rootItem.getChildrenCount() - self._first[TOPLEVEL] - 1
-
-    if self._selection[TOPLEVEL] > printable:
-      self._selection[TOPLEVEL] = printable - 1
-
-  def _drawTopLevel(self, popup, width, height):
-    labelwidth, printable = self._calculateTopLevelWidths(width)
-    children = self._rootItem.getChildren()[self._first[TOPLEVEL]:self._first[TOPLEVEL] + printable]
-
-    top = 1
-    left = 1
-    for (index, item) in enumerate(children):
-      labelformat = curses.A_STANDOUT if index == self._selection[TOPLEVEL] else curses.A_NORMAL
-
-      popup.addch(top, left, curses.ACS_VLINE)
-      left = left + 1
-      popup.addstr(top, left, item.getLabel().center(labelwidth), labelformat)
-      left = left + labelwidth
-
-    popup.addch(top, left, curses.ACS_VLINE)
-    left = left + 1
-
-  def _cascadeNLevel(self):
-    parent = self._getCurrentItem()
-
-    if parent.isLeaf():
-      return (False, [])
-
-    self._appendLevel()
-
-    labelwidth = self._calculateNLevelWidths(level=PARENTLEVEL)
-    printable = self._calculateNLevelHeights(level=PARENTLEVEL)
-
-    toplabelwidth, _ = self._calculateTopLevelWidths()
-    left = (toplabelwidth + 2) * self._selection[TOPLEVEL]
-
-    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:
-      returnkeys = []
-      try:
-        while True:
-          popup.win.erase()
-          popup.win.box()
-
-          self._drawNLevel(popup, width, height)
-
-          popup.win.refresh()
-
-          control = cli.controller.getController()
-          key = control.getScreen().getch()
-
-          if key == curses.KEY_DOWN:
-            self._moveNLevelDown(height)
-          elif key == curses.KEY_UP:
-            self._moveNLevelUp(height)
-          elif key == curses.KEY_RIGHT:
-            cascaded, returnkeys = self._cascadeNLevel()
-            if cascaded == False:
-              index = self._first[TOPLEVEL] + self._selection[TOPLEVEL] + 1
-              returnkeys.append(ord('m'))
-              for i in range(index):
-                returnkeys.append(curses.KEY_RIGHT)
-              returnkeys.append(curses.KEY_DOWN)
-            break
-          elif key == curses.KEY_LEFT:
-            index = self._first[TOPLEVEL] + self._selection[TOPLEVEL] - 1
-            index = index % self._rootItem.getChildrenCount()
-            returnkeys.append(ord('m'))
-            for i in range(index):
-              returnkeys.append(curses.KEY_RIGHT)
-            returnkeys.append(curses.KEY_DOWN)
-            break
-          elif key == 27:
-            self._removeLevel()
-            break
-          elif uiTools.isSelectionKey(key):
-            returnkey = self._handleEvent()
-            if returnkey:
-                returnkeys.append(returnkey)
-            self._removeLevel()
-            break
-
-      finally:
-        popups.finalize()
-
-      return (True, returnkeys)
-
-    return (False, [])
-
-  def _drawNLevel(self, popup, width, height):
-    printable = self._calculateNLevelHeights(level=PARENTLEVEL)
-    parent = self._getCurrentItem(level=PARENTLEVEL)
-    children = parent.getChildren()[self._first[PARENTLEVEL]:self._first[PARENTLEVEL] + printable]
-
-    top = 1
-    left = 1
-    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
-
-  def _moveNLevelDown(self, height):
-    printable = self._calculateNLevelHeights(level=PARENTLEVEL)
-    parent = self._getCurrentItem(level=PARENTLEVEL)
-
-    if self._selection[PARENTLEVEL] < printable - 1:
-      self._selection[PARENTLEVEL] = self._selection[PARENTLEVEL] + 1
-    else:
-      self._selection[PARENTLEVEL] = 0
-      if printable < parent.getChildrenCount():
-        self._first[PARENTLEVEL] = (self._first[PARENTLEVEL] + printable) % parent.getChildrenCount()
-
-    if self._first[PARENTLEVEL] + self._selection[PARENTLEVEL] == parent.getChildrenCount():
-      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)
-
-    if self._selection[PARENTLEVEL] > 0:
-      self._selection[PARENTLEVEL] = self._selection[PARENTLEVEL] - 1
-    else:
-      if self._first[PARENTLEVEL] == 0:
-        self._first[PARENTLEVEL] = ((parent.getChildrenCount() / printable) * printable) % parent.getChildrenCount()
-      else:
-        self._first[PARENTLEVEL] = abs(self._first[PARENTLEVEL] - printable) % parent.getChildrenCount()
-      self._selection[PARENTLEVEL] = parent.getChildrenCount() - self._first[PARENTLEVEL] - 1
-
-    if self._selection[PARENTLEVEL] > printable:
-      self._selection[PARENTLEVEL] = printable - 1
-
-    while self._getCurrentItem().isEnabled() == False:
-      self._moveNLevelUp(height)
-
-  def _handleEvent(self):
-    item = self._getCurrentItem()
-
-    if item.isLeaf():
-      return item.select()
-    else:
-      self._cascadeNLevel()
-
-  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):
-    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):
-    control = cli.controller.getController()
-    panel = control.getPanel(panel)
-    panel.handleKey(key)
-
-  def _callbackReturnKey(self, key):
-    return key
-
diff --git a/src/cli/menu_alt/__init__.py b/src/cli/menu_alt/__init__.py
new file mode 100644
index 0000000..6d7b6b7
--- /dev/null
+++ b/src/cli/menu_alt/__init__.py
@@ -0,0 +1,6 @@
+"""
+Resources for displaying the menu.
+"""
+
+__all__ = ["menuItem", "menu"]
+
diff --git a/src/cli/menu_alt/menu.py b/src/cli/menu_alt/menu.py
new file mode 100644
index 0000000..7e10366
--- /dev/null
+++ b/src/cli/menu_alt/menu.py
@@ -0,0 +1,439 @@
+"""
+A drop-down menu for sending actions to panels.
+"""
+
+import curses
+
+import cli.controller
+import cli.menu_alt.menuItem as menuItem
+import cli.popups
+
+from cli.graphing.graphPanel import Bounds as GraphBounds
+from util import log, panel, uiTools
+
+PARENTLEVEL, TOPLEVEL = (-1, 0)
+
+class Menu():
+  """Displays a popup menu and sends keys to appropriate panels"""
+
+  def __init__(self, item=None):
+    DEFAULT_ROOT = menuItem.MenuItem(label="Root", children=(
+      menuItem.MenuItem(label="File", children=(
+        menuItem.MenuItem(label="Exit",
+                          callback=lambda item: self._callbackReturnKey(ord('q'))),)),
+      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="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",
+                            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="Configuration" , children=(
+        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=lambda item: self._callbackPressKey('configFile', ord('r'))),
+        menuItem.MenuItem(label="Reset Tor",
+                          callback=lambda item: self._callbackReturnKey(ord('x'))),))
+      ))
+
+    self._first = [0]
+    self._selection = [0]
+
+    if item and item.isParent():
+      self._rootItem = item
+    else:
+      self._rootItem = DEFAULT_ROOT
+
+  def showMenu(self, keys=[]):
+    keys.reverse()
+    returnkeys = []
+
+    popup, width, height = cli.popups.init(height=3)
+    if popup:
+      try:
+        while True:
+          popup.win.erase()
+          popup.win.box()
+
+          self._drawTopLevel(popup, width, height)
+
+          popup.win.refresh()
+
+          control = cli.controller.getController()
+
+          if keys == []:
+            key = control.getScreen().getch()
+          else:
+            key = keys.pop()
+
+          if key == curses.KEY_RIGHT:
+            self._moveTopLevelRight(width)
+          elif key == curses.KEY_LEFT:
+            self._moveTopLevelLeft(width)
+          elif key == curses.KEY_DOWN:
+            cascaded, returnkeys = self._cascadeNLevel()
+            break
+          elif key == 27:
+            break
+          elif uiTools.isSelectionKey(key):
+            self._handleEvent()
+            break
+
+      finally:
+        cli.popups.finalize()
+
+    return returnkeys
+
+  def _appendLevel(self):
+    self._first.append(0)
+    self._selection.append(0)
+
+  def _removeLevel(self):
+    self._first.pop()
+    self._selection.pop()
+
+  def _getCurrentTopLevelItem(self):
+    index = self._first[TOPLEVEL] + self._selection[TOPLEVEL]
+    return self._rootItem.getChildren()[index]
+
+  def _getCurrentItem(self, level=0):
+    item = self._rootItem
+    if level == 0:
+      sums = [sum(values) for values in zip(self._first, self._selection)]
+    else:
+      sums = [sum(values) for values in zip(self._first[:level], self._selection[:level])]
+
+    for index in sums:
+      if item.isParent():
+        item = item.getChildren()[index]
+      else:
+        break
+
+    return item
+
+  def _calculateTopLevelWidths(self, width=0):
+    labels = [menuItem.getLabel() for menuItem in self._rootItem.getChildren()]
+
+    # width per label is set according to the longest label
+    labelwidth = max(map(len, labels)) + 2
+
+    # total number of labels that can be printed in supplied width
+    printable = min(width / labelwidth - 1, self._rootItem.getChildrenCount())
+
+    return (labelwidth, printable)
+
+  def _calculateNLevelWidths(self, level=0):
+    parent = self._getCurrentItem(level)
+
+    if parent.isLeaf():
+      return 0
+
+    labels = [menuItem.getLabel() for menuItem in parent.getChildren()]
+
+    labelwidth = max(map(len, labels))
+
+    return labelwidth
+
+  def _calculateNLevelHeights(self, height=0, level=0):
+    control = cli.controller.getController()
+    height, _ = control.getScreen().getmaxyx()
+    topSize = sum(stickyPanel.getHeight() for stickyPanel in control.getStickyPanels())
+    height = height - topSize
+
+    parent = self._getCurrentItem(level)
+
+    if parent.isLeaf():
+      return 0
+
+    printable = min(height - 4, parent.getChildrenCount())
+
+    return printable if printable else parent.getChildrenCount()
+
+  def _moveTopLevelRight(self, width):
+    _, printable = self._calculateTopLevelWidths(width)
+
+    if self._selection[TOPLEVEL] < printable - 1:
+      self._selection[TOPLEVEL] = self._selection[TOPLEVEL] + 1
+    else:
+      self._selection[TOPLEVEL] = 0
+      if printable < self._rootItem.getChildrenCount():
+        self._first[TOPLEVEL] = (self._first[TOPLEVEL] + printable) % self._rootItem.getChildrenCount()
+
+    if self._first[TOPLEVEL] + self._selection[TOPLEVEL] == self._rootItem.getChildrenCount():
+      self._first[TOPLEVEL] = 0
+      self._selection[TOPLEVEL] = 0
+
+  def _moveTopLevelLeft(self, width):
+    _, printable = self._calculateTopLevelWidths(width)
+
+    if self._selection[TOPLEVEL] > 0:
+      self._selection[TOPLEVEL] = self._selection[TOPLEVEL] - 1
+    else:
+      if self._first[TOPLEVEL] == 0:
+        self._first[TOPLEVEL] = ((self._rootItem.getChildrenCount() / printable) * printable) % self._rootItem.getChildrenCount()
+      else:
+        self._first[TOPLEVEL] = abs(self._first[TOPLEVEL] - printable) % self._rootItem.getChildrenCount()
+      self._selection[TOPLEVEL] = self._rootItem.getChildrenCount() - self._first[TOPLEVEL] - 1
+
+    if self._selection[TOPLEVEL] > printable:
+      self._selection[TOPLEVEL] = printable - 1
+
+  def _drawTopLevel(self, popup, width, height):
+    labelwidth, printable = self._calculateTopLevelWidths(width)
+    children = self._rootItem.getChildren()[self._first[TOPLEVEL]:self._first[TOPLEVEL] + printable]
+
+    top = 1
+    left = 1
+    for (index, item) in enumerate(children):
+      labelformat = curses.A_STANDOUT if index == self._selection[TOPLEVEL] else curses.A_NORMAL
+
+      popup.addch(top, left, curses.ACS_VLINE)
+      left = left + 1
+      popup.addstr(top, left, item.getLabel().center(labelwidth), labelformat)
+      left = left + labelwidth
+
+    popup.addch(top, left, curses.ACS_VLINE)
+    left = left + 1
+
+  def _cascadeNLevel(self):
+    parent = self._getCurrentItem()
+
+    if parent.isLeaf():
+      return (False, [])
+
+    self._appendLevel()
+
+    labelwidth = self._calculateNLevelWidths(level=PARENTLEVEL)
+    printable = self._calculateNLevelHeights(level=PARENTLEVEL)
+
+    toplabelwidth, _ = self._calculateTopLevelWidths()
+    left = (toplabelwidth + 2) * self._selection[TOPLEVEL]
+
+    popup, width, height = cli.popups.init(height=printable+2, width=labelwidth+2, top=2, left=left)
+
+    while self._getCurrentItem().isEnabled() == False:
+      self._moveNLevelDown(height)
+
+    if popup.win:
+      returnkeys = []
+      try:
+        while True:
+          popup.win.erase()
+          popup.win.box()
+
+          self._drawNLevel(popup, width, height)
+
+          popup.win.refresh()
+
+          control = cli.controller.getController()
+          key = control.getScreen().getch()
+
+          if key == curses.KEY_DOWN:
+            self._moveNLevelDown(height)
+          elif key == curses.KEY_UP:
+            self._moveNLevelUp(height)
+          elif key == curses.KEY_RIGHT:
+            cascaded, returnkeys = self._cascadeNLevel()
+            if cascaded == False:
+              index = self._first[TOPLEVEL] + self._selection[TOPLEVEL] + 1
+              returnkeys.append(ord('n'))
+              for i in range(index):
+                returnkeys.append(curses.KEY_RIGHT)
+              returnkeys.append(curses.KEY_DOWN)
+            break
+          elif key == curses.KEY_LEFT:
+            index = self._first[TOPLEVEL] + self._selection[TOPLEVEL] - 1
+            index = index % self._rootItem.getChildrenCount()
+            returnkeys.append(ord('n'))
+            for i in range(index):
+              returnkeys.append(curses.KEY_RIGHT)
+            returnkeys.append(curses.KEY_DOWN)
+            break
+          elif key == 27:
+            self._removeLevel()
+            break
+          elif uiTools.isSelectionKey(key):
+            returnkey = self._handleEvent()
+            if returnkey:
+                returnkeys.append(returnkey)
+            self._removeLevel()
+            break
+
+      finally:
+        cli.popups.finalize()
+
+      return (True, returnkeys)
+
+    return (False, [])
+
+  def _drawNLevel(self, popup, width, height):
+    printable = self._calculateNLevelHeights(level=PARENTLEVEL)
+    parent = self._getCurrentItem(level=PARENTLEVEL)
+    children = parent.getChildren()[self._first[PARENTLEVEL]:self._first[PARENTLEVEL] + printable]
+
+    top = 1
+    left = 1
+    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
+
+  def _moveNLevelDown(self, height):
+    printable = self._calculateNLevelHeights(level=PARENTLEVEL)
+    parent = self._getCurrentItem(level=PARENTLEVEL)
+
+    if self._selection[PARENTLEVEL] < printable - 1:
+      self._selection[PARENTLEVEL] = self._selection[PARENTLEVEL] + 1
+    else:
+      self._selection[PARENTLEVEL] = 0
+      if printable < parent.getChildrenCount():
+        self._first[PARENTLEVEL] = (self._first[PARENTLEVEL] + printable) % parent.getChildrenCount()
+
+    if self._first[PARENTLEVEL] + self._selection[PARENTLEVEL] == parent.getChildrenCount():
+      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)
+
+    if self._selection[PARENTLEVEL] > 0:
+      self._selection[PARENTLEVEL] = self._selection[PARENTLEVEL] - 1
+    else:
+      if self._first[PARENTLEVEL] == 0:
+        self._first[PARENTLEVEL] = ((parent.getChildrenCount() / printable) * printable) % parent.getChildrenCount()
+      else:
+        self._first[PARENTLEVEL] = abs(self._first[PARENTLEVEL] - printable) % parent.getChildrenCount()
+      self._selection[PARENTLEVEL] = parent.getChildrenCount() - self._first[PARENTLEVEL] - 1
+
+    if self._selection[PARENTLEVEL] > printable:
+      self._selection[PARENTLEVEL] = printable - 1
+
+    while self._getCurrentItem().isEnabled() == False:
+      self._moveNLevelUp(height)
+
+  def _handleEvent(self):
+    item = self._getCurrentItem()
+
+    if item.isLeaf():
+      return item.select()
+    else:
+      self._cascadeNLevel()
+
+  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):
+    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):
+    control = cli.controller.getController()
+    panel = control.getPanel(panel)
+    panel.handleKey(key)
+
+  def _callbackReturnKey(self, key):
+    return key
+
diff --git a/src/cli/menu_alt/menuItem.py b/src/cli/menu_alt/menuItem.py
new file mode 100644
index 0000000..277c78a
--- /dev/null
+++ b/src/cli/menu_alt/menuItem.py
@@ -0,0 +1,41 @@
+"""
+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=[], enabled=None):
+    self._label = label
+    self._callback = callback
+    self._children = children
+    self._enabled = enabled
+  
+  def getLabel(self):
+    return self._label
+  
+  def isLeaf(self):
+    return self._children == []
+  
+  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
+  
+  def getChildrenCount(self):
+    return len(self._children)
+  
+  def select(self):
+    return self._callback(self)
+
diff --git a/src/util/menuItem.py b/src/util/menuItem.py
deleted file mode 100644
index 277c78a..0000000
--- a/src/util/menuItem.py
+++ /dev/null
@@ -1,41 +0,0 @@
-"""
-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=[], enabled=None):
-    self._label = label
-    self._callback = callback
-    self._children = children
-    self._enabled = enabled
-  
-  def getLabel(self):
-    return self._label
-  
-  def isLeaf(self):
-    return self._children == []
-  
-  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
-  
-  def getChildrenCount(self):
-    return len(self._children)
-  
-  def select(self):
-    return self._callback(self)
-





More information about the tor-commits mailing list