Package libxyz :: Package core :: Module keymanager |
[hide private]
[frames] | no frames]

# Source Code for Module libxyz.core.keymanager

      1  #-*- coding: utf8 -*
      2  #
      3  # Max E. Kuznecov ~syhpoon <syhpoon@syhpoon.name> 2008
      4  #
      5  # This file is part of XYZCommander.
      6  # XYZCommander is free software: you can redistribute it and/or modify
      7  # it under the terms of the GNU Lesser Public License as published by
      8  # the Free Software Foundation, either version 3 of the License, or
      9  # (at your option) any later version.
     10  # XYZCommander is distributed in the hope that it will be useful,
     11  # but WITHOUT ANY WARRANTY; without even the implied warranty of
     12  # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
     13  # GNU Lesser Public License for more details.
     14  # You should have received a copy of the GNU Lesser Public License
     15  # along with XYZCommander. If not, see <http://www.gnu.org/licenses/>.
     16
     17  import libxyz
     18
     19  from libxyz.core.plugins import Namespace
     20  from libxyz.core.utils import ustring
     21  from libxyz.core.utils import is_func
     22
     23  from libxyz.ui import Shortcut
     24
     25  from libxyz.exceptions import PluginError
     26  from libxyz.exceptions import KeyManagerError
     27
     28 -class KeyManager(object):
     29      """
     30      Key bindings management class
     31      """
     32
     33      CONTEXT_DEFAULT = u"DEFAULT"
     34      CONTEXT_SELF = u"@"
     35
     36 -    def __init__(self, xyz):
     37          self.xyz = xyz
     38          self.keys = libxyz.ui.Keys()
     39
     40          self._loaded_methods = {}
     41          self._bind_data = {}
     42          self._prefixes = []
     43
     44      #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     45
     46 -    def process(self, pressed, context=None):
     47          """
     48          Process pressed keys
     49
     50          @return: Tuple (method, arguments)
     51          """
     52
     53          context = context or self.CONTEXT_DEFAULT
     54          _p = Shortcut(raw=pressed)
     55
     56          # Got prefix key. Now wait for another keystroke and proceed
     57          if _p in self._prefixes:
     58              _aux = self.xyz.input.get()
     59              _p = Shortcut(raw=pressed + _aux)
     60
     61          _method = None
     62
     63          # Look for binded shortcut
     64          try:
     65              _method = self._bind_data[context][_p]
     66          except KeyError:
     67              # No bind
     68              pass
     69
     70          return _method
     71
     72      #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     73
     74 -    def set_prefix(self, shortcut):
     75          """
     76          Set prefix key
     77          """
     78
     79          if not isinstance(shortcut, Shortcut):
     80              raise KeyManagerError(_(u"Invalid shortcut type: %s.") %
     81                                    ustring(type(shortcut)))
     82
     83          if shortcut not in self._prefixes:
     84              self._prefixes.append(shortcut)
     85
     86      #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     87
     88
     89 -    def load(self, method):
     90          """
     91          Load method
     92          """
     93
     94          _p = Namespace(method)
     95
     96          # Already loaded
     97          if _p.full in self._loaded_methods:
     98              return
     99
    100          # Wildcard
    101          if _p.method == _p.ALL:
    102              self._loaded_methods[_p.full] = _p.ALL
    103          # Just load and instantiate plugin
    104          elif _p.method is None:
    105              self.xyz.pm.load(_p)
    106          else:
    107              self._loaded_methods[_p.full] = self.xyz.pm.from_load(_p.pfull,
    108                                                                    _p.method)
    109
    110      #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    111
    112 -    def bind(self, method, shortcut, context=None):
    113          """
    114          Bind a shortcut to a method.
    115          A method can be either a string, in that case it should denote the
    116          plugin method or it can be a function.
    117
    118          @return: True on success, False otherwise, also raises exception
    119                   if method was not loaded
    120          """
    121
    122          if isinstance(method, basestring):
    123              _p = Namespace(method)
    124              _mobj = None
    125
    126              if context == self.CONTEXT_SELF:
    127                  context = _p.pfull
    128
    129              # First check if methods were loaded by wildcard ALL
    130              if _p.full not in self._loaded_methods:
    131                  if "%s:%s" % (_p.pfull, _p.ALL) not in self._loaded_methods:
    132                      raise KeyManagerError(_(u"Method %s not loaded" % _p))
    133
    134                  # Else try to load specified method
    135                  try:
    136                      _mobj = self.xyz.pm.from_load(_p.pfull, _p.method)
    137                  except PluginError, e:
    138                      raise KeyManagerError(_(u"Load error: %s" % e))
    139              else:
    140                  _mobj = self._loaded_methods[_p.full]
    141
    142              if _mobj is None:
    143                  # Wait until plugin method is available and then run callback
    144                  self.xyz.pm.wait_for(_p, self._bind_wait_cb, _p.method,
    145                                       shortcut, context)
    146
    147          elif is_func(method):
    148              _mobj = method
    149              _mobj.ns = _(u"<Internal function object>")
    150          else:
    151              raise KeyManagerError(_(u"Invalid method type: %s. "\
    152                                      u"Must be string or function") %
    153                                    type(method))
    154
    155          self._bind(_mobj, shortcut, context)
    156
    157      #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    158
    159 -    def _bind_wait_cb(self, plugin_obj, method, shortcut, context):
    160          if method not in plugin_obj.public:
    161              xyzlog.error(_(u"Unable to bind method %s. "\
    162                           u"Plugin %s doesn't export it." %
    163                           (method, plugin_obj.ns.pfull)))
    164              return
    165
    166          self._bind(plugin_obj.public[method], shortcut, context, force=False)
    167
    168      #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    169
    170 -    def _bind(self, mobj, shortcut, context=None, force=True):
    171          if context is None:
    172              context = self.CONTEXT_DEFAULT
    173
    174          if context not in self._bind_data:
    175              self._bind_data[context] = {}
    176
    177          if shortcut in self._bind_data[context] and \
    178          self._bind_data[context][shortcut] is not None and not force:
    179              return
    180
    181          self._bind_data[context][shortcut] = mobj
    182
    183      #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    184
    185 -    def get_binds(self):
    186          """
    187          Return keybindings data
    188          """
    189
    190          return self._bind_data
    191