From a3cd80796b7300a95f5629adbc1c79005057595a Mon Sep 17 00:00:00 2001 From: Markus Lampert Date: Sat, 25 Aug 2018 13:58:13 -0700 Subject: [PATCH] Template export/import of operation settings. --- .../Resources/panels/DlgJobTemplateExport.ui | 159 +++++++++--------- src/Mod/Path/PathScripts/PathJobCmd.py | 17 +- src/Mod/Path/PathScripts/PathSetupSheet.py | 53 +++++- src/Mod/Path/PathScripts/PathSetupSheetGui.py | 30 ++-- .../PathScripts/PathSetupSheetOpPrototype.py | 9 +- 5 files changed, 173 insertions(+), 95 deletions(-) diff --git a/src/Mod/Path/Gui/Resources/panels/DlgJobTemplateExport.ui b/src/Mod/Path/Gui/Resources/panels/DlgJobTemplateExport.ui index 749804959c..2734ec39b7 100644 --- a/src/Mod/Path/Gui/Resources/panels/DlgJobTemplateExport.ui +++ b/src/Mod/Path/Gui/Resources/panels/DlgJobTemplateExport.ui @@ -6,8 +6,8 @@ 0 0 - 422 - 434 + 650 + 887 @@ -42,6 +42,86 @@ + + + + <html><head/><body><p>If enabled tool controller definitions are stored in the template.</p></body></html> + + + Tools + + + true + + + + + + <html><head/><body><p>Check all tool controllers which should be included in the template.</p></body></html> + + + + + + + + + + <html><head/><body><p>Enable to include values of the SetupSheet in the template.</p><p>Any values of the SetupSheet that are changed from their default are preselected. If this field not selected the current SetupSheet was not modified.</p></body></html> + + + Setup Sheet + + + true + + + + + + Operation Depths + + + true + + + + + + + <html><head/><body><p>Enable to include the default heights for operations in the template.</p></body></html> + + + Operation Heights + + + true + + + + + + + <html><head/><body><p>Enable to include the default rapid tool speeds in the template.</p></body></html> + + + Tool Rapid Speeds + + + true + + + + + + + <html><head/><body><p>Enable all Operations for which the configuration values should be exported.</p><p><br/></p><p>Note that only operations are listed which currently have configuration values setup.</p></body></html> + + + + + + @@ -109,79 +189,6 @@ - - - - <html><head/><body><p>Enable to include values of the SetupSheet in the template.</p><p>Any values of the SetupSheet that are changed from their default are preselected. If this field not selected the current SetupSheet was not modified.</p></body></html> - - - Setup Sheet - - - true - - - - - - <html><head/><body><p>Enable to include the default heights for operations in the template.</p></body></html> - - - Operation Heights - - - true - - - - - - - Operation Depths - - - true - - - - - - - <html><head/><body><p>Enable to include the default rapid tool speeds in the template.</p></body></html> - - - Tool Rapid Speeds - - - true - - - - - - - - - - <html><head/><body><p>If enabled tool controller definitions are stored in the template.</p></body></html> - - - Tools - - - true - - - - - - <html><head/><body><p>Check all tool controllers which should be included in the template.</p></body></html> - - - - - - @@ -196,14 +203,12 @@ postProcessingGroup - stockGroup stockExtent stockPlacement settingsGroup settingOperationHeights settingOperationDepths settingToolRapid - toolsGroup toolsList buttonBox diff --git a/src/Mod/Path/PathScripts/PathJobCmd.py b/src/Mod/Path/PathScripts/PathJobCmd.py index a6812b95a7..bcb30680fa 100644 --- a/src/Mod/Path/PathScripts/PathJobCmd.py +++ b/src/Mod/Path/PathScripts/PathJobCmd.py @@ -162,11 +162,16 @@ class DlgJobTemplateExport: rapidChanged = not job.SetupSheet.Proxy.hasDefaultToolRapids() depthsChanged = not job.SetupSheet.Proxy.hasDefaultOperationDepths() heightsChanged = not job.SetupSheet.Proxy.hasDefaultOperationHeights() - settingsChanged = rapidChanged or depthsChanged or heightsChanged + opsWithSettings = job.SetupSheet.Proxy.operationsWithSettings() + settingsChanged = rapidChanged or depthsChanged or heightsChanged or 0 != len(opsWithSettings) self.dialog.settingsGroup.setChecked(settingsChanged) self.dialog.settingToolRapid.setChecked(rapidChanged) self.dialog.settingOperationDepths.setChecked(depthsChanged) self.dialog.settingOperationHeights.setChecked(heightsChanged) + for op in opsWithSettings: + item = QtGui.QListWidgetItem(op) + item.setCheckState(QtCore.Qt.CheckState.Checked) + self.dialog.settingsOpsList.addItem(item) for tc in sorted(job.ToolController, key=lambda o: o.Label): item = QtGui.QListWidgetItem(tc.Label) @@ -208,6 +213,14 @@ class DlgJobTemplateExport: def includeSettingOperationDepths(self): return self.dialog.settingOperationDepths.isChecked() + def includeSettingOpsSettings(self): + ops = [] + for i in range(self.dialog.settingsOpsList.count()): + item = self.dialog.settingsOpsList.item(i) + if item.checkState() == QtCore.Qt.CheckState.Checked: + ops.append(item.text()) + return ops + def exec_(self): return self.dialog.exec_() @@ -283,7 +296,7 @@ class CommandJobTemplateExport: # setup sheet setupSheetAttrs = None if dialog: - setupSheetAttrs = job.Proxy.setupSheet.templateAttributes(dialog.includeSettingToolRapid(), dialog.includeSettingOperationHeights(), dialog.includeSettingOperationDepths()) + setupSheetAttrs = job.Proxy.setupSheet.templateAttributes(dialog.includeSettingToolRapid(), dialog.includeSettingOperationHeights(), dialog.includeSettingOperationDepths(), dialog.includeSettingOpsSettings()) else: setupSheetAttrs = job.Proxy.setupSheet.templateAttributes(True, True, True) if setupSheetAttrs: diff --git a/src/Mod/Path/PathScripts/PathSetupSheet.py b/src/Mod/Path/PathScripts/PathSetupSheet.py index 5937e3dddc..1fdb038c8e 100644 --- a/src/Mod/Path/PathScripts/PathSetupSheet.py +++ b/src/Mod/Path/PathScripts/PathSetupSheet.py @@ -26,6 +26,7 @@ import FreeCAD import Path import PathScripts.PathGeom as PathGeom import PathScripts.PathLog as PathLog +import PathScripts.PathSetupSheetOpPrototype as PathSetupSheetOpPrototype import PathScripts.PathUtil as PathUtil import PySide @@ -154,21 +155,48 @@ class SetupSheet: if attrs.get(name) is not None: setattr(self.obj, name, attrs[name]) - def templateAttributes(self, includeRapids=True, includeHeights=True, includeDepths=True): + for opName,op in PathUtil.keyValueIter(_RegisteredOps): + opSetting = attrs.get(opName) + if opSetting is not None: + prototype = op.prototype(opName) + for propName in op.properties(): + value = opSetting.get(propName) + if not value is None: + prop = prototype.getProperty(propName) + propertyName = OpPropertyName(opName, propName) + propertyGroup = OpPropertyGroup(opName) + prop.setupProperty(self.obj, propertyName, propertyGroup, prop.valueFromString(value)) + + + def templateAttributes(self, includeRapids=True, includeHeights=True, includeDepths=True, includeOps=None): '''templateAttributes(includeRapids, includeHeights, includeDepths) ... answers a dictionary with the default values.''' attrs = {} + if includeRapids: attrs[Template.VertRapid] = self.obj.VertRapid.UserString attrs[Template.HorizRapid] = self.obj.HorizRapid.UserString + if includeHeights: attrs[Template.SafeHeightOffset] = self.obj.SafeHeightOffset.UserString attrs[Template.SafeHeightExpression] = self.obj.SafeHeightExpression attrs[Template.ClearanceHeightOffset] = self.obj.ClearanceHeightOffset.UserString attrs[Template.ClearanceHeightExpression] = self.obj.ClearanceHeightExpression + if includeDepths: attrs[Template.StartDepthExpression] = self.obj.StartDepthExpression attrs[Template.FinalDepthExpression] = self.obj.FinalDepthExpression attrs[Template.StepDownExpression] = self.obj.StepDownExpression + + if includeOps: + for opName in includeOps: + settings = {} + op = _RegisteredOps[opName] + for propName in op.properties(): + prop = OpPropertyName(opName, propName) + if hasattr(self.obj, prop): + settings[propName] = getattr(self.obj, prop) + attrs[opName] = settings + return attrs def expressionReference(self): @@ -208,6 +236,16 @@ class SetupSheet: '''decodeTemplateAttributes(attrs) ... expand template attributes to reference the receiver where applicable.''' return _traverseTemplateAttributes(attrs, self.decodeAttributeString) + def operationsWithSettings(self): + '''operationsWithSettings() ... returns a list of operations which currently have some settings defined.''' + ops = [] + for name,value in PathUtil.keyValueIter(_RegisteredOps): + for prop in value.registeredPropertyNames(name): + if hasattr(self.obj, prop): + ops.append(name) + break + return ops + def Create(name = 'SetupSheet'): obj = FreeCAD.ActiveDocument.addObject('App::FeaturePython', name) @@ -215,10 +253,19 @@ def Create(name = 'SetupSheet'): return obj class _RegisteredOp(object): + def __init__(self, factory, properties): self.factory = factory self.properties = properties + def registeredPropertyNames(self, name): + return [OpPropertyName(name, prop) for prop in self.properties()] + + def prototype(self, name): + ptt = PathSetupSheetOpPrototype.OpPrototype(name) + self.factory("OpPrototype.%s" % name, ptt) + return ptt + def RegisterOperation(name, objFactory, setupProperties): global _RegisteredOps _RegisteredOps[name] = _RegisteredOp(objFactory, setupProperties) @@ -226,3 +273,7 @@ def RegisterOperation(name, objFactory, setupProperties): def OpNamePrefix(name): return name.replace('Path', '').replace(' ', '').replace('_', '') +def OpPropertyName(opName, propName): + return "{}{}".format(OpNamePrefix(opName), propName) +def OpPropertyGroup(opName): + return "Op {}".format(opName) diff --git a/src/Mod/Path/PathScripts/PathSetupSheetGui.py b/src/Mod/Path/PathScripts/PathSetupSheetGui.py index 2abe9cf126..e624ca16b9 100644 --- a/src/Mod/Path/PathScripts/PathSetupSheetGui.py +++ b/src/Mod/Path/PathScripts/PathSetupSheetGui.py @@ -128,14 +128,12 @@ class OpTaskPanel: def __init__(self, obj, name, op): self.name = name - self.prefix = PathSetupSheet.OpNamePrefix(name) self.obj = obj self.op = op self.form = FreeCADGui.PySideUic.loadUi(":/panels/SetupOp.ui") self.form.setWindowTitle(self.name) self.props = sorted(op.properties()) - self.prototype = PathSetupSheetOpPrototype.OpPrototype(name) - op.factory("OpPrototype.%s" % name, self.prototype) + self.prototype = op.prototype(name) def updateData(self, topLeft, bottomRight): if 0 == topLeft.column(): @@ -179,23 +177,25 @@ class OpTaskPanel: self.model.dataChanged.connect(self.updateData) def propertyName(self, prop): - return "{}{}".format(self.prefix, prop) + return PathSetupSheet.OpPropertyName(self.name, prop) - def categoryName(self): - return "Op {}".format(self.name) + def propertyGroup(self): + return PathSetupSheet.OpPropertyGroup(self.name) def accept(self): + propertiesCreatedRemoved = False for i,name in enumerate(self.props): prop = self.prototype.getProperty(name) propName = self.propertyName(name) enabled = self.model.item(i, 0).checkState() == QtCore.Qt.Checked if enabled and not prop.getValue() is None: - prop.setupProperty(self.obj, propName, self.categoryName()) - setattr(self.obj, propName, prop.getValue()) + if prop.setupProperty(self.obj, propName, self.propertyGroup(), prop.getValue()): + propertiesCreatedRemoved = True else: if hasattr(self.obj, propName): self.obj.removeProperty(propName) - return True + propertiesCreatedRemoved = True + return propertiesCreatedRemoved class TaskPanel: @@ -219,16 +219,18 @@ class TaskPanel: def accept(self): self.getFields() [op.accept() for op in self.ops] - #if any([op.accept() for op in self.ops]): - # PathLog.track() - # self.obj.touch() + if any([op.accept() for op in self.ops]): + PathLog.track() + #sel = FreeCADGui.Selection.getSelection() + #FreeCADGui.Selection.clearSelection() + #for o in sel: + # FreeCADGui.Selection.addSelection(o) FreeCAD.ActiveDocument.commitTransaction() FreeCADGui.ActiveDocument.resetEdit() FreeCADGui.Control.closeDialog() FreeCAD.ActiveDocument.recompute() #FreeCADGui.Selection.removeObserver(self.s) - FreeCAD.ActiveDocument.recompute() - #self.vobj.update() + #FreeCAD.ActiveDocument.recompute() def getFields(self): def updateExpression(name, widget): diff --git a/src/Mod/Path/PathScripts/PathSetupSheetOpPrototype.py b/src/Mod/Path/PathScripts/PathSetupSheetOpPrototype.py index 2d83200adc..28773d5887 100644 --- a/src/Mod/Path/PathScripts/PathSetupSheetOpPrototype.py +++ b/src/Mod/Path/PathScripts/PathSetupSheetOpPrototype.py @@ -66,14 +66,21 @@ class Property(object): def typeString(self): return "Property" - def setupProperty(self, obj, name, category): + def setupProperty(self, obj, name, category, value): if not hasattr(obj, name): obj.addProperty(self.propType, name, category, self.info) self.initProperty(obj, name) + setattr(obj, name, value) + return True + return False def initProperty(self, obj, name): pass + + def valueFromString(self, string): + return string + class PropertyEnumeration(Property): def typeString(self): return "Enumeration"