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  from libxyz.core.utils import typer 
 23   
 24  from libxyz.ui import Shortcut 
 25   
 26  from libxyz.exceptions import PluginError 
 27  from libxyz.exceptions import KeyManagerError 
28 29 -class KeyManager(object):
30 """ 31 Key bindings management class 32 """ 33 34 CONTEXT_DEFAULT = u"DEFAULT" 35 CONTEXT_SELF = u"@" 36
37 - def __init__(self, xyz):
38 self.xyz = xyz 39 self.keys = libxyz.ui.Keys() 40 41 self._loaded_methods = {} 42 self._bind_data = {} 43 self._prefixes = []
44 45 #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 46
47 - def process(self, pressed, context=None):
48 """ 49 Process pressed keys 50 51 @return: Tuple (method, arguments) 52 """ 53 54 context = context or self.CONTEXT_DEFAULT 55 _p = Shortcut(raw=pressed) 56 57 # Got prefix key. Now wait for another keystroke and proceed 58 if _p in self._prefixes: 59 _aux = self.xyz.input.get() 60 _p = Shortcut(raw=pressed + _aux) 61 62 _method = None 63 64 # Look for binded shortcut 65 try: 66 _method = self._bind_data[context][_p] 67 except KeyError: 68 # No bind 69 pass 70 71 return _method
72 73 #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 74
75 - def set_prefix(self, shortcut):
76 """ 77 Set prefix key 78 """ 79 80 if not isinstance(shortcut, Shortcut): 81 raise KeyManagerError(_(u"Invalid shortcut type: %s.") % 82 ustring(type(shortcut))) 83 84 if shortcut not in self._prefixes: 85 self._prefixes.append(shortcut)
86 87 #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 88 89 @typer(None, Shortcut)
90 - def is_prefix(self, shortcut):
91 """ 92 Check if provided shortcut is a prefix 93 """ 94 95 return shortcut in self._prefixes
96 97 #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 98
99 - def load(self, method):
100 """ 101 Load method 102 """ 103 104 _p = Namespace(method) 105 106 # Already loaded 107 if _p.full in self._loaded_methods: 108 return 109 110 # Wildcard 111 if _p.method == _p.ALL: 112 self._loaded_methods[_p.full] = _p.ALL 113 # Just load and instantiate plugin 114 elif _p.method is None: 115 self.xyz.pm.load(_p) 116 else: 117 self._loaded_methods[_p.full] = self.xyz.pm.from_load(_p.pfull, 118 _p.method)
119 120 #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 121
122 - def bind(self, method, shortcut, context=None):
123 """ 124 Bind a shortcut to a method. 125 A method can be either a string, in that case it should denote the 126 plugin method or it can be a function or it can be a tuple with two 127 elements: first - function to bind and the second - string description 128 129 @return: True on success, False otherwise, also raises exception 130 if method was not loaded 131 """ 132 133 if isinstance(method, basestring): 134 _p = Namespace(method) 135 _mobj = None 136 137 if context == self.CONTEXT_SELF: 138 context = _p.pfull 139 140 # First check if methods were loaded by wildcard ALL 141 if _p.full not in self._loaded_methods: 142 if "%s:%s" % (_p.pfull, _p.ALL) not in self._loaded_methods: 143 raise KeyManagerError(_(u"Method %s not loaded") % _p) 144 145 # Else try to load specified method 146 try: 147 _mobj = self.xyz.pm.from_load(_p.pfull, _p.method) 148 except PluginError, e: 149 raise KeyManagerError(_(u"Load error: %s") % e) 150 else: 151 _mobj = self._loaded_methods[_p.full] 152 153 if _mobj is None: 154 # Wait until plugin method is available and then run callback 155 self.xyz.pm.wait_for(_p, self._bind_wait_cb, _p.method, 156 shortcut, context) 157 158 elif is_func(method): 159 _mobj = method 160 _mobj.ns = _(u"<Internal function object>") 161 elif isinstance(method, tuple) and len(method) == 2: 162 _mobj = method[0] 163 _mobj.ns = method[1] 164 else: 165 raise KeyManagerError(_(u"Invalid method type: %s. "\ 166 u"Must be string or function") % 167 type(method)) 168 169 self._bind(_mobj, shortcut, context)
170 171 #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 172
173 - def _bind_wait_cb(self, plugin_obj, method, shortcut, context):
174 if method not in plugin_obj.public: 175 xyzlog.error(_(u"Unable to bind method %s. "\ 176 u"Plugin %s doesn't export it.") % 177 (method, plugin_obj.ns.pfull)) 178 return 179 180 self._bind(plugin_obj.public[method], shortcut, context, force=False)
181 182 #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 183
184 - def _bind(self, mobj, shortcut, context=None, force=True):
185 if context is None: 186 context = self.CONTEXT_DEFAULT 187 188 if context not in self._bind_data: 189 self._bind_data[context] = {} 190 191 if shortcut in self._bind_data[context] and \ 192 self._bind_data[context][shortcut] is not None and not force: 193 return 194 195 self._bind_data[context][shortcut] = mobj
196 197 #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 198
199 - def get_binds(self):
200 """ 201 Return keybindings data 202 """ 203 204 return self._bind_data
205 206 #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 207 208 @typer(None, Shortcut, basestring)
209 - def get_method_by_key(self, sc, context=None):
210 """ 211 Find a method that a provided shortcut is bound to 212 """ 213 214 return self._bind_data[context or self.CONTEXT_DEFAULT].get(sc, None)
215