4 from __future__ import with_statement
12 from libraries import gtkpie
13 from libraries import gtkpieboard
14 from libraries.recipes import io
18 class CommandStackHandler(object):
20 def __init__(self, stack, command, operator):
21 self.command = command
24 self.__operator = operator
26 def handler(self, commandName, activeModifiers):
27 self.__stack.apply_operation(self.__operator)
30 class PieKeyboardPlugin(object):
32 def __init__(self, name, factory):
34 self.factory = factory
37 def setup(self, calcStack, style, boardHandler):
38 self.__handler = boardHandler
40 with open(self.factory.mapFile, "r") as mapfile:
41 boardTree = gtkpieboard.parse_keyboard_data("\n".join(mapfile.readlines()))
43 rows, columns = boardTree["dimensions"]
44 keyboardName = boardTree["name"]
45 keyTree = boardTree["keys"]
47 keyboard = gtkpieboard.PieKeyboard(style, rows, columns)
48 gtkpieboard.load_keyboard(keyboardName, keyTree, keyboard, self.__handler)
50 for commandName, operator in self.factory.commands.iteritems():
51 handler = CommandStackHandler(calcStack, commandName, operator)
52 self.__handler.register_command_handler(commandName, handler.handler)
57 for commandName, operator in self.factory.commands.itervalues():
58 self.__handler.unregister_command_handler(commandName)
60 # Leave our self completely unusable
66 class PieKeyboardPluginFactory(object):
68 def __init__(self, pluginName, keyboardMapFile):
69 self.name = pluginName
70 self.mapFile = keyboardMapFile
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: