[Author Prev][Author Next][Thread Prev][Thread Next][Author Index][Thread Index]

[tor-commits] [nyx/master] Move submenus to panels



commit c9467743eb00f282c36677ef37d6dda5e23856be
Author: Damian Johnson <atagar@xxxxxxxxxxxxxx>
Date:   Thu Aug 25 09:55:55 2016 -0700

    Move submenus to panels
    
    Now that constructing submenus is so much simpler this fits a lot better in the
    Panel subclasses. This is a great simplification for the panels as well as the
    menu module sincel it lets us make numerous attributes and functions private.
---
 nyx/controller.py       |   7 +--
 nyx/menu.py             | 141 ++----------------------------------------------
 nyx/panel/__init__.py   |  11 ++++
 nyx/panel/config.py     |  24 +++++++--
 nyx/panel/connection.py |  24 ++++++++-
 nyx/panel/graph.py      |  97 ++++++++++++++++-----------------
 nyx/panel/log.py        |  75 +++++++++++++-------------
 nyx/panel/torrc.py      |  43 ++++++++-------
 8 files changed, 163 insertions(+), 259 deletions(-)

diff --git a/nyx/controller.py b/nyx/controller.py
index 8040e7e..bf7a22d 100644
--- a/nyx/controller.py
+++ b/nyx/controller.py
@@ -372,9 +372,7 @@ def start_nyx():
     for panel_impl in control.get_all_panels():
       panel_impl.set_visible(panel_impl in display_panels)
 
-    # redraws the interface if it's needed
-
-    control.redraw(False)
+    control.redraw()
 
     with nyx.curses.raw_screen() as stdscr:
       stdscr.refresh()
@@ -419,9 +417,6 @@ def start_nyx():
           log.error('Error detected when reloading tor: %s' % exc.strerror)
     elif key.match('h'):
       override_key = nyx.popups.show_help()
-    elif key == ord('l') - 96:
-      # force redraw when ctrl+l is pressed
-      control.redraw(True)
     else:
       for panel_impl in display_panels:
         for keybinding in panel_impl.key_handlers():
diff --git a/nyx/menu.py b/nyx/menu.py
index b0fb646..ed58613 100644
--- a/nyx/menu.py
+++ b/nyx/menu.py
@@ -10,16 +10,8 @@ import functools
 import nyx.controller
 import nyx.curses
 import nyx.popups
-import nyx.panel.config
-import nyx.panel.connection
-import nyx.panel.graph
-import nyx.panel.log
-import nyx.panel.torrc
-import nyx.controller
-import nyx.tracker
 
 import stem
-import stem.util.connection
 
 from nyx import tor_controller
 from nyx.curses import RED, WHITE, NORMAL, BOLD, UNDERLINE
@@ -182,17 +174,11 @@ def make_menu():
 
   root_menu.add(_view_menu())
 
