Using property container for endmill attributes.
This commit is contained in:
@@ -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):
|
||||
|
||||
@@ -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):
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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()
|
||||
|
||||
Binary file not shown.
Reference in New Issue
Block a user