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