From 3922e378492c7a481e14b69367664f677dc165e0 Mon Sep 17 00:00:00 2001 From: Markus Lampert Date: Sun, 20 Dec 2020 18:14:29 -0800 Subject: [PATCH] Using property container for endmill attributes. --- .../Path/PathScripts/PathPropertyContainer.py | 34 +++++-- .../PathScripts/PathPropertyContainerGui.py | 19 +--- src/Mod/Path/PathScripts/PathToolBit.py | 88 +++++++++++------- src/Mod/Path/PathScripts/PathToolBitEdit.py | 51 +++++----- src/Mod/Path/PathScripts/PathToolBitGui.py | 4 +- src/Mod/Path/Tools/Shape/endmill.fcstd | Bin 10858 -> 11351 bytes 6 files changed, 116 insertions(+), 80 deletions(-) diff --git a/src/Mod/Path/PathScripts/PathPropertyContainer.py b/src/Mod/Path/PathScripts/PathPropertyContainer.py index a1b52b8e08..baf033dfba 100644 --- a/src/Mod/Path/PathScripts/PathPropertyContainer.py +++ b/src/Mod/Path/PathScripts/PathPropertyContainer.py @@ -32,6 +32,31 @@ def translate(context, text, disambig=None): return PySide.QtCore.QCoreApplication.translate(context, text, disambig) +SupportedPropertyType = { + 'Angle' : 'App::PropertyAngle', + 'Bool' : 'App::PropertyBool', + 'Distance' : 'App::PropertyDistance', + # 'Enumeration' : 'App::PropertyEnumeration', + 'File' : 'App::PropertyFile', + 'Float' : 'App::PropertyFloat', + 'Integer' : 'App::PropertyInteger', + 'Length' : 'App::PropertyLength', + 'Percent' : 'App::PropertyPercent', + 'String' : 'App::PropertyString', + } + +def getPropertyType(o): + if type(o) == str: + return SupportedPropertyType['String'] + if type(o) == bool: + return SupportedPropertyType['Bool'] + if type(o) == int: + return SupportedPropertyType['Integer'] + if type(o) == float: + return SupportedPropertyType['Float'] + if type(o) == FreeCAD.Units.Quantity: + return SupportedPropertyType[o.Unit.Type] + class PropertyContainer(object): '''Property container object.''' @@ -39,22 +64,17 @@ class PropertyContainer(object): CustomPropertyGroupDefault = 'User' def __init__(self, obj): - self.obj = obj obj.addProperty('App::PropertyStringList', self.CustomPropertyGroups, 'Base', PySide.QtCore.QT_TRANSLATE_NOOP('PathPropertyContainer', 'List of custom property groups')) - obj.setEditorMode(self.CustomPropertyGroups, 2) # hide + self.onDocumentRestored(obj) def __getstate__(self): return None def __setstate__(self, state): - for obj in FreeCAD.ActiveDocument.Objects: - if hasattr(obj, 'Proxy') and obj.Proxy == self: - self.obj = obj - obj.setEditorMode(self.CustomPropertyGroups, 2) # hide - break return None def onDocumentRestored(self, obj): + self.obj = obj obj.setEditorMode(self.CustomPropertyGroups, 2) # hide def getCustomProperties(self): diff --git a/src/Mod/Path/PathScripts/PathPropertyContainerGui.py b/src/Mod/Path/PathScripts/PathPropertyContainerGui.py index c5c799d19c..d12ee29466 100644 --- a/src/Mod/Path/PathScripts/PathPropertyContainerGui.py +++ b/src/Mod/Path/PathScripts/PathPropertyContainerGui.py @@ -43,19 +43,6 @@ PathLog.setLevel(PathLog.Level.INFO, PathLog.thisModule()) def translate(context, text, disambig=None): return QtCore.QCoreApplication.translate(context, text, disambig) -SupportedPropertyType = { - 'Angle' : 'App::PropertyAngle', - 'Bool' : 'App::PropertyBool', - 'Distance' : 'App::PropertyDistance', - # 'Enumeration' : 'App::PropertyEnumeration', - 'File' : 'App::PropertyFile', - 'Float' : 'App::PropertyFloat', - 'Integer' : 'App::PropertyInteger', - 'Length' : 'App::PropertyLength', - 'Percent' : 'App::PropertyPercent', - 'String' : 'App::PropertyString', - } - class ViewProvider(object): '''ViewProvider for a PropertyContainer. It's sole job is to provide an icon and invoke the TaskPanel on edit.''' @@ -148,9 +135,9 @@ class PropertyCreate(object): if grp: self.form.propertyGroup.setCurrentText(grp) - for t in sorted(SupportedPropertyType): + for t in sorted(PathPropertyContainer.SupportedPropertyType): self.form.propertyType.addItem(t) - if SupportedPropertyType[t] == typ: + if PathPropertyContainer.SupportedPropertyType[t] == typ: typ = t if typ: self.form.propertyType.setCurrentText(typ) @@ -176,7 +163,7 @@ class PropertyCreate(object): def propertyGroup(self): return self.form.propertyGroup.currentText().strip() def propertyType(self): - return SupportedPropertyType[self.form.propertyType.currentText()].strip() + return PathPropertyContainer.SupportedPropertyType[self.form.propertyType.currentText()].strip() def propertyInfo(self): return self.form.propertyInfo.toPlainText().strip() def createAnother(self): diff --git a/src/Mod/Path/PathScripts/PathToolBit.py b/src/Mod/Path/PathScripts/PathToolBit.py index 5ffe7503dd..5e63902c34 100644 --- a/src/Mod/Path/PathScripts/PathToolBit.py +++ b/src/Mod/Path/PathScripts/PathToolBit.py @@ -24,6 +24,7 @@ import FreeCAD import PathScripts.PathGeom as PathGeom import PathScripts.PathLog as PathLog import PathScripts.PathPreferences as PathPreferences +import PathScripts.PathPropertyContainer as PathPropertyContainer import PathScripts.PathSetupSheetOpPrototype as PathSetupSheetOpPrototype import PathScripts.PathUtil as PathUtil import PySide @@ -42,8 +43,10 @@ __author__ = "sliptonic (Brad Collette)" __url__ = "https://www.freecadweb.org" __doc__ = "Class to deal with and represent a tool bit." -# PathLog.setLevel(PathLog.Level.DEBUG, PathLog.thisModule()) -# PathLog.trackModule() +_DebugFindTool = True + +PathLog.setLevel(PathLog.Level.DEBUG, PathLog.thisModule()) +PathLog.trackModule() def translate(context, text, disambig=None): @@ -58,7 +61,8 @@ ParameterTypeConstraint = { 'Radius': 'App::PropertyLength'} -def _findTool(path, typ, dbg=False): +def _findTool(path, typ, dbg=_DebugFindTool): + PathLog.track(path) if os.path.exists(path): # absolute reference if dbg: PathLog.debug("Found {} at {}".format(typ, path)) @@ -67,7 +71,7 @@ def _findTool(path, typ, dbg=False): def searchFor(pname, fname): # PathLog.debug("pname: {} fname: {}".format(pname, fname)) if dbg: - PathLog.debug("Looking for {}".format(pname)) + PathLog.debug("Looking for {} in {}".format(pname, fname)) if fname: for p in PathPreferences.searchPathsTool(typ): PathLog.track(p) @@ -174,6 +178,9 @@ class ToolBit(object): translate('PathToolBit', 'The file of the tool')) obj.addProperty('App::PropertyString', 'ShapeName', 'Base', translate('PathToolBit', 'The name of the shape file')) + obj.addProperty('App::PropertyStringList', 'BitPropertyNames', 'Base', + translate('PathToolBit', 'List of all properties inherited from the bit')) + if shapeFile is None: obj.BitShape = 'endmill.fcstd' self._setupBitShape(obj) @@ -193,9 +200,6 @@ class ToolBit(object): break return None - def propertyNamesBit(self, obj): - return [prop for prop in obj.PropertiesList if obj.getGroupOfProperty(prop) == PropertyGroupBit] - def propertyNamesAttribute(self, obj): return [prop for prop in obj.PropertiesList if obj.getGroupOfProperty(prop) == PropertyGroupAttribute] @@ -206,8 +210,9 @@ class ToolBit(object): obj.setEditorMode('BitBody', 2) obj.setEditorMode('File', 1) obj.setEditorMode('Shape', 2) + obj.setEditorMode('BitPropertyNames', 2) - for prop in self.propertyNamesBit(obj): + for prop in obj.BitPropertyNames: obj.setEditorMode(prop, 1) # I currently don't see why these need to be read-only # for prop in self.propertyNamesAttribute(obj): @@ -227,12 +232,9 @@ class ToolBit(object): def _updateBitShape(self, obj, properties=None): if obj.BitBody is not None: - if not properties: - properties = self.propertyNamesBit(obj) - for prop in properties: - for sketch in [o for o in obj.BitBody.Group if o.TypeId == 'Sketcher::SketchObject']: - PathLog.track(obj.Label, sketch.Label, prop) - updateConstraint(sketch, prop, obj.getPropertyByName(prop)) + for attributes in [o for o in obj.BitBody.Group if hasattr(o, 'Proxy') and hasattr(o.Proxy, 'getCustomProperties')]: + for prop in attributes.Proxy.getCustomProperties(): + setattr(attributes, prop, obj.getPropertyByName(prop)) self._copyBitShape(obj) def _copyBitShape(self, obj): @@ -243,6 +245,7 @@ class ToolBit(object): obj.Shape = Part.Shape() def _loadBitBody(self, obj, path=None): + PathLog.track(obj.Label, path) p = path if path else obj.BitShape docOpened = False doc = None @@ -254,9 +257,12 @@ class ToolBit(object): p = findShape(p) if not path and p != obj.BitShape: obj.BitShape = p + PathLog.debug("ToolBit {} using shape file: {}".format(obj.Label, p)) doc = FreeCAD.openDocument(p, True) obj.ShapeName = doc.Name docOpened = True + else: + PathLog.debug("ToolBit {} already open: {}".format(obj.Label, doc)) return (doc, docOpened) def _removeBitBody(self, obj): @@ -269,7 +275,7 @@ class ToolBit(object): PathLog.track(obj.Label) self._removeBitBody(obj) self._copyBitShape(obj) - for prop in self.propertyNamesBit(obj): + for prop in obj.BitPropertyNames: obj.removeProperty(prop) def loadBitBody(self, obj, force=False): @@ -296,6 +302,10 @@ class ToolBit(object): obj.Label = doc.RootObjects[0].Label self._deleteBitSetup(obj) bitBody = obj.Document.copyObject(doc.RootObjects[0], True) + + for o in doc.RootObjects[0].Group: + PathLog.debug("..... {}: {}".format(o.Label, o.Name)) + if docOpened: FreeCAD.setActiveDocument(activeDoc.Name) FreeCAD.closeDocument(doc.Name) @@ -303,23 +313,35 @@ class ToolBit(object): if bitBody.ViewObject: bitBody.ViewObject.Visibility = False - for sketch in [o for o in bitBody.Group if o.TypeId == 'Sketcher::SketchObject']: - for constraint in [c for c in sketch.Constraints if c.Name != '']: - typ = ParameterTypeConstraint.get(constraint.Type) - PathLog.track(constraint, typ) - if typ is not None: - parts = [p.strip() for p in constraint.Name.split(';')] - prop = parts[0] - desc = '' - if len(parts) > 1: - desc = parts[1] - obj.addProperty(typ, prop, PropertyGroupBit, desc) - obj.setEditorMode(prop, 1) - value = constraint.Value - if constraint.Type == 'Angle': - value = value * 180 / math.pi - PathUtil.setProperty(obj, prop, value) + PathLog.debug("bitBody.{} ({}): {}".format(bitBody.Label, bitBody.Name, type(bitBody))) + + def isAttributes(o): + if not hasattr(o, 'Proxy'): + PathLog.debug(" {} has not Proxy ({})".format(o.Label, type(o))) + return False + if not hasattr(o.Proxy, 'getCustomProperties'): + PathLog.debug(" {}.Proxy has no getCustomProperties ({})".format(o.Label, type(o.Proxy))) + return False + PathLog.debug(" {} <-".format(o.Label)) + return True + + propNames = [] + for attributes in [o for o in bitBody.Group if isAttributes(o)]: + PathLog.debug("Process properties from {}".format(attributes.Label)) + for prop in attributes.Proxy.getCustomProperties(): + # extract property parameters and values so it can be copied + src = attributes.getPropertyByName(prop) + typ = PathPropertyContainer.getPropertyType(src) + grp = attributes.getGroupOfProperty(prop) + dsc = attributes.getDocumentationOfProperty(prop) + + obj.addProperty(typ, prop, grp, dsc) + obj.setEditorMode(prop, 1) + PathUtil.setProperty(obj, prop, src) + propNames.append(prop) + # has to happen last because it could trigger op.execute evaluations + obj.BitPropertyNames = propNames obj.BitBody = bitBody self._copyBitShape(obj) @@ -360,7 +382,7 @@ class ToolBit(object): else: attrs['shape'] = findRelativePathShape(obj.BitShape) params = {} - for name in self.propertyNamesBit(obj): + for name in obj.BitPropertyNames: params[name] = PathUtil.getPropertyValueString(obj, name) attrs['parameter'] = params params = {} @@ -435,6 +457,7 @@ class ToolBitFactory(object): return obj def CreateFrom(self, path, name='ToolBit'): + PathLog.track(name, path) try: data = Declaration(path) bit = Factory.CreateFromAttrs(data, name) @@ -445,6 +468,7 @@ class ToolBitFactory(object): raise def Create(self, name='ToolBit', shapeFile=None): + PathLog.track(name, shapeFile) obj = FreeCAD.ActiveDocument.addObject('Part::FeaturePython', name) obj.Proxy = ToolBit(obj, shapeFile) return obj diff --git a/src/Mod/Path/PathScripts/PathToolBitEdit.py b/src/Mod/Path/PathScripts/PathToolBitEdit.py index 3488bcc95d..b2cc823d76 100644 --- a/src/Mod/Path/PathScripts/PathToolBitEdit.py +++ b/src/Mod/Path/PathScripts/PathToolBitEdit.py @@ -84,32 +84,32 @@ class ToolBitEditor(object): layout = self.form.bitParams.layout() ui = FreeCADGui.UiLoader() - nr = 0 # for all properties either assign them to existing labels and editors # or create additional ones for them if not enough have already been # created. - for name in tool.PropertiesList: - if tool.getGroupOfProperty(name) == PathToolBit.PropertyGroupBit: - if nr < len(self.widgets): - PathLog.debug("re-use row: {} [{}]".format(nr, name)) - label, qsb, editor = self.widgets[nr] - label.setText(labelText(name)) - editor.attachTo(tool, name) - label.show() - qsb.show() - else: - qsb = ui.createWidget('Gui::QuantitySpinBox') - editor = PathGui.QuantitySpinBox(qsb, tool, name) - label = QtGui.QLabel(labelText(name)) - self.widgets.append((label, qsb, editor)) - PathLog.debug("create row: {} [{}]".format(nr, name)) - if nr >= layout.rowCount(): - layout.addRow(label, qsb) - nr = nr + 1 + for nr, name in enumerate(tool.BitPropertyNames): + if nr < len(self.widgets): + PathLog.debug("re-use row: {} [{}]".format(nr, name)) + label, qsb, editor = self.widgets[nr] + label.setText(labelText(name)) + editor.attachTo(tool, name) + label.show() + qsb.show() + else: + qsb = ui.createWidget('Gui::QuantitySpinBox') + editor = PathGui.QuantitySpinBox(qsb, tool, name) + label = QtGui.QLabel(labelText(name)) + self.widgets.append((label, qsb, editor)) + PathLog.debug("create row: {} [{}] {}".format(nr, name, type(qsb))) + if hasattr(qsb, 'editingFinished'): + qsb.editingFinished.connect(self.updateTool) + + if nr >= layout.rowCount(): + layout.addRow(label, qsb) # hide all rows which aren't being used - for i in range(nr, len(self.widgets)): + for i in range(len(tool.BitPropertyNames), len(self.widgets)): label, qsb, editor = self.widgets[i] label.hide() qsb.hide() @@ -242,13 +242,18 @@ class ToolBitEditor(object): def updateTool(self): PathLog.track() - self.tool.Label = str(self.form.toolName.text()) - self.tool.BitShape = str(self.form.shapePath.text()) + + label = str(self.form.toolName.text()) + shape = str(self.form.shapePath.text()) + if self.tool.Label != label: + self.tool.Label = label + if self.tool.BitShape != shape: + self.tool.BitShape = shape for lbl, qsb, editor in self.widgets: editor.updateProperty() - # self.tool.Proxy._updateBitShape(self.tool) + self.tool.Proxy._updateBitShape(self.tool) def refresh(self): PathLog.track() diff --git a/src/Mod/Path/PathScripts/PathToolBitGui.py b/src/Mod/Path/PathScripts/PathToolBitGui.py index 1fe1df5370..c36bb83ec0 100644 --- a/src/Mod/Path/PathScripts/PathToolBitGui.py +++ b/src/Mod/Path/PathScripts/PathToolBitGui.py @@ -174,8 +174,8 @@ class ToolBitGuiFactory(PathToolBit.ToolBitFactory): '''Create(name = 'ToolBit') ... creates a new tool bit. It is assumed the tool will be edited immediately so the internal bit body is still attached.''' - FreeCAD.ActiveDocument.openTransaction(translate('PathToolBit', - 'Create ToolBit')) + PathLog.track(name, shapeFile) + FreeCAD.ActiveDocument.openTransaction(translate('PathToolBit', 'Create ToolBit')) tool = PathToolBit.ToolBitFactory.Create(self, name, shapeFile) PathIconViewProvider.Attach(tool.ViewObject, name) FreeCAD.ActiveDocument.commitTransaction() diff --git a/src/Mod/Path/Tools/Shape/endmill.fcstd b/src/Mod/Path/Tools/Shape/endmill.fcstd index 98888db1e3f04f93e66ad561a105cd998a066be5..c5be12d7453497eae4253a031fdb551660285db3 100644 GIT binary patch delta 10103 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 delta 9614 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 G`2PSA(J)>B