4 from __future__ import with_statement
12 from util import qtpieboard
17 class CommandStackHandler(object):
19 def __init__(self, stack, command, operator):
20 self.command = command
23 self.__operator = operator
25 def handler(self, commandName, activeModifiers):
26 self.__stack.apply_operation(self.__operator)
29 class PieKeyboardPlugin(object):
31 def __init__(self, name, factory):
33 self.factory = factory
36 def setup(self, calcStack, boardHandler):
37 self.__handler = boardHandler
39 boardTree = self.factory.map
41 keyboardName = boardTree["name"]
42 keyTree = boardTree["keys"]
44 keyboard = qtpieboard.PieKeyboard()
45 qtpieboard.load_keyboard(keyboardName, keyTree, keyboard, self.__handler, self.factory.iconPaths)
47 for commandName, operator in self.factory.commands.iteritems():
48 handler = CommandStackHandler(calcStack, commandName, operator)
49 self.__handler.register_command_handler(commandName, handler.handler)
54 for commandName, operator in self.factory.commands.itervalues():
55 self.__handler.unregister_command_handler(commandName)
57 # Leave our self completely unusable
63 class PieKeyboardPluginFactory(object):
65 def __init__(self, pluginName, icon, keyboardMap, iconPaths):
66 self.name = pluginName
67 self.map = keyboardMap
70 self.iconPaths = iconPaths
72 def register_operation(self, commandName, operator):
73 self.commands[commandName] = operator
75 def construct_keyboard(self):
76 plugin = PieKeyboardPlugin(self.name, self)
80 class PluginManager(object):
82 def __init__(self, pluginType):
83 self._pluginType = pluginType
87 self.__searchPaths = []
89 def add_path(self, *paths):
90 self.__searchPaths.append(paths)
95 self.__scan(self.__searchPaths)
97 def plugin_info(self, pluginId):
98 pluginData = self._plugins[pluginId]
99 return pluginData["name"], pluginData["version"], pluginData["description"]
102 for id, pluginData in self._plugins.iteritems():
103 yield id, pluginData["name"], pluginData["version"], pluginData["description"]
105 def enable_plugin(self, id):
106 assert id in self._plugins, "Can't find plugin %s in the search path %r" % (id, self.__searchPaths)
107 self._load_module(id)
108 self._enabled.add(id)
110 def disable_plugin(self, id):
111 self._enabled.remove(id)
113 def lookup_plugin(self, name):
114 for id, data in self._plugins.iteritems():
115 if data["name"] == name:
118 def _load_module(self, id):
119 pluginData = self._plugins[id]
121 if "module" not in pluginData:
122 pluginPath = pluginData["pluginpath"]
123 dataPath = pluginData["datapath"]
124 assert dataPath.endswith(".ini")
126 dataPath = io.relpath(pluginPath, dataPath)
127 pythonPath = dataPath[0:-len(".ini")]
128 modulePath = fspath_to_ipath(pythonPath, "")
130 sys.path.append(pluginPath)
132 module = __import__(modulePath)
134 sys.path.remove(pluginPath)
135 pluginData["module"] = module
137 # @todo Decide if want to call reload
138 module = pluginData["module"]
142 def __scan(self, paths):
143 pluginDataFiles = find_plugins(paths, ".ini")
145 for pluginPath, pluginDataFile in pluginDataFiles:
146 config = ConfigParser.SafeConfigParser()
147 config.read(pluginDataFile)
149 name = config.get(self._pluginType, "name")
150 version = config.get(self._pluginType, "version")
151 description = config.get(self._pluginType, "description")
153 self._plugins[pluginDataFile] = {
156 "description": description,
157 "datapath": pluginDataFile,
158 "pluginpath": pluginPath,
162 class ConstantPluginManager(PluginManager):
165 super(ConstantPluginManager, self).__init__("Constants")
166 self.__constants = {}
167 self.__constantsCache = {}
168 self.__isCacheDirty = False
170 def enable_plugin(self, id):
171 super(ConstantPluginManager, self).enable_plugin(id)
172 self.__constants[id] = dict(
173 extract_instance_from_plugin(self._plugins[id]["module"], operation.Operation)
175 self.__isCacheDirty = True
177 def disable_plugin(self, id):
178 super(ConstantPluginManager, self).disable_plugin(id)
179 self.__isCacheDirty = True
183 if self.__isCacheDirty:
184 self.__update_cache()
185 return self.__constantsCache
187 def __update_cache(self):
188 self.__constantsCache.clear()
189 for pluginId in self._enabled:
190 self.__constantsCache.update(self.__constants[pluginId])
191 self.__isCacheDirty = False
194 class OperatorPluginManager(PluginManager):
197 super(OperatorPluginManager, self).__init__("Operator")
198 self.__operators = {}
199 self.__operatorsCache = {}
200 self.__isCacheDirty = False
202 def enable_plugin(self, id):
203 super(OperatorPluginManager, self).enable_plugin(id)
205 extract_class_from_plugin(self._plugins[id]["module"], operation.Operation)
207 self.__operators[id] = dict(
211 self.__isCacheDirty = True
213 def disable_plugin(self, id):
214 super(OperatorPluginManager, self).disable_plugin(id)
215 self.__isCacheDirty = True
219 if self.__isCacheDirty:
220 self.__update_cache()
221 return self.__operatorsCache
223 def __update_cache(self):
224 self.__operatorsCache.clear()
225 for pluginId in self._enabled:
226 self.__operatorsCache.update(self.__operators[pluginId])
227 self.__isCacheDirty = False
230 class KeyboardPluginManager(PluginManager):
233 super(KeyboardPluginManager, self).__init__("Keyboard")
234 self.__keyboards = {}
235 self.__keyboardsCache = {}
236 self.__isCacheDirty = False
238 def enable_plugin(self, id):
239 super(KeyboardPluginManager, self).enable_plugin(id)
241 extract_instance_from_plugin(self._plugins[id]["module"], PieKeyboardPluginFactory)
243 self.__keyboards[id] = dict(
245 for boardVariableName, board in keyboards
247 self.__isCacheDirty = True
249 def disable_plugin(self, id):
250 super(KeyboardPluginManager, self).disable_plugin(id)
251 self.__isCacheDirty = True
255 if self.__isCacheDirty:
256 self.__update_cache()
257 return self.__keyboardsCache
259 def __update_cache(self):
260 self.__keyboardsCache.clear()
261 for pluginId in self._enabled:
262 self.__keyboardsCache.update(self.__keyboards[pluginId])
263 self.__isCacheDirty = False
266 def fspath_to_ipath(fsPath, extension = ".py"):
268 >>> fspath_to_ipath("user/test/file.py")
271 assert fsPath.endswith(extension)
272 CURRENT_DIR = "."+os.sep
273 CURRENT_DIR_LEN = len(CURRENT_DIR)
274 if fsPath.startswith(CURRENT_DIR):
275 fsPath = fsPath[CURRENT_DIR_LEN:]
278 fsPath = fsPath[0:-len(extension)]
279 parts = fsPath.split(os.sep)
280 return ".".join(parts)
283 def find_plugins(searchPaths, fileType=".py"):
285 (path, os.path.join(root, file))
286 for path in searchPaths
287 for root, dirs, files in os.walk(path)
289 if file.endswith(fileType)
294 def extract_class_from_plugin(pluginModule, cls):
296 for item in pluginModule.__dict__.itervalues():
298 if cls in inspect.getmro(item):
300 except AttributeError:
302 except AttributeError:
306 def extract_instance_from_plugin(pluginModule, cls):
308 for name, item in pluginModule.__dict__.iteritems():
310 if isinstance(item, cls):
312 except AttributeError:
314 except AttributeError: