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