123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282 |
- from PyQt5.QtCore import QObject, pyqtProperty, pyqtSignal, pyqtSlot
- from UM.PluginRegistry import PluginRegistry
- from UM.Resources import Resources
- from UM.Application import Application
- from UM.Extension import Extension
- from UM.Logger import Logger
- import configparser
- import io
- import os.path
- import pkgutil
- import sys
- import importlib.util
- from UM.i18n import i18nCatalog
- i18n_catalog = i18nCatalog("cura")
- class PostProcessingPlugin(QObject, Extension):
- def __init__(self, parent = None):
- super().__init__(parent)
- self.addMenuItem(i18n_catalog.i18n("Modify G-Code"), self.showPopup)
- self._view = None
-
- self._loaded_scripts = {}
- self._script_labels = {}
-
-
- self._script_list = []
- self._selected_script_index = -1
- Application.getInstance().getOutputDeviceManager().writeStarted.connect(self.execute)
- Application.getInstance().globalContainerStackChanged.connect(self._onGlobalContainerStackChanged)
- Application.getInstance().mainWindowChanged.connect(self._createView)
- selectedIndexChanged = pyqtSignal()
- @pyqtProperty("QVariant", notify = selectedIndexChanged)
- def selectedScriptDefinitionId(self):
- try:
- return self._script_list[self._selected_script_index].getDefinitionId()
- except:
- return ""
- @pyqtProperty("QVariant", notify=selectedIndexChanged)
- def selectedScriptStackId(self):
- try:
- return self._script_list[self._selected_script_index].getStackId()
- except:
- return ""
-
- def execute(self, output_device):
- scene = Application.getInstance().getController().getScene()
-
- if not hasattr(scene, "gcode_dict"):
- return
- gcode_dict = getattr(scene, "gcode_dict")
- if not gcode_dict:
- return
-
- active_build_plate_id = Application.getInstance().getMultiBuildPlateModel().activeBuildPlate
- gcode_list = gcode_dict[active_build_plate_id]
- if not gcode_list:
- return
- if ";POSTPROCESSED" not in gcode_list[0]:
- for script in self._script_list:
- try:
- gcode_list = script.execute(gcode_list)
- except Exception:
- Logger.logException("e", "Exception in post-processing script.")
- if len(self._script_list):
- gcode_list[0] += ";POSTPROCESSED\n"
- gcode_dict[active_build_plate_id] = gcode_list
- setattr(scene, "gcode_dict", gcode_dict)
- else:
- Logger.log("e", "Already post processed")
- @pyqtSlot(int)
- def setSelectedScriptIndex(self, index):
- self._selected_script_index = index
- self.selectedIndexChanged.emit()
- @pyqtProperty(int, notify = selectedIndexChanged)
- def selectedScriptIndex(self):
- return self._selected_script_index
- @pyqtSlot(int, int)
- def moveScript(self, index, new_index):
- if new_index < 0 or new_index > len(self._script_list) - 1:
- return
- else:
-
- self._script_list[new_index], self._script_list[index] = self._script_list[index], self._script_list[new_index]
- self.scriptListChanged.emit()
- self.selectedIndexChanged.emit()
- self._propertyChanged()
-
- @pyqtSlot(int)
- def removeScriptByIndex(self, index):
- self._script_list.pop(index)
- if len(self._script_list) - 1 < self._selected_script_index:
- self._selected_script_index = len(self._script_list) - 1
- self.scriptListChanged.emit()
- self.selectedIndexChanged.emit()
- self._propertyChanged()
-
-
-
- def loadAllScripts(self):
- if self._loaded_scripts:
- return
-
-
-
- for root in [PluginRegistry.getInstance().getPluginPath("PostProcessingPlugin"), Resources.getStoragePath(Resources.Resources), Resources.getStoragePath(Resources.Preferences)]:
- path = os.path.join(root, "scripts")
- if not os.path.isdir(path):
- try:
- os.makedirs(path)
- except OSError:
- Logger.log("w", "Unable to create a folder for scripts: " + path)
- continue
- self.loadScripts(path)
-
-
-
- def loadScripts(self, path):
-
- scripts = pkgutil.iter_modules(path = [path])
- for loader, script_name, ispkg in scripts:
-
- if script_name not in sys.modules:
- try:
- spec = importlib.util.spec_from_file_location(__name__ + "." + script_name, os.path.join(path, script_name + ".py"))
- loaded_script = importlib.util.module_from_spec(spec)
- spec.loader.exec_module(loaded_script)
- sys.modules[script_name] = loaded_script
- loaded_class = getattr(loaded_script, script_name)
- temp_object = loaded_class()
- Logger.log("d", "Begin loading of script: %s", script_name)
- try:
- setting_data = temp_object.getSettingData()
- if "name" in setting_data and "key" in setting_data:
- self._script_labels[setting_data["key"]] = setting_data["name"]
- self._loaded_scripts[setting_data["key"]] = loaded_class
- else:
- Logger.log("w", "Script %s.py has no name or key", script_name)
- self._script_labels[script_name] = script_name
- self._loaded_scripts[script_name] = loaded_class
- except AttributeError:
- Logger.log("e", "Script %s.py is not a recognised script type. Ensure it inherits Script", script_name)
- except NotImplementedError:
- Logger.log("e", "Script %s.py has no implemented settings", script_name)
- except Exception as e:
- Logger.logException("e", "Exception occurred while loading post processing plugin: {error_msg}".format(error_msg = str(e)))
- loadedScriptListChanged = pyqtSignal()
- @pyqtProperty("QVariantList", notify = loadedScriptListChanged)
- def loadedScriptList(self):
- return sorted(list(self._loaded_scripts.keys()))
- @pyqtSlot(str, result = str)
- def getScriptLabelByKey(self, key):
- return self._script_labels[key]
- scriptListChanged = pyqtSignal()
- @pyqtProperty("QVariantList", notify = scriptListChanged)
- def scriptList(self):
- script_list = [script.getSettingData()["key"] for script in self._script_list]
- return script_list
- @pyqtSlot(str)
- def addScriptToList(self, key):
- Logger.log("d", "Adding script %s to list.", key)
- new_script = self._loaded_scripts[key]()
- self._script_list.append(new_script)
- self.setSelectedScriptIndex(len(self._script_list) - 1)
- self.scriptListChanged.emit()
- self._propertyChanged()
-
-
- def _onGlobalContainerStackChanged(self):
- self.loadAllScripts()
- new_stack = Application.getInstance().getGlobalContainerStack()
- self._script_list.clear()
- if not new_stack.getMetaDataEntry("post_processing_scripts"):
- self.scriptListChanged.emit()
- return
- self._script_list.clear()
- scripts_list_strs = new_stack.getMetaDataEntry("post_processing_scripts")
- for script_str in scripts_list_strs.split("\n"):
- if not script_str:
- continue
- script_str = script_str.replace("\\n", "\n").replace("\\\\", "\\")
- script_parser = configparser.ConfigParser(interpolation = None)
- script_parser.optionxform = str
- script_parser.read_string(script_str)
- for script_name, settings in script_parser.items():
- if script_name == "DEFAULT":
- continue
- if script_name not in self._loaded_scripts:
- Logger.log("e", "Unknown post-processing script {script_name} was encountered in this global stack.".format(script_name = script_name))
- continue
- new_script = self._loaded_scripts[script_name]()
- for setting_key, setting_value in settings.items():
- new_script._instance.setProperty(setting_key, "value", setting_value)
- self._script_list.append(new_script)
- self.setSelectedScriptIndex(0)
- self.scriptListChanged.emit()
- @pyqtSlot()
- def writeScriptsToStack(self):
- script_list_strs = []
- for script in self._script_list:
- parser = configparser.ConfigParser(interpolation = None)
- parser.optionxform = str
- script_name = script.getSettingData()["key"]
- parser.add_section(script_name)
- for key in script.getSettingData()["settings"]:
- value = script.getSettingValueByKey(key)
- parser[script_name][key] = str(value)
- serialized = io.StringIO()
- parser.write(serialized)
- serialized.seek(0)
- script_str = serialized.read()
- script_str = script_str.replace("\\", "\\\\").replace("\n", "\\n")
- script_list_strs.append(script_str)
- script_list_strs = "\n".join(script_list_strs)
- global_stack = Application.getInstance().getGlobalContainerStack()
- if "post_processing_scripts" not in global_stack.getMetaData():
- global_stack.addMetaDataEntry("post_processing_scripts", "")
- Application.getInstance().getGlobalContainerStack().setMetaDataEntry("post_processing_scripts", script_list_strs)
-
- def _createView(self):
- Logger.log("d", "Creating post processing plugin view.")
- self.loadAllScripts()
-
- path = os.path.join(PluginRegistry.getInstance().getPluginPath("PostProcessingPlugin"), "PostProcessingPlugin.qml")
- self._view = Application.getInstance().createQmlComponent(path, {"manager": self})
- Logger.log("d", "Post processing view created.")
-
- Application.getInstance().addAdditionalComponent("saveButton", self._view.findChild(QObject, "postProcessingSaveAreaButton"))
-
- def showPopup(self):
- if self._view is None:
- self._createView()
- self._view.show()
-
-
-
-
- def _propertyChanged(self):
- global_container_stack = Application.getInstance().getGlobalContainerStack()
- global_container_stack.propertyChanged.emit("post_processing_plugin", "value")
|