From e6aee7c99933951604f81e2dbf6dd34a57bd0868 Mon Sep 17 00:00:00 2001 From: daid Date: Wed, 12 Feb 2014 14:51:32 +0100 Subject: [PATCH] Put plugin code into a different file, split from profile. Also use a nice class to keep the plugin information in, which improves support for future plugin types. --- Cura/gui/pluginPanel.py | 38 +++++----- Cura/gui/printWindow2.py | 2 +- Cura/util/plugin.py | 147 +++++++++++++++++++++++++++++++++++++++ Cura/util/profile.py | 110 ++++------------------------- 4 files changed, 180 insertions(+), 117 deletions(-) create mode 100644 Cura/util/plugin.py diff --git a/Cura/gui/pluginPanel.py b/Cura/gui/pluginPanel.py index 330fcb26..3478f037 100644 --- a/Cura/gui/pluginPanel.py +++ b/Cura/gui/pluginPanel.py @@ -6,23 +6,24 @@ import webbrowser from wx.lib import scrolledpanel from Cura.util import profile +from Cura.util import plugin from Cura.util import explorer class pluginPanel(wx.Panel): def __init__(self, parent, callback): wx.Panel.__init__(self, parent,-1) #Plugin page - self.pluginList = profile.getPluginList() + self.pluginList = plugin.getPluginList("postprocess") self.callback = callback sizer = wx.GridBagSizer(2, 2) self.SetSizer(sizer) - effectStringList = [] - for effect in self.pluginList: - effectStringList.append(effect['name']) + pluginStringList = [] + for p in self.pluginList: + pluginStringList.append(p.getName()) - self.listbox = wx.ListBox(self, -1, choices=effectStringList) + self.listbox = wx.ListBox(self, -1, choices=pluginStringList) title = wx.StaticText(self, -1, _("Plugins:")) title.SetFont(wx.Font(wx.SystemSettings.GetFont(wx.SYS_ANSI_VAR_FONT).GetPointSize(), wx.FONTFAMILY_DEFAULT, wx.NORMAL, wx.FONTWEIGHT_BOLD)) helpButton = wx.Button(self, -1, '?', style=wx.BU_EXACTFIT) @@ -58,7 +59,7 @@ class pluginPanel(wx.Panel): self.updateProfileToControls() def updateProfileToControls(self): - self.pluginConfig = profile.getPluginConfig() + self.pluginConfig = plugin.getPostProcessPluginConfig() for p in self.panelList: p.Show(False) self.pluginEnabledPanel.GetSizer().Detach(p) @@ -69,7 +70,7 @@ class pluginPanel(wx.Panel): def _buildPluginPanel(self, pluginConfig): plugin = None for pluginTest in self.pluginList: - if pluginTest['filename'] == pluginConfig['filename']: + if pluginTest.getFilename() == pluginConfig['filename']: plugin = pluginTest if plugin is None: return False @@ -77,7 +78,7 @@ class pluginPanel(wx.Panel): pluginPanel = wx.Panel(self.pluginEnabledPanel) s = wx.GridBagSizer(2, 2) pluginPanel.SetSizer(s) - title = wx.StaticText(pluginPanel, -1, plugin['name']) + title = wx.StaticText(pluginPanel, -1, plugin.getName()) title.SetFont(wx.Font(wx.SystemSettings.GetFont(wx.SYS_ANSI_VAR_FONT).GetPointSize(), wx.FONTFAMILY_DEFAULT, wx.NORMAL, wx.FONTWEIGHT_BOLD)) remButton = wx.Button(pluginPanel, -1, 'X', style=wx.BU_EXACTFIT) helpButton = wx.Button(pluginPanel, -1, '?', style=wx.BU_EXACTFIT) @@ -85,13 +86,13 @@ class pluginPanel(wx.Panel): s.Add(helpButton, pos=(0,0), span=(1,1), flag=wx.TOP|wx.LEFT|wx.ALIGN_RIGHT, border=5) s.Add(remButton, pos=(0,3), span=(1,1), flag=wx.TOP|wx.RIGHT|wx.ALIGN_RIGHT, border=5) s.Add(wx.StaticLine(pluginPanel), pos=(1,0), span=(1,4), flag=wx.EXPAND|wx.LEFT|wx.RIGHT,border=3) - info = wx.StaticText(pluginPanel, -1, plugin['info']) + info = wx.StaticText(pluginPanel, -1, plugin.getInfo()) info.Wrap(300) s.Add(info, pos=(2,0), span=(1,4), flag=wx.EXPAND|wx.LEFT|wx.RIGHT,border=3) pluginPanel.paramCtrls = {} i = 0 - for param in plugin['params']: + for param in plugin.getParams(): value = param['default'] if param['name'] in pluginConfig['params']: value = pluginConfig['params'][param['name']] @@ -125,19 +126,19 @@ class pluginPanel(wx.Panel): idx = self.panelList.index(panel) for k in panel.paramCtrls.keys(): self.pluginConfig[idx]['params'][k] = panel.paramCtrls[k].GetValue() - profile.setPluginConfig(self.pluginConfig) + plugin.setPostProcessPluginConfig(self.pluginConfig) self.callback() def OnAdd(self, e): if self.listbox.GetSelection() < 0: wx.MessageBox(_("You need to select a plugin before you can add anything."), _("Error: no plugin selected"), wx.OK | wx.ICON_INFORMATION) return - plugin = self.pluginList[self.listbox.GetSelection()] - newConfig = {'filename': plugin['filename'], 'params': {}} + p = self.pluginList[self.listbox.GetSelection()] + newConfig = {'filename': p.getFilename(), 'params': {}} if not self._buildPluginPanel(newConfig): return self.pluginConfig.append(newConfig) - profile.setPluginConfig(self.pluginConfig) + plugin.setPostProcessPluginConfig(self.pluginConfig) self.callback() def OnRem(self, e): @@ -157,12 +158,11 @@ class pluginPanel(wx.Panel): self.Layout() self.pluginConfig.pop(idx) - profile.setPluginConfig(self.pluginConfig) + plugin.setPostProcessPluginConfig(self.pluginConfig) self.callback() def OnHelp(self, e): panel = e.GetEventObject().GetParent() - sizer = self.pluginEnabledPanel.GetSizer() idx = self.panelList.index(panel) fname = self.pluginConfig[idx]['filename'].lower() @@ -174,6 +174,6 @@ class pluginPanel(wx.Panel): webbrowser.open('http://wiki.ultimaker.com/Category:CuraPlugin') def OnOpenPluginLocation(self, e): - if not os.path.exists(profile.getPluginBasePaths()[0]): - os.mkdir(profile.getPluginBasePaths()[0]) - explorer.openExplorerPath(profile.getPluginBasePaths()[0]) + if not os.path.exists(plugin.getPluginBasePaths()[0]): + os.mkdir(plugin.getPluginBasePaths()[0]) + explorer.openExplorerPath(plugin.getPluginBasePaths()[0]) diff --git a/Cura/gui/printWindow2.py b/Cura/gui/printWindow2.py index b5ce553d..df8a7e3c 100644 --- a/Cura/gui/printWindow2.py +++ b/Cura/gui/printWindow2.py @@ -78,7 +78,7 @@ class printWindowPlugin(wx.Frame): def script_setImage(self, guiImage, mapImage): self._backgroundImage = wx.BitmapFromImage(wx.Image(os.path.join(self._basePath, guiImage))) self._mapImage = wx.Image(os.path.join(self._basePath, mapImage)) - self.SetClientSize(self._backgroundImage.GetSize()) + self.SetClientSize(self._mapImage.GetSize()) def script_addColorCommand(self, r, g, b, command, data = None): self._colorCommandMap[(r, g, b)] = (command, data) diff --git a/Cura/util/plugin.py b/Cura/util/plugin.py new file mode 100644 index 00000000..382c62e2 --- /dev/null +++ b/Cura/util/plugin.py @@ -0,0 +1,147 @@ +""" +The plugin module contains information about the plugins found for Cura. +It keeps track of a list of installed plugins and the information contained within. +""" +__copyright__ = "Copyright (C) 2013 David Braam - Released under terms of the AGPLv3 License" + +import os +import sys +import traceback +import platform +import glob +import re +import cPickle as pickle + +from Cura.util import profile +from Cura.util import resources + +_pluginList = None + +class pluginInfo(object): + def __init__(self, dirname, filename): + self._dirname = dirname + self._filename = filename + self._name = os.path.splitext(os.path.basename(filename))[0] + self._type = 'unknown' + self._info = '' + self._params = [] + with open(os.path.join(dirname, filename), "r") as f: + for line in f: + line = line.strip() + if not line.startswith('#'): + break + line = line[1:].split(':', 1) + if len(line) != 2: + continue + if line[0].upper() == 'NAME': + self._name = line[1].strip() + elif line[0].upper() == 'INFO': + self._info = line[1].strip() + elif line[0].upper() == 'TYPE': + self._type = line[1].strip() + elif line[0].upper() == 'DEPEND': + pass + elif line[0].upper() == 'PARAM': + m = re.match('([a-zA-Z][a-zA-Z0-9_]*)\(([a-zA-Z_]*)(?::([^\)]*))?\) +(.*)', line[1].strip()) + if m is not None: + self._params.append({'name': m.group(1), 'type': m.group(2), 'default': m.group(3), 'description': m.group(4)}) + # else: + # print "Unknown item in plugin meta data: %s %s" % (line[0], line[1]) + + def getFilename(self): + return self._filename + + def getFullFilename(self): + return os.path.join(self._dirname, self._filename) + + def getType(self): + return self._type + + def getName(self): + return self._name + + def getInfo(self): + return self._info + + def getParams(self): + return self._params + +def getPostProcessPluginConfig(): + try: + return pickle.loads(str(profile.getProfileSetting('plugin_config'))) + except: + return [] + +def setPostProcessPluginConfig(config): + profile.putProfileSetting('plugin_config', pickle.dumps(config)) + +def getPluginBasePaths(): + ret = [] + if platform.system() != "Windows": + ret.append(os.path.expanduser('~/.cura/plugins/')) + if platform.system() == "Darwin" and hasattr(sys, 'frozen'): + ret.append(os.path.normpath(os.path.join(resources.resourceBasePath, "plugins"))) + else: + ret.append(os.path.normpath(os.path.join(os.path.dirname(os.path.abspath(__file__)), '..', '..', 'plugins'))) + return ret + +def getPluginList(pluginType): + global _pluginList + if _pluginList is None: + _pluginList = [] + for basePath in getPluginBasePaths(): + for filename in os.listdir(basePath): + if filename.startswith('.'): + continue + if filename.startswith('_'): + continue + if os.path.isdir(os.path.join(basePath, filename)): + if os.path.exists(os.path.join(basePath, filename, 'script.py')): + _pluginList.append(pluginInfo(basePath, os.path.join(filename, 'script.py'))) + elif filename.endswith('.py'): + _pluginList.append(pluginInfo(basePath, filename)) + ret = [] + for plugin in _pluginList: + if plugin.getType() == pluginType: + ret.append(plugin) + return ret + +def runPostProcessingPlugins(engineResult): + pluginConfigList = getPostProcessPluginConfig() + pluginList = getPluginList() + + for pluginConfig in pluginConfigList: + plugin = None + for pluginTest in pluginList: + if pluginTest['filename'] == pluginConfig['filename']: + plugin = pluginTest + if plugin is None: + continue + + pythonFile = None + for basePath in getPluginBasePaths(): + testFilename = os.path.join(basePath, pluginConfig['filename']) + if os.path.isfile(testFilename): + pythonFile = testFilename + if pythonFile is None: + continue + + locals = {'filename': gcodefilename} + for param in plugin['params']: + value = param['default'] + if param['name'] in pluginConfig['params']: + value = pluginConfig['params'][param['name']] + + if param['type'] == 'float': + try: + value = float(value) + except: + value = float(param['default']) + + locals[param['name']] = value + try: + execfile(pythonFile, locals) + except: + locationInfo = traceback.extract_tb(sys.exc_info()[2])[-1] + return "%s: '%s' @ %s:%s:%d" % (str(sys.exc_info()[0].__name__), str(sys.exc_info()[1]), os.path.basename(locationInfo[0]), locationInfo[2], locationInfo[1]) + return None diff --git a/Cura/util/profile.py b/Cura/util/profile.py index dbc8b7aa..b63a04eb 100644 --- a/Cura/util/profile.py +++ b/Cura/util/profile.py @@ -5,7 +5,19 @@ These settings can be globally accessed and modified. from __future__ import division __copyright__ = "Copyright (C) 2013 David Braam - Released under terms of the AGPLv3 License" -import os, traceback, math, re, zlib, base64, time, sys, platform, glob, string, stat, types +import os +import traceback +import math +import re +import zlib +import base64 +import time +import sys +import platform +import glob +import string +import stat +import types import cPickle as pickle import numpy if sys.version_info[0] < 3: @@ -13,7 +25,6 @@ if sys.version_info[0] < 3: else: import configparser as ConfigParser -from Cura.util import resources from Cura.util import version from Cura.util import validators @@ -1042,98 +1053,3 @@ def getAlterationFileContents(filename, extruderCount = 1): #Append the profile string to the end of the GCode, so we can load it from the GCode file later. postfix = ';CURA_PROFILE_STRING:%s\n' % (getProfileString()) return unicode(prefix + re.sub("(.)\{([^\}]*)\}", replaceTagMatch, alterationContents).rstrip() + '\n' + postfix).strip().encode('utf-8') + '\n' - -###### PLUGIN ##### - -def getPluginConfig(): - try: - return pickle.loads(str(getProfileSetting('plugin_config'))) - except: - return [] - -def setPluginConfig(config): - putProfileSetting('plugin_config', pickle.dumps(config)) - -def getPluginBasePaths(): - ret = [] - if platform.system() != "Windows": - ret.append(os.path.expanduser('~/.cura/plugins/')) - if platform.system() == "Darwin" and hasattr(sys, 'frozen'): - ret.append(os.path.normpath(os.path.join(resources.resourceBasePath, "plugins"))) - else: - ret.append(os.path.normpath(os.path.join(os.path.dirname(os.path.abspath(__file__)), '..', '..', 'plugins'))) - return ret - -def getPluginList(): - ret = [] - for basePath in getPluginBasePaths(): - for filename in glob.glob(os.path.join(basePath, '*.py')): - filename = os.path.basename(filename) - if filename.startswith('_'): - continue - with open(os.path.join(basePath, filename), "r") as f: - item = {'filename': filename, 'name': None, 'info': None, 'type': None, 'params': []} - for line in f: - line = line.strip() - if not line.startswith('#'): - break - line = line[1:].split(':', 1) - if len(line) != 2: - continue - if line[0].upper() == 'NAME': - item['name'] = line[1].strip() - elif line[0].upper() == 'INFO': - item['info'] = line[1].strip() - elif line[0].upper() == 'TYPE': - item['type'] = line[1].strip() - elif line[0].upper() == 'DEPEND': - pass - elif line[0].upper() == 'PARAM': - m = re.match('([a-zA-Z][a-zA-Z0-9_]*)\(([a-zA-Z_]*)(?::([^\)]*))?\) +(.*)', line[1].strip()) - if m is not None: - item['params'].append({'name': m.group(1), 'type': m.group(2), 'default': m.group(3), 'description': m.group(4)}) - else: - print "Unknown item in effect meta data: %s %s" % (line[0], line[1]) - if item['name'] is not None and item['type'] == 'postprocess': - ret.append(item) - return ret - -def runPostProcessingPlugins(gcodefilename): - pluginConfigList = getPluginConfig() - pluginList = getPluginList() - - for pluginConfig in pluginConfigList: - plugin = None - for pluginTest in pluginList: - if pluginTest['filename'] == pluginConfig['filename']: - plugin = pluginTest - if plugin is None: - continue - - pythonFile = None - for basePath in getPluginBasePaths(): - testFilename = os.path.join(basePath, pluginConfig['filename']) - if os.path.isfile(testFilename): - pythonFile = testFilename - if pythonFile is None: - continue - - locals = {'filename': gcodefilename} - for param in plugin['params']: - value = param['default'] - if param['name'] in pluginConfig['params']: - value = pluginConfig['params'][param['name']] - - if param['type'] == 'float': - try: - value = float(value) - except: - value = float(param['default']) - - locals[param['name']] = value - try: - execfile(pythonFile, locals) - except: - locationInfo = traceback.extract_tb(sys.exc_info()[2])[-1] - return "%s: '%s' @ %s:%s:%d" % (str(sys.exc_info()[0].__name__), str(sys.exc_info()[1]), os.path.basename(locationInfo[0]), locationInfo[2], locationInfo[1]) - return None -- 2.30.2