diff --git a/src/Mod/Path/Gui/Resources/panels/ToolBitEditor.ui b/src/Mod/Path/Gui/Resources/panels/ToolBitEditor.ui index 06b0ccad45..ab057b2dda 100644 --- a/src/Mod/Path/Gui/Resources/panels/ToolBitEditor.ui +++ b/src/Mod/Path/Gui/Resources/panels/ToolBitEditor.ui @@ -6,156 +6,209 @@ 0 0 - 411 - 886 + 587 + 744 Form - - - - - Tool Bit + + + + + 0 - - - - - Name - - - - - - - 50 - - - Display Name - - - - - - - Type - - - - - - - - 0 - - - 0 - - - 0 - - - 0 - - - - - - - - ... - - - - - - - - - - - - - Bit Parameter - - - - QFormLayout::AllNonFixedFieldsGrow + + + + 0 + 0 + 559 + 626 + - - - - Point/Tip Angle - - - - - - - 180° - - - ° - - - - - - - Cutting Edge Height - - - - - - - 0.00 - - - mm - - - - + + Shape + + + + + + Tool Bit + + + + + + Name + + + + + + + 50 + + + Display Name + + + + + + + Type + + + + + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + + + ... + + + + + + + + + + + + + Bit Parameter + + + + QFormLayout::AllNonFixedFieldsGrow + + + + + Point/Tip Angle + + + + + + + 180° + + + ° + + + + + + + Cutting Edge Height + + + + + + + 0.00 + + + mm + + + + + + + + + + + 210 + 297 + + + + Image + + + Qt::AlignCenter + + + + + + + Qt::Vertical + + + + 20 + 277 + + + + + + + + + + 0 + 0 + 559 + 626 + + + + Attributes + + + + + + + 0 + 2 + + + + + 0 + 300 + + + + QAbstractItemView::AllEditTriggers + + + true + + + + + - - - - - - - - 210 - 297 - - - - Image - - - Qt::AlignCenter - - - - - - - - - - Qt::Vertical - - - - 20 - 40 - - - - diff --git a/src/Mod/Path/PathScripts/PathSetupSheet.py b/src/Mod/Path/PathScripts/PathSetupSheet.py index 1378d91032..aaaca2732e 100644 --- a/src/Mod/Path/PathScripts/PathSetupSheet.py +++ b/src/Mod/Path/PathScripts/PathSetupSheet.py @@ -209,11 +209,7 @@ class SetupSheet: for propName in op.properties(): prop = OpPropertyName(opName, propName) if hasattr(self.obj, prop): - attr = getattr(self.obj, prop) - if hasattr(attr, 'UserString'): - settings[propName] = attr.UserString - else: - settings[propName] = attr + settings[propName] = PathUtil.getPropertyValueString(self.obj, prop) attrs[opName] = settings return attrs diff --git a/src/Mod/Path/PathScripts/PathSetupSheetOpPrototype.py b/src/Mod/Path/PathScripts/PathSetupSheetOpPrototype.py index 8c5c3e4b8d..fba3d33f0e 100644 --- a/src/Mod/Path/PathScripts/PathSetupSheetOpPrototype.py +++ b/src/Mod/Path/PathScripts/PathSetupSheetOpPrototype.py @@ -126,14 +126,23 @@ class PropertyFloat(Property): def typeString(self): return "Float" + def valueFromString(self, string): + return float(string) + class PropertyInteger(Property): def typeString(self): return "Integer" + def valueFromString(self, string): + return int(string) + class PropertyBool(Property): def typeString(self): return "Bool" + def valueFromString(self, string): + return bool(string) + class PropertyString(Property): def typeString(self): return "String" diff --git a/src/Mod/Path/PathScripts/PathToolBit.py b/src/Mod/Path/PathScripts/PathToolBit.py index 703859aaee..cfe40f387b 100644 --- a/src/Mod/Path/PathScripts/PathToolBit.py +++ b/src/Mod/Path/PathScripts/PathToolBit.py @@ -116,7 +116,8 @@ def updateConstraint(sketch, name, value): PathLog.track(name, constraint.Type, 'unchanged') break -PropertyGroupBit = 'Bit' +PropertyGroupBit = 'Bit' +PropertyGroupAttribute = 'Attribute' class ToolBit(object): @@ -128,7 +129,7 @@ class ToolBit(object): obj.addProperty('App::PropertyFile', 'File', 'Base', translate('PathToolBit', 'The file of the tool')) if templateFile is not None: obj.BitTemplate = templateFile - self._setupBitFromTemplate(obj) + self._setupBitShape(obj) self.onDocumentRestored(obj) def __getstate__(self): @@ -141,29 +142,35 @@ class ToolBit(object): break return None - def bitPropertyNames(self, obj): + 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] + def onDocumentRestored(self, obj): obj.setEditorMode('BitTemplate', 1) obj.setEditorMode('BitBody', 2) obj.setEditorMode('File', 1) obj.setEditorMode('Shape', 2) - for prop in self.bitPropertyNames(obj): + for prop in self.propertyNamesBit(obj): obj.setEditorMode(prop, 1) + # I currently don't see why these need to be read-only + #for prop in self.propertyNamesAttribute(obj): + # obj.setEditorMode(prop, 1) def onChanged(self, obj, prop): PathLog.track(obj.Label, prop) if prop == 'BitTemplate' and not 'Restore' in obj.State: - self._setupBitFromTemplate(obj) + self._setupBitShape(obj) #elif obj.getGroupOfProperty(prop) == PropertyGroupBit: # self._updateBitShape(obj, [prop]) def _updateBitShape(self, obj, properties=None): if not obj.BitBody is None: if not properties: - properties = self.bitPropertyNames(obj) + 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) @@ -203,7 +210,7 @@ class ToolBit(object): PathLog.track(obj.Label) self._removeBitBody(obj) self._copyBitShape(obj) - for prop in self.bitPropertyNames(obj): + for prop in self.propertyNamesBit(obj): obj.removeProperty(prop) def loadBitBody(self, obj, force=False): @@ -219,7 +226,7 @@ class ToolBit(object): def unloadBitBody(self, obj): self._removeBitBody(obj) - def _setupBitFromTemplate(self, obj, path=None): + def _setupBitShape(self, obj, path=None): (doc, docOpened) = self._loadBitBody(obj, path) obj.Label = doc.RootObjects[0].Label @@ -277,15 +284,30 @@ class ToolBit(object): attrs['name'] = obj.Label attrs['template'] = obj.BitTemplate params = {} - for prop in self.bitPropertyNames(obj): - params[prop] = PathUtil.getProperty(obj, prop).UserString + for name in self.propertyNamesBit(obj): + params[name] = PathUtil.getPropertyValueString(obj, name) attrs['parameter'] = params + params = {} + for name in self.propertyNamesAttribute(obj): + params[name] = PathUtil.getPropertyValueString(obj, name) + attrs['attribute'] = params return attrs def Declaration(path): with open(path, 'r') as fp: return json.load(fp) +class AttributePrototype(PathSetupSheetOpPrototype.OpPrototype): + + def __init__(self): + PathSetupSheetOpPrototype.OpPrototype.__init__(self, 'ToolBitAttribute') + self.addProperty('App::PropertyEnumeration', 'Material', PropertyGroupAttribute, translate('PathToolBit', 'Tool bit material')) + self.Material = ['Carbide', 'CastAlloy', 'Ceramics', 'Diamond', 'HighCarbonToolSteel', 'HighSpeedSteel', 'Sialon'] + self.addProperty('App::PropertyDistance', 'LengthOffset', PropertyGroupAttribute, translate('PathToolBit', 'Length offset in Z direction')) + self.addProperty('App::PropertyInteger', 'Flutes', PropertyGroupAttribute, translate('PathToolBit', 'The number of flutes')) + self.addProperty('App::PropertyDistance', 'ChipLoad', PropertyGroupAttribute, translate('PathToolBit', 'Chipload as per manufacturer')) + + class ToolBitFactory(object): def CreateFromAttrs(self, attrs, name='ToolBit'): @@ -296,6 +318,13 @@ class ToolBitFactory(object): PathUtil.setProperty(obj, prop, params[prop]) obj.Proxy._updateBitShape(obj) obj.Proxy.unloadBitBody(obj) + params = attrs['attribute'] + proto = AttributePrototype() + for pname in params: + prop = proto.getProperty(pname) + val = prop.valueFromString(params[pname]) + print("prop[%s] = %s (%s)" % (pname, params[pname], type(val))) + prop.setupProperty(obj, pname, PropertyGroupAttribute, prop.valueFromString(params[pname])) return obj def CreateFrom(self, path, name='ToolBit'): diff --git a/src/Mod/Path/PathScripts/PathToolBitEdit.py b/src/Mod/Path/PathScripts/PathToolBitEdit.py index f7ca4f2ab8..d10c66ae8c 100644 --- a/src/Mod/Path/PathScripts/PathToolBitEdit.py +++ b/src/Mod/Path/PathScripts/PathToolBitEdit.py @@ -27,19 +27,23 @@ import FreeCADGui import Path import PathScripts.PathGui as PathGui import PathScripts.PathLog as PathLog +import PathScripts.PathPreferences as PathPreferences +import PathScripts.PathSetupSheetGui as PathSetupSheetGui import PathScripts.PathToolBit as PathToolBit import copy import math import re -from PySide import QtGui +from PySide import QtCore, QtGui PathLog.setLevel(PathLog.Level.DEBUG, PathLog.thisModule()) PathLog.trackModule(PathLog.thisModule()) -LastPath = 'src/Mod/Path/Tools/Template' +# Qt translation handling +def translate(context, text, disambig=None): + return QtCore.QCoreApplication.translate(context, text, disambig) -class ToolBitEditor: +class ToolBitEditor(object): '''UI and controller for editing a ToolBit. The controller embeds the UI to the parentWidget which has to have a layout attached to it. ''' @@ -56,6 +60,7 @@ class ToolBitEditor: self.tool.BitTemplate = 'src/Mod/Path/Tools/Template/endmill-straight.fcstd' self.tool.Proxy.loadBitBody(self.tool) self.setupTool(self.tool) + self.setupAttributes(self.tool) def setupTool(self, tool): layout = self.form.bitParams.layout() @@ -78,10 +83,63 @@ class ToolBitEditor: else: self.form.image.setPixmap(QtGui.QPixmap()) + def setupAttributes(self, tool): + self.proto = PathToolBit.AttributePrototype() + self.props = sorted(self.proto.properties) + self.delegate = PathSetupSheetGui.Delegate(self.form) + self.model = QtGui.QStandardItemModel(len(self.props), 3, self.form) + self.model.setHorizontalHeaderLabels(['Set', 'Property', 'Value']) + + for i, name in enumerate(self.props): + prop = self.proto.getProperty(name) + isset = hasattr(tool, name) + if isset: + prop.setValue(getattr(tool, name)) + + self.model.setData(self.model.index(i, 0), isset, QtCore.Qt.EditRole) + self.model.setData(self.model.index(i, 1), name, QtCore.Qt.EditRole) + self.model.setData(self.model.index(i, 2), prop, PathSetupSheetGui.Delegate.PropertyRole) + self.model.setData(self.model.index(i, 2), prop.displayString(), QtCore.Qt.DisplayRole) + + self.model.item(i, 0).setCheckable(True) + self.model.item(i, 0).setText('') + self.model.item(i, 1).setEditable(False) + self.model.item(i, 1).setToolTip(prop.info) + self.model.item(i, 2).setToolTip(prop.info) + + if isset: + self.model.item(i, 0).setCheckState(QtCore.Qt.Checked) + else: + self.model.item(i, 0).setCheckState(QtCore.Qt.Unchecked) + self.model.item(i, 1).setEnabled(False) + self.model.item(i, 2).setEnabled(False) + + self.form.attrTable.setModel(self.model) + self.form.attrTable.setItemDelegateForColumn(2, self.delegate) + self.form.attrTable.resizeColumnsToContents() + self.form.attrTable.verticalHeader().hide() + + self.model.dataChanged.connect(self.updateData) + + def updateData(self, topLeft, bottomRight): + if 0 == topLeft.column(): + isset = self.model.item(topLeft.row(), 0).checkState() == QtCore.Qt.Checked + self.model.item(topLeft.row(), 1).setEnabled(isset) + self.model.item(topLeft.row(), 2).setEnabled(isset) + def accept(self): self.refresh() self.tool.Proxy.unloadBitBody(self.tool) + # get the attributes + for i, name in enumerate(self.props): + prop = self.proto.getProperty(name) + enabled = self.model.item(i, 0).checkState() == QtCore.Qt.Checked + if enabled and not prop.getValue() is None: + prop.setupProperty(self.tool, name, PathToolBit.PropertyGroupAttribute, prop.getValue()) + elif hasattr(self.tool, name): + self.obj.removeProperty(name) + def reject(self): self.tool.Proxy.unloadBitBody(self.tool) pass @@ -120,15 +178,15 @@ class ToolBitEditor: self.form.blockSignals(False) def selectTemplate(self): - global LastPath path = self.tool.BitTemplate if not path: - path = LastPath + path = PathPreferences.lastPathToolTemplate() foo = QtGui.QFileDialog.getOpenFileName(self.form, "Path - Tool Template", path, "*.fcstd") if foo and foo[0]: + PathPreferences.setLastPathToolTemplate(os.path.dirname(foo[0])) self.form.templatePath.setText(foo[0]) self.updateTemplate() diff --git a/src/Mod/Path/PathScripts/PathUtil.py b/src/Mod/Path/PathScripts/PathUtil.py index 9633c6833d..952ced9b2f 100644 --- a/src/Mod/Path/PathScripts/PathUtil.py +++ b/src/Mod/Path/PathScripts/PathUtil.py @@ -63,6 +63,13 @@ def getProperty(obj, prop): o, attr, name = _getProperty(obj, prop) # pylint: disable=unused-variable return attr +def getPropertyValueString(obj, prop): + '''getPropertyValueString(obj, prop) ... answer a string represntation of an object's property's value.''' + attr = getProperty(obj, prop) + if hasattr(attr, 'UserString'): + return attr.UserString + return str(attr) + def setProperty(obj, prop, value): '''setProperty(obj, prop, value) ... set the property value of obj's property defined by its canonical name.''' o, attr, name = _getProperty(obj, prop) # pylint: disable=unused-variable