-  for page_panel in nyx_controller.get_display_panels():
-    if isinstance(page_panel, nyx.panel.graph.GraphPanel):
-      root_menu.add(_graph_menu(page_panel))
-    elif isinstance(page_panel, nyx.panel.log.LogPanel):
-      root_menu.add(_log_menu(page_panel))
-    elif isinstance(page_panel, nyx.panel.connection.ConnectionPanel):
-      root_menu.add(_connections_menu(page_panel))
-    elif isinstance(page_panel, nyx.panel.config.ConfigPanel):
-      root_menu.add(_configuration_menu(page_panel))
-    elif isinstance(page_panel, nyx.panel.torrc.TorrcPanel):
-      root_menu.add(_torrc_menu(page_panel))
+  for panel in nyx_controller.get_display_panels():
+    submenu = panel.submenu()
+
+    if submenu:
+      root_menu.add(submenu)
 
   root_menu.add(Submenu('Help', [
     MenuItem('Hotkeys', nyx.popups.show_help),
@@ -233,123 +219,6 @@ def _view_menu():
   return view_menu
 
 
-def _graph_menu(graph_panel):
-  """
-  Graph panel submenu consisting of...
-
-    [X] <Stat 1>
-    [ ] <Stat 2>
-    [ ] <Stat 2>
-        Resize...
-        Interval (Submenu)
-        Bounds (Submenu)
-  """
-
-  stat_group = RadioGroup(functools.partial(setattr, graph_panel, 'displayed_stat'), graph_panel.displayed_stat)
-  interval_group = RadioGroup(functools.partial(setattr, graph_panel, 'update_interval'), graph_panel.update_interval)
-  bounds_group = RadioGroup(functools.partial(setattr, graph_panel, 'bounds_type'), graph_panel.bounds_type)
-
-  return Submenu('Graph', [
-    RadioMenuItem('None', stat_group, None),
-    [RadioMenuItem(str_tools._to_camel_case(opt, divider = ' '), stat_group, opt) for opt in sorted(graph_panel.stat_options())],
-    MenuItem('Resize...', graph_panel.resize_graph),
-    Submenu('Interval', [RadioMenuItem(opt, interval_group, opt) for opt in nyx.panel.graph.Interval]),
-    Submenu('Bounds', [RadioMenuItem(opt, bounds_group, opt) for opt in nyx.panel.graph.Bounds]),
-  ])
-
-
-def _log_menu(log_panel):
-  """
-  Log panel submenu consisting of...
-
-    Events...
-    Snapshot...
-    Clear
-    Show / Hide Duplicates
-    Filter (Submenu)
-  """
-
-  log_filter = log_panel.get_filter()
-  filter_group = RadioGroup(log_filter.select, log_filter.selection())
-
-  if not log_panel.is_duplicates_visible():
-    duplicate_item = MenuItem('Show Duplicates', log_panel.set_duplicate_visability, True)
-  else:
-    duplicate_item = MenuItem('Hide Duplicates', log_panel.set_duplicate_visability, False)
-
-  return Submenu('Log', [
-    MenuItem('Events...', log_panel.show_event_selection_prompt),
-    MenuItem('Snapshot...', log_panel.show_snapshot_prompt),
-    MenuItem('Clear', log_panel.clear),
-    duplicate_item,
-    Submenu('Filter', [
-      RadioMenuItem('None', filter_group, None),
-      [RadioMenuItem(opt, filter_group, opt) for opt in log_filter.latest_selections()],
-      MenuItem('New...', log_panel.show_filter_prompt),
-    ]),
-  ])
-
-
-def _connections_menu(conn_panel):
-  """
-  Connection panel submenu consisting of...
-
-    Sorting...
-    Resolver (Submenu)
-  """
-
-  tracker = nyx.tracker.get_connection_tracker()
-  resolver_group = RadioGroup(tracker.set_custom_resolver, tracker.get_custom_resolver())
-
-  return Submenu('Connections', [
-    MenuItem('Sorting...', conn_panel.show_sort_dialog),
-    Submenu('Resolver', [
-      RadioMenuItem('auto', resolver_group, None),
-      [RadioMenuItem(opt, resolver_group, opt) for opt in stem.util.connection.Resolver],
-    ]),
-  ])
-
-
-def _configuration_menu(config_panel):
-  """
-  Configuration panel submenu consisting of...
-
-    Save Config...
-    Sorting...
-    Filter / Unfilter Options
-  """
-
-  return Submenu('Configuration', [
-    MenuItem('Save Config...', config_panel.show_write_dialog),
-    MenuItem('Sorting...', config_panel.show_sort_dialog),
-  ])
-
-
-def _torrc_menu(torrc_panel):
-  """
-  Torrc panel submenu consisting of...
-
-    Reload
-    Show / Hide Comments
-    Show / Hide Line Numbers
-  """
-
-  if not torrc_panel._show_comments:
-    comments_item = MenuItem('Show Comments', torrc_panel.set_comments_visible, True)
-  else:
-    comments_item = MenuItem('Hide Comments', torrc_panel.set_comments_visible, False)
-
-  if not torrc_panel._show_line_numbers:
-    line_number_item = MenuItem('Show Line Numbers', torrc_panel.set_line_number_visible, True)
-  else:
-    line_number_item = MenuItem('Hide Line Numbers', torrc_panel.set_line_number_visible, False)
-
-  return Submenu('Torrc', [
-    comments_item,
-    line_number_item,
-  ])
-
-
 class MenuCursor:
   """
   Tracks selection and key handling in the menu.
diff --git a/nyx/panel/__init__.py b/nyx/panel/__init__.py
index decb276..18a66ce 100644
--- a/nyx/panel/__init__.py
+++ b/nyx/panel/__init__.py
@@ -22,6 +22,7 @@ Panels consisting the nyx interface.
     |
     |- set_visible - toggles panel visiblity
     |- key_handlers - keyboard input accepted by the panel
+    |- submenu - submenu for the panel
     +- redraw - renders the panel content
 """
 
@@ -139,6 +140,16 @@ class Panel(object):
 
     return ()
 
+  def submenu(self):
+    """
+    Provides submenu to include when the panel is shown.
+
+    :returns: :class:`~nyx.menu.Submenu` with the panel's options or **None**
+      if no submenu should be shown
+    """
+
+    return None
+
   def redraw(self, force = True):
     """
     Renders our panel's content to the screen.
diff --git a/nyx/panel/config.py b/nyx/panel/config.py
index 7640b99..424586c 100644
--- a/nyx/panel/config.py
+++ b/nyx/panel/config.py
@@ -16,8 +16,10 @@ import nyx.popups
 
 import stem.control
 import stem.manual
+import stem.util.connection
 
 from nyx.curses import WHITE, NORMAL, BOLD, HIGHLIGHT
+from nyx.menu import MenuItem, Submenu
 from nyx import DATA_DIR, tor_controller
 
 from stem.util import conf, enum, log, str_tools
@@ -169,7 +171,7 @@ class ConfigPanel(nyx.panel.Panel):
     except stem.ControllerError as exc:
       log.warn('Unable to determine the configuration options tor supports: %s' % exc)
 
-  def show_sort_dialog(self):
+  def _show_sort_dialog(self):
     """
     Provides the dialog for sorting our configuration options.
     """
@@ -181,7 +183,7 @@ class ConfigPanel(nyx.panel.Panel):
       self._sort_order = results
       self._contents = sorted(self._contents, key = lambda entry: [entry.sort_value(field) for field in self._sort_order])
 
-  def show_write_dialog(self):
+  def _show_write_dialog(self):
     """
     Confirmation dialog for saving tor's configuration.
     """
@@ -235,11 +237,25 @@ class ConfigPanel(nyx.panel.Panel):
     return (
       nyx.panel.KeyHandler('arrows', 'scroll up and down', _scroll, key_func = lambda key: key.is_scroll()),
       nyx.panel.KeyHandler('enter', 'edit configuration option', _edit_selected_value, key_func = lambda key: key.is_selection()),
-      nyx.panel.KeyHandler('w', 'write torrc', self.show_write_dialog),
+      nyx.panel.KeyHandler('w', 'write torrc', self._show_write_dialog),
       nyx.panel.KeyHandler('a', 'toggle filtering', _toggle_show_all),
-      nyx.panel.KeyHandler('s', 'sort ordering', self.show_sort_dialog),
+      nyx.panel.KeyHandler('s', 'sort ordering', self._show_sort_dialog),
     )
 
+  def submenu(self):
+    """
+    Submenu consisting of...
+
+      Save Config...
+      Sorting...
+      Filter / Unfilter Options
+    """
+
+    return Submenu('Configuration', [
+      MenuItem('Save Config...', self._show_write_dialog),
+      MenuItem('Sorting...', self._show_sort_dialog),
+    ])
+
   def _draw(self, subwindow):
     contents = self._get_config_options()
     selected, scroll = self._scroller.selection(contents, subwindow.height - DETAILS_HEIGHT)
diff --git a/nyx/panel/connection.py b/nyx/panel/connection.py
index afcf457..d30742f 100644
--- a/nyx/panel/connection.py
+++ b/nyx/panel/connection.py
@@ -18,6 +18,7 @@ import nyx.popups
 import nyx.tracker
 
 from nyx.curses import WHITE, NORMAL, BOLD, HIGHLIGHT
+from nyx.menu import MenuItem, Submenu, RadioMenuItem, RadioGroup
 from nyx import tor_controller
 
 from stem.control import Listener
@@ -296,7 +297,7 @@ class ConnectionPanel(nyx.panel.DaemonPanel):
             locale, count = entry.split('=', 1)
             self._client_locale_usage[locale] = int(count)
 
-  def show_sort_dialog(self):
+  def _show_sort_dialog(self):
     """
     Provides a dialog for sorting our connections.
     """
@@ -384,7 +385,7 @@ class ConnectionPanel(nyx.panel.DaemonPanel):
       nyx.panel.KeyHandler('arrows', 'scroll up and down', _scroll, key_func = lambda key: key.is_scroll()),
       nyx.panel.KeyHandler('enter', 'show connection details', _show_details, key_func = lambda key: key.is_selection()),
       nyx.panel.KeyHandler('d', 'raw consensus descriptor', _show_descriptor),
-      nyx.panel.KeyHandler('s', 'sort ordering', self.show_sort_dialog),
+      nyx.panel.KeyHandler('s', 'sort ordering', self._show_sort_dialog),
       nyx.panel.KeyHandler('r', 'connection resolver', _pick_connection_resolver, 'auto' if resolver is None else resolver),
     ]
 
@@ -396,6 +397,25 @@ class ConnectionPanel(nyx.panel.DaemonPanel):
 
     return tuple(options)
 
+  def submenu(self):
+    """
+    Submenu consisting of...
+
+      Sorting...
+      Resolver (Submenu)
+    """
+
+    tracker = nyx.tracker.get_connection_tracker()
+    resolver_group = RadioGroup(tracker.set_custom_resolver, tracker.get_custom_resolver())
+
+    return Submenu('Connections', [
+      MenuItem('Sorting...', self._show_sort_dialog),
+      Submenu('Resolver', [
+        RadioMenuItem('auto', resolver_group, None),
+        [RadioMenuItem(opt, resolver_group, opt) for opt in connection.Resolver],
+      ]),
+    ])
+
   def _draw(self, subwindow):
     controller = tor_controller()
     nyx_controller = nyx.controller.get_controller()
diff --git a/nyx/panel/graph.py b/nyx/panel/graph.py
index 9dd3244..492037e 100644
--- a/nyx/panel/graph.py
+++ b/nyx/panel/graph.py
@@ -15,6 +15,7 @@ Downloaded (0.0 B/sec):           Uploaded (0.0 B/sec):
 """
 
 import copy
+import functools
 import time
 
 import nyx.controller
@@ -25,6 +26,7 @@ import nyx.tracker
 
 from nyx import join, msg, tor_controller
 from nyx.curses import RED, GREEN, CYAN, BOLD, HIGHLIGHT
+from nyx.menu import MenuItem, Submenu, RadioMenuItem, RadioGroup
 from stem.control import EventType, Listener
 from stem.util import conf, enum, log, str_tools, system
 
@@ -413,7 +415,7 @@ class GraphPanel(nyx.panel.Panel):
 
     self._displayed_stat = None if CONFIG['features.graph.type'] == 'none' else CONFIG['features.graph.type']
     self._update_interval = CONFIG['features.graph.interval']
-    self._bounds = CONFIG['features.graph.bound']
+    self._bounds_type = CONFIG['features.graph.bound']
     self._graph_height = CONFIG['features.graph.height']
 
     self._accounting_stats = None
@@ -437,42 +439,9 @@ class GraphPanel(nyx.panel.Panel):
     controller.add_event_listener(self._update_stats, EventType.BW)
     controller.add_status_listener(lambda *args: self.redraw())
 
-  @property
-  def displayed_stat(self):
-    return self._displayed_stat
-
-  @displayed_stat.setter
-  def displayed_stat(self, value):
-    if value is not None and value not in self._stats.keys():
-      raise ValueError("%s isn't a graphed statistic" % value)
-
-    self._displayed_stat = value
-
   def stat_options(self):
     return self._stats.keys()
 
-  @property
-  def update_interval(self):
-    return self._update_interval
-
-  @update_interval.setter
-  def update_interval(self, value):
-    if value not in Interval:
-      raise ValueError("%s isn't a valid graphing update interval" % value)
-
-    self._update_interval = value
-
-  @property
-  def bounds_type(self):
-    return self._bounds
-
-  @bounds_type.setter
-  def bounds_type(self, value):
-    if value not in Bounds:
-      raise ValueError("%s isn't a valid type of bounds" % value)
-
-    self._bounds = value
-
   def get_height(self):
     """
     Provides the height of the content.
@@ -480,14 +449,14 @@ class GraphPanel(nyx.panel.Panel):
 
     max_height = nyx.panel.Panel.get_height(self)
 
-    if not self.displayed_stat:
+    if not self._displayed_stat:
       return 0
 
     nyx_controller = nyx.controller.get_controller()
     height = DEFAULT_CONTENT_HEIGHT + self._graph_height
     accounting_stats = self._accounting_stats if nyx_controller.is_paused() else self._accounting_stats_paused
 
-    if self.displayed_stat == GraphStat.BANDWIDTH and accounting_stats:
+    if self._displayed_stat == GraphStat.BANDWIDTH and accounting_stats:
       height += 3
 
     return min(max_height, height)
@@ -495,7 +464,7 @@ class GraphPanel(nyx.panel.Panel):
   def set_graph_height(self, new_graph_height):
     self._graph_height = max(1, new_graph_height)
 
-  def resize_graph(self):
+  def _resize_graph(self):
     """
     Prompts for user input to resize the graph panel. Options include...
 
@@ -534,48 +503,72 @@ class GraphPanel(nyx.panel.Panel):
     def _pick_stats():
       available_stats = sorted(self.stat_options())
       options = ['None'] + [stat.capitalize() for stat in available_stats]
-      previous_selection = options[available_stats.index(self.displayed_stat) + 1] if self.displayed_stat else 'None'
+      previous_selection = options[available_stats.index(self._displayed_stat) + 1] if self._displayed_stat else 'None'
 
       selection = nyx.popups.select_from_list('Graphed Stats:', options, previous_selection)
-      self.displayed_stat = None if selection == 'None' else available_stats[options.index(selection) - 1]
+      self._displayed_stat = None if selection == 'None' else available_stats[options.index(selection) - 1]
 
     def _next_bounds():
-      self.bounds_type = Bounds.next(self.bounds_type)
+      self._bounds_type = Bounds.next(self._bounds_type)
       self.redraw()
 
     def _pick_interval():
-      self.update_interval = nyx.popups.select_from_list('Update Interval:', list(Interval), self.update_interval)
+      self._update_interval = nyx.popups.select_from_list('Update Interval:', list(Interval), self._update_interval)
       self.redraw()
 
     return (
-      nyx.panel.KeyHandler('g', 'resize graph', self.resize_graph),
-      nyx.panel.KeyHandler('s', 'graphed stats', _pick_stats, self.displayed_stat if self.displayed_stat else 'none'),
-      nyx.panel.KeyHandler('b', 'graph bounds', _next_bounds, self.bounds_type.replace('_', ' ')),
-      nyx.panel.KeyHandler('i', 'graph update interval', _pick_interval, self.update_interval),
+      nyx.panel.KeyHandler('g', 'resize graph', self._resize_graph),
+      nyx.panel.KeyHandler('s', 'graphed stats', _pick_stats, self._displayed_stat if self._displayed_stat else 'none'),
+      nyx.panel.KeyHandler('b', 'graph bounds', _next_bounds, self._bounds_type.replace('_', ' ')),
+      nyx.panel.KeyHandler('i', 'graph update interval', _pick_interval, self._update_interval),
     )
 
+  def submenu(self):
+    """
+    Submenu consisting of...
+
+      [X] <Stat 1>
+      [ ] <Stat 2>
+      [ ] <Stat 2>
+          Resize...
+          Interval (Submenu)
+          Bounds (Submenu)
+    """
+
+    stat_group = RadioGroup(functools.partial(setattr, self, '_displayed_stat'), self._displayed_stat)
+    interval_group = RadioGroup(functools.partial(setattr, self, '_update_interval'), self._update_interval)
+    bounds_group = RadioGroup(functools.partial(setattr, self, '_bounds_type'), self._bounds_type)
+
+    return Submenu('Graph', [
+      RadioMenuItem('None', stat_group, None),
+      [RadioMenuItem(str_tools._to_camel_case(opt, divider = ' '), stat_group, opt) for opt in sorted(self.stat_options())],
+      MenuItem('Resize...', self._resize_graph),
+      Submenu('Interval', [RadioMenuItem(opt, interval_group, opt) for opt in Interval]),
+      Submenu('Bounds', [RadioMenuItem(opt, bounds_group, opt) for opt in Bounds]),
+    ])
+
   def set_paused(self, is_pause):
     if is_pause:
       self._accounting_stats_paused = copy.copy(self._accounting_stats)
       self._stats_paused = dict([(key, type(self._stats[key])(self._stats[key])) for key in self._stats])
 
   def _draw(self, subwindow):
-    if not self.displayed_stat:
+    if not self._displayed_stat:
       return
 
     nyx_controller = nyx.controller.get_controller()
 
     if not nyx_controller.is_paused():
-      stat = self._stats[self.displayed_stat]
+      stat = self._stats[self._displayed_stat]
       accounting_stats = self._accounting_stats
     else:
-      stat = self._stats_paused[self.displayed_stat]
+      stat = self._stats_paused[self._displayed_stat]
       accounting_stats = self._accounting_stats_paused
 
     stat = type(stat)(stat)  # clone the GraphCategory
     subgraph_height = self._graph_height + 2  # graph rows + header + x-axis label
     subgraph_width = min(subwindow.width / 2, CONFIG['features.graph.max_width'])
-    interval, bounds_type = self.update_interval, self.bounds_type
+    interval, bounds_type = self._update_interval, self._bounds_type
 
     subwindow.addstr(0, 0, stat.title(subwindow.width), HIGHLIGHT)
 
@@ -604,9 +597,9 @@ class GraphPanel(nyx.panel.Panel):
     for stat in self._stats.values():
       stat.bandwidth_event(event)
 
-    if self.displayed_stat:
-      param = self._stats[self.displayed_stat]
-      update_rate = INTERVAL_SECONDS[self.update_interval]
+    if self._displayed_stat:
+      param = self._stats[self._displayed_stat]
+      update_rate = INTERVAL_SECONDS[self._update_interval]
 
       if param.primary.tick % update_rate == 0:
         self.redraw()
diff --git a/nyx/panel/log.py b/nyx/panel/log.py
index 502e383..ec9e238 100644
--- a/nyx/panel/log.py
+++ b/nyx/panel/log.py
@@ -7,6 +7,7 @@ for. This provides prepopulation from the log file and supports filtering by
 regular expressions.
 """
 
+import functools
 import os
 import time
 
@@ -21,6 +22,7 @@ import nyx.log
 
 from nyx import join, tor_controller
 from nyx.curses import GREEN, YELLOW, WHITE, NORMAL, BOLD, HIGHLIGHT
+from nyx.menu import MenuItem, Submenu, RadioMenuItem, RadioGroup
 from stem.util import conf, log
 
 
@@ -111,33 +113,7 @@ class LogPanel(nyx.panel.DaemonPanel):
 
     NYX_LOGGER.emit = self._register_nyx_event
 
-  def is_duplicates_visible(self):
-    """
-    Checks if duplicate log entries are collapsed or not.
-
-    :returns: **True** if duplicates are shown and **False** otherwise
-    """
-
-    return self._show_duplicates
-
-  def set_duplicate_visability(self, is_visible):
-    """
-    Sets if duplicate log entries are collaped or expanded.
-
-    :param bool is_visible: if **True** all log entries are shown, otherwise
-      they're deduplicated
-    """
-
-    self._show_duplicates = is_visible
-
-  def get_filter(self):
-    """
-    Provides our currently selected regex filter.
-    """
-
-    return self._filter
-
-  def show_filter_prompt(self):
+  def _show_filter_prompt(self):
     """
     Prompts the user to add a new regex filter.
     """
@@ -147,10 +123,9 @@ class LogPanel(nyx.panel.DaemonPanel):
     if regex_input:
       self._filter.select(regex_input)
 
-  def show_event_selection_prompt(self):
+  def _show_event_selection_prompt(self):
     """
     Prompts the user to select the events being listened for.
-    TODO: Replace show_event_selection_prompt() with this method.
     """
 
     event_types = nyx.popups.select_event_types(self._event_types)
@@ -159,7 +134,7 @@ class LogPanel(nyx.panel.DaemonPanel):
       self._event_types = nyx.log.listen_for_events(self._register_tor_event, event_types)
       self.redraw()
 
-  def show_snapshot_prompt(self):
+  def _show_snapshot_prompt(self):
     """
     Lets user enter a path to take a snapshot, canceling if left blank.
     """
@@ -173,7 +148,7 @@ class LogPanel(nyx.panel.DaemonPanel):
       except IOError as exc:
         nyx.controller.show_message('Unable to save snapshot: %s' % exc, HIGHLIGHT, max_wait = 2)
 
-  def clear(self):
+  def _clear(self):
     """
     Clears the contents of the event log.
     """
@@ -231,12 +206,12 @@ class LogPanel(nyx.panel.DaemonPanel):
         if selection == 'None':
           self._filter.select(None)
         elif selection == 'New...':
-          self.show_filter_prompt()  # prompt user to input regular expression
+          self._show_filter_prompt()  # prompt user to input regular expression
         else:
           self._filter.select(selection)
 
     def _toggle_deduplication():
-      self.set_duplicate_visability(not self.is_duplicates_visible())
+      self._show_duplicates = not self._show_duplicates
       self.redraw()
 
     def _clear_log():
@@ -244,17 +219,43 @@ class LogPanel(nyx.panel.DaemonPanel):
       key_press = nyx.controller.show_message(msg, BOLD, max_wait = 30)
 
       if key_press.match('c'):
-        self.clear()
+        self._clear()
 
     return (
       nyx.panel.KeyHandler('arrows', 'scroll up and down', _scroll, key_func = lambda key: key.is_scroll()),
-      nyx.panel.KeyHandler('a', 'save snapshot of the log', self.show_snapshot_prompt),
-      nyx.panel.KeyHandler('e', 'change logged events', self.show_event_selection_prompt),
+      nyx.panel.KeyHandler('a', 'save snapshot of the log', self._show_snapshot_prompt),
+      nyx.panel.KeyHandler('e', 'change logged events', self._show_event_selection_prompt),
       nyx.panel.KeyHandler('f', 'log regex filter', _pick_filter, 'enabled' if self._filter.selection() else 'disabled'),
-      nyx.panel.KeyHandler('u', 'duplicate log entries', _toggle_deduplication, 'visible' if self.is_duplicates_visible() else 'hidden'),
+      nyx.panel.KeyHandler('u', 'duplicate log entries', _toggle_deduplication, 'visible' if self._show_duplicates else 'hidden'),
       nyx.panel.KeyHandler('c', 'clear event log', _clear_log),
     )
 
+  def submenu(self):
+    """
+    Submenu consisting of...
+
+      Events...
+      Snapshot...
+      Clear
+      Show / Hide Duplicates
+      Filter (Submenu)
+    """
+
+    filter_group = RadioGroup(self._filter.select, self._filter.selection())
+    duplicates_label, duplicates_arg = ('Hide Duplicates', False) if self._show_duplicates else ('Show Duplicates', True)
+
+    return Submenu('Log', [
+      MenuItem('Events...', self._show_event_selection_prompt),
+      MenuItem('Snapshot...', self._show_snapshot_prompt),
+      MenuItem('Clear', self._clear),
+      MenuItem(duplicates_label, functools.partial(setattr, self, '_show_duplicates'), duplicates_arg),
+      Submenu('Filter', [
+        RadioMenuItem('None', filter_group, None),
+        [RadioMenuItem(opt, filter_group, opt) for opt in self._filter.latest_selections()],
+        MenuItem('New...', self._show_filter_prompt),
+      ]),
+    ])
+
   def set_paused(self, is_pause):
     if is_pause:
       self._event_log_paused = self._event_log.clone()
diff --git a/nyx/panel/torrc.py b/nyx/panel/torrc.py
index 0bdaf2c..d5e890e 100644
--- a/nyx/panel/torrc.py
+++ b/nyx/panel/torrc.py
@@ -5,12 +5,14 @@
 Panel displaying the torrc or nyxrc with the validation done against it.
 """
 
+import functools
 import math
 import string
 
 import nyx.curses
 
 from nyx.curses import RED, GREEN, YELLOW, CYAN, WHITE, BOLD, HIGHLIGHT
+from nyx.menu import MenuItem, Submenu
 from nyx import expand_path, msg, panel, tor_controller
 
 from stem import ControllerError
@@ -68,26 +70,6 @@ class TorrcPanel(panel.Panel):
         self._torrc_load_error = msg('panel.torrc.unable_to_load_torrc', error = exc_msg)
         self._torrc_content = None
 
-  def set_comments_visible(self, is_visible):
-    """
-    Sets if comments and blank lines are shown or stripped.
-
-    :var bool is_visible: shows comments if true, strips otherwise
-    """
-
-    self._show_comments = is_visible
-    self.redraw()
-
-  def set_line_number_visible(self, is_visible):
-    """
-    Sets if line numbers are shown or hidden.
-
-    :var bool is_visible: displays line numbers if true, hides otherwise
-    """
-
-    self._show_line_numbers = is_visible
-    self.redraw()
-
   def key_handlers(self):
     def _scroll(key):
       page_height = self.get_height() - 1
@@ -97,10 +79,10 @@ class TorrcPanel(panel.Panel):
         self.redraw()
 
     def _toggle_comment_stripping():
-      self.set_comments_visible(not self._show_comments)
+      self._show_comments = not self._show_comments
 
     def _toggle_line_numbers():
-      self.set_line_number_visible(not self._show_line_numbers)
+      self._show_line_numbers = not self._show_line_numbers
 
     return (
       nyx.panel.KeyHandler('arrows', 'scroll up and down', _scroll, key_func = lambda key: key.is_scroll()),
@@ -108,6 +90,23 @@ class TorrcPanel(panel.Panel):
       nyx.panel.KeyHandler('l', 'line numbering', _toggle_line_numbers, 'on' if self._show_line_numbers else 'off'),
     )
 
+  def submenu(self):
+    """
+    Submenu consisting of...
+
+      Reload
+      Show / Hide Comments
+      Show / Hide Line Numbers
+    """
+
+    comments_label, comments_arg = ('Hide Comments', False) if self._show_comments else ('Show Comments', True)
+    line_number_label, line_number_arg = ('Hide Line Numbers', False) if self._show_line_numbers else ('Show Line Numbers', True)
+
+    return Submenu('Torrc', [
+      MenuItem(comments_label, functools.partial(setattr, self, '_show_comments'), comments_arg),
+      MenuItem(line_number_label, functools.partial(setattr, self, '_show_line_numbers'), line_number_arg),
+    ])
+
   def _draw(self, subwindow):
     scroll = self._scroller.location(self._last_content_height, subwindow.height - 1)
 



_______________________________________________
tor-commits mailing list
tor-commits@xxxxxxxxxxxxxxxxxxxx
https://lists.torproject.org/cgi-bin/mailman/listinfo/tor-commits