Push GUI config setting changes to the engine process' Hooke.
[hooke.git] / hooke / ui / __init__.py
index 1f2bd4e2cf536fabb10c5e24d741441011f6e7b0..cfdac7293bbc07ceb28cafa9cadd6597c081b7e6 100644 (file)
@@ -1,17 +1,44 @@
+# Copyright (C) 2010 W. Trevor King <wking@drexel.edu>
+#
+# This file is part of Hooke.
+#
+# Hooke is free software: you can redistribute it and/or modify it
+# under the terms of the GNU Lesser General Public License as
+# published by the Free Software Foundation, either version 3 of the
+# License, or (at your option) any later version.
+#
+# Hooke is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+# or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General
+# Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with Hooke.  If not, see
+# <http://www.gnu.org/licenses/>.
+
 """The `ui` module provides :class:`UserInterface` and various subclasses.
 """
 
 import ConfigParser as configparser
+import logging
 
 from .. import version
-from ..compat.odict import odict
 from ..config import Setting
-from ..util.pluggable import IsSubclass
+from ..engine import CommandMessage
+from ..util.pluggable import IsSubclass, construct_odict
+
+try:
+    from ..license import short_license
+except ImportError, e:
+    logging.warn('could not load short_license from hooke.license')
+    from .. import __license__
+    def short_license(extra_info, **kwargs):
+        return __license__
 
 
 USER_INTERFACE_MODULES = [
     'commandline',
-    #'gui',
+    'gui',
     ]
 """List of user interface modules.  TODO: autodiscovery
 """
@@ -21,23 +48,6 @@ USER_INTERFACE_SETTING_SECTION = 'user interfaces'
 """
 
 
-class QueueMessage (object):
-    def __str__(self):
-        return self.__class__.__name__
-
-class CloseEngine (QueueMessage):
-    pass
-
-class CommandMessage (QueueMessage):
-    """A message storing a command to run, `command` should be a
-    :class:`hooke.command.Command` instance, and `arguments` should be
-    a :class:`dict` with `argname` keys and `value` values to be
-    passed to the command.
-    """
-    def __init__(self, command, arguments):
-        self.command = command
-        self.arguments = arguments
-
 class UserInterface (object):
     """A user interface to drive the :class:`hooke.engine.CommandEngine`.
     """
@@ -60,54 +70,54 @@ class UserInterface (object):
         """Update the user interface for new config settings.
 
         Should be called with the new `config` upon recipt of
-        `ReloadUserInterfaceConfig` from the `CommandEngine`.
+        `ReloadUserInterfaceConfig` from the `CommandEngine` or when
+        loading the initial configuration.
         """
         try:
             self.config = dict(config.items(self.setting_section))
         except configparser.NoSectionError:
             self.config = {}
 
-    def run(self, hooke, ui_to_command_queue, command_to_ui_queue):
+    def run(self, commands, ui_to_command_queue, command_to_ui_queue):
         return
 
     # Assorted useful tidbits for subclasses
 
-    def _splash_text(self):
+    def _submit_command(self, command_message, ui_to_command_queue):
+        log = logging.getLogger('hooke')
+        log.debug('executing %s' % command_message)
+        ui_to_command_queue.put(command_message)
+
+    def _set_config(self, option, value, ui_to_command_queue, response_handler,
+                     section=None):
+        if section == None:
+            section = self.setting_section
+        if section in [self.setting_section, 'conditions']:
+            if self.config[option] == value:
+                return  # No change, so no need to push the new value.
+            self.config[option] = value
+        cm = CommandMessage(
+            command='set config',
+            arguments={'section': section, 'option': option, 'value': value})
+        self._submit_command(command_message=cm,
+                             ui_to_command_queue=ui_to_command_queue)
+        response_handler(command_message=cm)
+
+    def _splash_text(self, extra_info, **kwargs):
         return ("""
 Hooke version %s
 
-COPYRIGHT
+%s
 ----
-""" % version()).strip()
+""" % (version(), short_license(extra_info, **kwargs))).strip()
 
     def _playlist_status(self, playlist):
         if len(playlist) > 0:
-            return '%s (%s/%s)' % (playlist.name, playlist._index + 1,
+            return '%s (%s/%s)' % (playlist.name, playlist.index() + 1,
                                    len(playlist))
         return 'The playlist %s does not contain any valid force curve data.' \
             % self.name
 
-def construct_odict(this_modname, submodnames, class_selector):
-    """Search the submodules `submodnames` of a module `this_modname`
-    for class objects for which `class_selector(class)` returns
-    `True`.  These classes are instantiated and stored in the returned
-    :class:`hooke.compat.odict.odict` in the order in which they were
-    discovered.
-    """
-    instances = odict()
-    for submodname in submodnames:
-        count = len([s for s in submodnames if s == submodname])
-        assert count > 0, 'No %s entries: %s' % (submodname, submodnames)
-        assert count == 1, 'Multiple (%d) %s entries: %s' \
-            % (count, submodname, submodnames)
-        this_mod = __import__(this_modname, fromlist=[submodname])
-        submod = getattr(this_mod, submodname)
-        for objname in dir(submod):
-            obj = getattr(submod, objname)
-            if class_selector(obj):
-                instance = obj()
-                instances[instance.name] = instance
-    return instances
 
 USER_INTERFACES = construct_odict(
     this_modname=__name__,
@@ -135,8 +145,5 @@ def load_ui(config, name=None):
         assert len(uis) == 1, 'Can only select one UI, not %d: %s' % (len(uis),uis)
         name = uis[0]
     ui = USER_INTERFACES[name]
-    try:
-        ui.config = dict(config.items(ui.setting_section))
-    except configparser.NoSectionError:
-        pass
+    ui.reload_config(config)
     return ui