diff --git a/src/Mod/Path/Path/Op/Custom.py b/src/Mod/Path/Path/Op/Custom.py index 3d89dd5777..6bd4f3d85f 100644 --- a/src/Mod/Path/Path/Op/Custom.py +++ b/src/Mod/Path/Path/Op/Custom.py @@ -21,6 +21,8 @@ # *************************************************************************** import FreeCAD +import FreeCADGui +import os import Path import Path.Op.Base as PathOp @@ -43,10 +45,58 @@ translate = FreeCAD.Qt.translate class ObjectCustom(PathOp.ObjectOp): + @classmethod + def propertyEnumerations(self, dataType="data"): + """customOpPropertyEnumerations(dataType="data")... return property enumeration lists of specified dataType. + Args: + dataType = 'data', 'raw', 'translated' + Notes: + 'data' is list of internal string literals used in code + 'raw' is list of (translated_text, data_string) tuples + 'translated' is list of translated string literals + """ + + # Enumeration lists for App::PropertyEnumeration properties + + enums = { + "Source": [ + (translate("PathCustom", "Text"), "Text"), + (translate("PathCustom", "File"), "File"), + ], + } + + if dataType == "raw": + return enums + + data = list() + idx = 0 if dataType == "translated" else 1 + + Path.Log.debug(enums) + + for k, v in enumerate(enums): + data.append((v, [tup[idx] for tup in enums[v]])) + Path.Log.debug(data) + + return data + def opFeatures(self, obj): return PathOp.FeatureTool | PathOp.FeatureCoolant def initOperation(self, obj): + obj.addProperty( + "App::PropertyEnumeration", + "Source", + "Path", + "Source of gcode (text, file, ...)", + ) + + obj.addProperty( + "App::PropertyFile", + "GcodeFile", + "Path", + "File containing gcode to be inserted", + ) + obj.addProperty( "App::PropertyStringList", "Gcode", @@ -54,14 +104,90 @@ class ObjectCustom(PathOp.ObjectOp): QT_TRANSLATE_NOOP("App::Property", "The G-code to be inserted"), ) + # populate the property enumerations + for n in self.propertyEnumerations(): + setattr(obj, n[0], n[1]) + obj.Proxy = self + self.setEditorModes(obj) + + def onChanged(self, obj, prop): + if prop == "Source": + self.setEditorModes(obj) + + def opOnDocumentRestored(self, obj): + if not hasattr(obj, "Source"): + obj.addProperty( + "App::PropertyEnumeration", + "Source", + "Path", + "Source of gcode (text, file, ...)", + ) + + if not hasattr(obj, "GcodeFile"): + obj.addProperty( + "App::PropertyFile", + "GcodeFile", + "Path", + "File containing gcode to be inserted", + ) + + # populate the property enumerations + for n in self.propertyEnumerations(): + setattr(obj, n[0], n[1]) + + def onDocumentRestore(self, obj): + self.setEditorModes(self, obj) + + def setEditorModes(self, obj, features=None): + if not hasattr(obj, "Source"): + return + + if obj.Source == "Text": + obj.setEditorMode("GcodeFile", 2) + obj.setEditorMode("Gcode", 0) + elif obj.Source == "File": + obj.setEditorMode("GcodeFile", 0) + obj.setEditorMode("Gcode", 2) + + def findGcodeFile(self, filename): + if os.path.exists(filename): + # probably absolute, just return + return filename + + doc_path = os.path.dirname(FreeCAD.ActiveDocument.FileName) + prospective_path = os.path.join(doc_path, filename) + + if os.path.exists(prospective_path): + return prospective_path def opExecute(self, obj): self.commandlist.append(Path.Command("(Begin Custom)")) - if obj.Gcode: + + if obj.Source == "Text" and obj.Gcode: for l in obj.Gcode: newcommand = Path.Command(str(l)) self.commandlist.append(newcommand) + elif obj.Source == "File" and len(obj.GcodeFile) > 0: + gcode_file = self.findGcodeFile(obj.GcodeFile) + + # could not determine the path + if not gcode_file: + Path.Log.error( + translate("PathCustom", "Custom file %s could not be found.") + % obj.GcodeFile + ) + + with open(gcode_file) as fd: + for l in fd.readlines(): + try: + newcommand = Path.Command(str(l)) + self.commandlist.append(newcommand) + except ValueError: + Path.Log.warning( + translate("PathCustom", "Invalid Gcode line: %s") % l + ) + continue self.commandlist.append(Path.Command("(End Custom)"))