4 from __future__ import with_statement
12 from libraries 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 with open(self.factory.mapFile, "r") as mapfile:
40 boardTree = qtpieboard.parse_keyboard_data("\n".join(mapfile.readlines()))
42 rows, columns = boardTree["dimensions"]
43 keyboardName = boardTree["name"]
44 keyTree = boardTree["keys"]
46 keyboard = qtpieboard.PieKeyboard(rows, columns)
47 qtpieboard.load_keyboard(keyboardName, keyTree, keyboard, self.__handler, self.factory.iconPaths)
49 for commandName, operator in self.factory.commands.iteritems():
50 handler = CommandStackHandler(calcStack, commandName, operator)
51 self.__handler.register_command_handler(commandName, handler.handler)
56 for commandName, operator in self.factory.commands.itervalues():
57 self.__handler.unregister_command_handler(commandName)
59 # Leave our self completely unusable
65 class PieKeyboardPluginFactory(object):
67 def __init__(self, pluginName, keyboardMapFile):
68 self.name = pluginName
69 self.mapFile = keyboardMapFile
71 self.iconPaths = [os.path.join(os.path.dirname(keyboardMapFile), "images")]
73 def register_operation(self, commandName, operator):
74 self.commands[commandName] = operator
76 def construct_keyboard(self):
77 plugin = PieKeyboardPlugin(self.name, self)
81 class PluginManager(object):
83 def __init__(self, pluginType):
84 self._pluginType = pluginType
88 self.__searchPaths = []
90 def add_path(self, *paths):
91 self.__searchPaths.append(paths)
96 self.__scan(self.__searchPaths)
98 def plugin_info(self, pluginId):
99 pluginData = self._plugins[pluginId]
100 return pluginData["name"], pluginData["version"], pluginData["description"]
103 for id, pluginData in self._plugins.iteritems():
104 yield id, pluginData["name"], pluginData["version"], pluginData["description"]
106 def enable_plugin(self, id):
107 assert id in self._plugins, "Can't find plugin %s in the search path %r" % (id, self.__searchPaths)
108 self._load_module(id)
109 self._enabled.add(id)
111 def disable_plugin(self, id):
112 self._enabled.remove(id)
114 def lookup_plugin(self, name):
115 for id, data in self._plugins.iteritems():
116 if data["name"] == name:
119 def _load_module(self, id):
120 pluginData = self._plugins[id]
122 if "module" not in pluginData:
123 pluginPath = pluginData["pluginpath"]
124 dataPath = pluginData["datapath"]
125 assert dataPath.endswith(".ini")
127 dataPath = io.relpath(pluginPath, dataPath)
128 pythonPath = dataPath[0:-len(".ini")]
129 modulePath = fspath_to_ipath(pythonPath, "")
131 sys.path.append(pluginPath)
133 module = __import__(modulePath)
135 sys.path.remove(pluginPath)
136 pluginData["module"] = module
138 # @todo Decide if want to call reload
139 module = pluginData["module"]
143 def __scan(self, paths):
144 pluginDataFiles = find_plugins(paths, ".ini")
146 for pluginPath, pluginDataFile in pluginDataFiles:
147 config = ConfigParser.SafeConfigParser()
148 config.read(pluginDataFile)
150 name = config.get(self._pluginType, "name")
151 version = config.get(self._pluginType, "version")
152 description = config.get(self._pluginType, "description")
154 self._plugins[pluginDataFile] = {
157 "description": description,
158 "datapath": pluginDataFile,
159 "pluginpath": pluginPath,
163 class ConstantPluginManager(PluginManager):
166 super(ConstantPluginManager, self).__init__("Constants")
167 self.__constants = {}
168 self.__constantsCache = {}
169 self.__isCacheDirty = False
171 def enable_plugin(self, id):
172 super(ConstantPluginManager, self).enable_plugin(id)
173 self.__constants[id] = dict(
174 extract_instance_from_plugin(self._plugins[id]["module"], operation.Operation)
176 self.__isCacheDirty = True
178 def disable_plugin(self, id):
179 super(ConstantPluginManager, self).disable_plugin(id)
180 self.__isCacheDirty = True
184 if self.__isCacheDirty:
185 self.__update_cache()
186 return self.__constantsCache
188 def __update_cache(self):
189 self.__constantsCache.clear()
190 for pluginId in self._enabled:
191 self.__constantsCache.update(self.__constants[pluginId])
192 self.__isCacheDirty = False
195 class OperatorPluginManager(PluginManager):
198 super(OperatorPluginManager, self).__init__("Operator")
199 self.__operators = {}
200 self.__operatorsCache = {}
201 self.__isCacheDirty = False
203 def enable_plugin(self, id):
204 super(OperatorPluginManager, self).enable_plugin(id)
206 extract_class_from_plugin(self._plugins[id]["module"], operation.Operation)
208 self.__operators[id] = dict(
212 self.__isCacheDirty = True
214 def disable_plugin(self, id):
215 super(OperatorPluginManager, self).disable_plugin(id)
216 self.__isCacheDirty = True
220 if self.__isCacheDirty:
221 self.__update_cache()
222 return self.__operatorsCache
224 def __update_cache(self):
225 self.__operatorsCache.clear()
226 for pluginId in self._enabled:
227 self.__operatorsCache.update(self.__operators[pluginId])
228 self.__isCacheDirty = False
231 class KeyboardPluginManager(PluginManager):
234 super(KeyboardPluginManager, self).__init__("Keyboard")
235 self.__keyboards = {}
236 self.__keyboardsCache = {}
237 self.__isCacheDirty = False
239 def enable_plugin(self, id):
240 super(KeyboardPluginManager, self).enable_plugin(id)
242 extract_instance_from_plugin(self._plugins[id]["module"], PieKeyboardPluginFactory)
244 self.__keyboards[id] = dict(
246 for boardVariableName, board in keyboards
248 self.__isCacheDirty = True
250 def disable_plugin(self, id):
251 super(KeyboardPluginManager, self).disable_plugin(id)
252 self.__isCacheDirty = True
256 if self.__isCacheDirty:
257 self.__update_cache()
258 return self.__keyboardsCache
260 def __update_cache(self):
261 self.__keyboardsCache.clear()
262 for pluginId in self._enabled:
263 self.__keyboardsCache.update(self.__keyboards[pluginId])
264 self.__isCacheDirty = False
267 def fspath_to_ipath(fsPath, extension = ".py"):
269 >>> fspath_to_ipath("user/test/file.py")
272 assert fsPath.endswith(extension)
273 CURRENT_DIR = "."+os.sep
274 CURRENT_DIR_LEN = len(CURRENT_DIR)
275 if fsPath.startswith(CURRENT_DIR):
276 fsPath = fsPath[CURRENT_DIR_LEN:]
279 fsPath = fsPath[0:-len(extension)]
280 parts = fsPath.split(os.sep)
281 return ".".join(parts)
284 def find_plugins(searchPaths, fileType=".py"):
286 (path, os.path.join(root, file))
287 for path in searchPaths
288 for root, dirs, files in os.walk(path)
290 if file.endswith(fileType)
295 def extract_class_from_plugin(pluginModule, cls):
297 for item in pluginModule.__dict__.itervalues():
299 if cls in inspect.getmro(item):
301 except AttributeError:
303 except AttributeError:
307 def extract_instance_from_plugin(pluginModule, cls):
309 for name, item in pluginModule.__dict__.iteritems():
311 if isinstance(item, cls):
313 except AttributeError:
315 except AttributeError: