[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