| | |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| |
|
| | import FreeCAD |
| | import FreeCADGui |
| | import os |
| | import Path |
| | import Path.Op.Base as PathOp |
| |
|
| | from PySide.QtCore import QT_TRANSLATE_NOOP |
| |
|
| | __title__ = "CAM Custom Operation" |
| | __author__ = "sliptonic (Brad Collette)" |
| | __url__ = "https://www.freecad.org" |
| | __doc__ = "CAM Custom object and FreeCAD command" |
| |
|
| |
|
| | if False: |
| | Path.Log.setLevel(Path.Log.Level.DEBUG, Path.Log.thisModule()) |
| | Path.Log.trackModule(Path.Log.thisModule()) |
| | else: |
| | Path.Log.setLevel(Path.Log.Level.INFO, Path.Log.thisModule()) |
| |
|
| |
|
| | 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 |
| | """ |
| |
|
| | |
| |
|
| | 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", |
| | "Path", |
| | QT_TRANSLATE_NOOP("App::Property", "The G-code to be inserted"), |
| | ) |
| |
|
| | |
| | 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) |
| |
|
| | if prop == "Active" and obj.ViewObject: |
| | obj.ViewObject.signalChangeIcon() |
| |
|
| | 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", |
| | ) |
| |
|
| | |
| | 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): |
| | |
| | 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)")) |
| | errorNumLines = [] |
| | errorLines = [] |
| | counter = 0 |
| |
|
| | if obj.Source == "Text" and obj.Gcode: |
| | for l in obj.Gcode: |
| | counter += 1 |
| | try: |
| | newcommand = Path.Command(str(l)) |
| | self.commandlist.append(newcommand) |
| | except ValueError: |
| | errorNumLines.append(counter) |
| | if len(errorLines) < 7: |
| | errorLines.append(f"{counter}: {str(l).strip()}") |
| | if errorLines: |
| | Path.Log.warning( |
| | translate("PathCustom", "Total invalid lines in Custom Text G-code: %s") |
| | % len(errorNumLines) |
| | ) |
| |
|
| | elif obj.Source == "File" and len(obj.GcodeFile) > 0: |
| | gcode_file = self.findGcodeFile(obj.GcodeFile) |
| |
|
| | |
| | if not gcode_file: |
| | Path.Log.error( |
| | translate("PathCustom", "Custom file %s could not be found.") % obj.GcodeFile |
| | ) |
| | else: |
| | with open(gcode_file) as fd: |
| | for l in fd.readlines(): |
| | counter += 1 |
| | try: |
| | newcommand = Path.Command(str(l)) |
| | self.commandlist.append(newcommand) |
| | except ValueError: |
| | errorNumLines.append(counter) |
| | if len(errorLines) < 7: |
| | errorLines.append(f"{counter}: {str(l).strip()}") |
| | if errorLines: |
| | Path.Log.warning(f'"{gcode_file}"') |
| | Path.Log.warning( |
| | translate("PathCustom", "Total invalid lines in Custom File G-code: %s") |
| | % len(errorNumLines) |
| | ) |
| |
|
| | if errorNumLines: |
| | Path.Log.warning( |
| | translate("PathCustom", "Please check lines: %s") |
| | % ", ".join(map(str, errorNumLines)) |
| | ) |
| |
|
| | if len(errorLines) > 7: |
| | errorLines.append("...") |
| | Path.Log.warning("\n" + "\n".join(errorLines)) |
| |
|
| | self.commandlist.append(Path.Command("(End Custom)")) |
| |
|
| |
|
| | def SetupProperties(): |
| | setup = [] |
| | return setup |
| |
|
| |
|
| | def Create(name, obj=None, parentJob=None): |
| | """Create(name) ... Creates and returns a Custom operation.""" |
| | if obj is None: |
| | obj = FreeCAD.ActiveDocument.addObject("Path::FeaturePython", name) |
| | obj.Proxy = ObjectCustom(obj, name, parentJob) |
| | return obj |
| |
|