From ac1e863c3e3a32e77450dbcd9053776bb8ae1285 Mon Sep 17 00:00:00 2001 From: Markus Lampert Date: Sat, 2 Jan 2021 00:38:53 -0800 Subject: [PATCH] Added support for enumerations to the tool bit setup and using the property bag editors instead of re-implementing. --- src/Mod/Path/PathScripts/PathToolBit.py | 36 ++++++++---- src/Mod/Path/PathScripts/PathToolBitEdit.py | 62 +------------------- src/Mod/Path/Tools/Shape/endmill.fcstd | Bin 11485 -> 11592 bytes 3 files changed, 28 insertions(+), 70 deletions(-) diff --git a/src/Mod/Path/PathScripts/PathToolBit.py b/src/Mod/Path/PathScripts/PathToolBit.py index 97176b86cd6a..4a72dedab2fd 100644 --- a/src/Mod/Path/PathScripts/PathToolBit.py +++ b/src/Mod/Path/PathScripts/PathToolBit.py @@ -192,7 +192,17 @@ def _updateBitShape(self, obj, properties=None): if obj.BitBody is not None: 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)) + # the property might not exist in our local object (new attribute in shape) + # for such attributes we just keep the default + if hasattr(obj, prop): + setattr(attributes, prop, obj.getPropertyByName(prop)) + else: + # if the template shape has a new attribute defined we should add that + # to the local object + self._setupProperty(obj, prop, attributes) + propNames = obj.BitPropertyNames + propNames.append(prop) + obj.BitPropertyNames = propNames self._copyBitShape(obj) def _copyBitShape(self, obj): @@ -251,6 +261,20 @@ def loadBitBody(self, obj, force=False): def unloadBitBody(self, obj): self._removeBitBody(obj) + def _setupProperty(self, obj, prop, orig): + # extract property parameters and values so it can be copied + val = orig.getPropertyByName(prop) + typ = orig.getTypeIdOfProperty(prop) + grp = orig.getGroupOfProperty(prop) + dsc = orig.getDocumentationOfProperty(prop) + + obj.addProperty(typ, prop, grp, dsc) + if 'App::PropertyEnumeration' == typ: + setattr(obj, prop, orig.getEnumerationsOfProperty(prop)) + + obj.setEditorMode(prop, 1) + PathUtil.setProperty(obj, prop, val) + def _setupBitShape(self, obj, path=None): PathLog.track(obj.Label) @@ -275,15 +299,7 @@ def _setupBitShape(self, obj, path=None): for attributes in [o for o in bitBody.Group if PathPropertyBag.IsPropertyBag(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 = PathPropertyBag.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) + self._setupProperty(obj, prop, attributes) propNames.append(prop) if not propNames: PathLog.error(translate('PathToolBit', 'Did not find a PropertyBag in {} - not a ToolBit shape?').format(docName)) diff --git a/src/Mod/Path/PathScripts/PathToolBitEdit.py b/src/Mod/Path/PathScripts/PathToolBitEdit.py index 26ccd068d5b4..724f5b65cc1f 100644 --- a/src/Mod/Path/PathScripts/PathToolBitEdit.py +++ b/src/Mod/Path/PathScripts/PathToolBitEdit.py @@ -25,6 +25,7 @@ import PathScripts.PathGui as PathGui import PathScripts.PathLog as PathLog import PathScripts.PathPreferences as PathPreferences +import PathScripts.PathPropertyEditor as PathPropertyEditor import PathScripts.PathToolBit as PathToolBit import PathScripts.PathUtil as PathUtil import os @@ -40,65 +41,6 @@ def translate(context, text, disambig=None): return QtCore.QCoreApplication.translate(context, text, disambig) -class _PropertyEditorBase(object): - '''Base class of all typed property editors''' - - def __init__(self, obj, prop): - self.obj = obj - self.prop = prop - def getValue(self): - return getattr(self.obj, self.prop) - def setValue(self, val): - setattr(self.obj, self.prop, val) - -class _PropertyEditorInteger(_PropertyEditorBase): - def widget(self, parent): - return QtGui.QSpinBox(parent) - def setEditorData(self, widget): - widget.setValue(self.getValue()) - def setModelData(self, widget): - self.setValue(widget.value()) - -class _PropertyEditorFloat(_PropertyEditorInteger): - def widget(self, parent): - return QtGui.QDoubleSpinBox(parent) - -class _PropertyEditorBool(_PropertyEditorBase): - def widget(self, parent): - return QtGui.QComboBox(parent) - def setEditorData(self, widget): - widget.clear() - widget.addItems([str(False), str(True)]) - widget.setCurrentIndex(1 if self.getValue() else 0) - def setModelData(self, widget): - self.setValue(widget.currentIndex() == 1) - -class _PropertyEditorString(_PropertyEditorBase): - def widget(self, parent): - return QtGui.QLineEdit(parent) - def setEditorData(self, widget): - widget.setText(self.getValue()) - def setModelData(self, widget): - self.setValue(widget.text()) - -class _PropertyEditorQuantity(_PropertyEditorBase): - def widget(self, parent): - qsb = FreeCADGui.UiLoader().createWidget('Gui::QuantitySpinBox', parent) - self.editor = PathGui.QuantitySpinBox(qsb, self.obj, self.prop) - return qsb - def setEditorData(self, widget): - self.editor.updateSpinBox() - def setModelData(self, widget): - self.editor.updateProperty() - -_PropertyEditorFactory = { - bool : _PropertyEditorBool, - int : _PropertyEditorInteger, - float : _PropertyEditorFloat, - str : _PropertyEditorString, - FreeCAD.Units.Quantity : _PropertyEditorQuantity, - } - class _Delegate(QtGui.QStyledItemDelegate): '''Handles the creation of an appropriate editing widget for a given property.''' ObjectRole = QtCore.Qt.UserRole + 1 @@ -110,7 +52,7 @@ def createEditor(self, parent, option, index): if editor is None: obj = index.data(self.ObjectRole) prp = index.data(self.PropertyRole) - editor = _PropertyEditorFactory[type(getattr(obj, prp))](obj, prp) + editor = PathPropertyEditor.Editor(obj, prp) index.model().setData(index, editor, self.EditorRole) return editor.widget(parent) diff --git a/src/Mod/Path/Tools/Shape/endmill.fcstd b/src/Mod/Path/Tools/Shape/endmill.fcstd index a40e5fbe5168b3cbda5f37d5ff67a630bc9b9f33..60526286e134970ae10f7c04ce4aaaa0a10c4544 100644 GIT binary patch delta 5449 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 P$uh{o%$#i@c255T>Ywf1 delta 5354 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