Basic property container with editor, no adding of properties yet
This commit is contained in:
@@ -96,6 +96,10 @@ SET(PathScripts_SRCS
|
||||
PathScripts/PathProfileFaces.py
|
||||
PathScripts/PathProfileFacesGui.py
|
||||
PathScripts/PathProfileGui.py
|
||||
PathScripts/PathProperty.py
|
||||
PathScripts/PathPropertyContainer.py
|
||||
PathScripts/PathPropertyContainerGui.py
|
||||
PathScripts/PathPropertyEditor.py
|
||||
PathScripts/PathSanity.py
|
||||
PathScripts/PathSelection.py
|
||||
PathScripts/PathSetupSheet.py
|
||||
|
||||
@@ -121,6 +121,7 @@
|
||||
<file>panels/PageOpVcarveEdit.ui</file>
|
||||
<file>panels/PathEdit.ui</file>
|
||||
<file>panels/PointEdit.ui</file>
|
||||
<file>panels/PropertyContainer.ui</file>
|
||||
<file>panels/SetupGlobal.ui</file>
|
||||
<file>panels/SetupOp.ui</file>
|
||||
<file>panels/ToolBitEditor.ui</file>
|
||||
|
||||
57
src/Mod/Path/Gui/Resources/panels/PropertyContainer.ui
Normal file
57
src/Mod/Path/Gui/Resources/panels/PropertyContainer.ui
Normal file
@@ -0,0 +1,57 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>Form</class>
|
||||
<widget class="QWidget" name="Form">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>552</width>
|
||||
<height>651</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Form</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<widget class="QTableView" name="table">
|
||||
<property name="editTriggers">
|
||||
<set>QAbstractItemView::AllEditTriggers</set>
|
||||
</property>
|
||||
<attribute name="horizontalHeaderCascadingSectionResizes">
|
||||
<bool>true</bool>
|
||||
</attribute>
|
||||
<attribute name="horizontalHeaderStretchLastSection">
|
||||
<bool>true</bool>
|
||||
</attribute>
|
||||
<attribute name="verticalHeaderVisible">
|
||||
<bool>false</bool>
|
||||
</attribute>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QWidget" name="widget" native="true">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<item>
|
||||
<widget class="QPushButton" name="remove">
|
||||
<property name="text">
|
||||
<string>Remove</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="add">
|
||||
<property name="text">
|
||||
<string>Add</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
||||
@@ -66,6 +66,7 @@ def Startup():
|
||||
# from PathScripts import PathProfileEdgesGui
|
||||
# from PathScripts import PathProfileFacesGui
|
||||
from PathScripts import PathProfileGui
|
||||
from PathScripts import PathPropertyContainerGui
|
||||
from PathScripts import PathSanity
|
||||
from PathScripts import PathSetupSheetGui
|
||||
from PathScripts import PathSimpleCopy
|
||||
|
||||
201
src/Mod/Path/PathScripts/PathProperty.py
Normal file
201
src/Mod/Path/PathScripts/PathProperty.py
Normal file
@@ -0,0 +1,201 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# ***************************************************************************
|
||||
# * Copyright (c) 2020 sliptonic <shopinthewoods@gmail.com> *
|
||||
# * *
|
||||
# * This program is free software; you can redistribute it and/or modify *
|
||||
# * it under the terms of the GNU Lesser General Public License (LGPL) *
|
||||
# * as published by the Free Software Foundation; either version 2 of *
|
||||
# * the License, or (at your option) any later version. *
|
||||
# * for detail see the LICENCE text file. *
|
||||
# * *
|
||||
# * This program is distributed in the hope that it will be useful, *
|
||||
# * but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
# * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
# * GNU Library General Public License for more details. *
|
||||
# * *
|
||||
# * You should have received a copy of the GNU Library General Public *
|
||||
# * License along with this program; if not, write to the Free Software *
|
||||
# * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 *
|
||||
# * USA *
|
||||
# * *
|
||||
# ***************************************************************************
|
||||
|
||||
import PathScripts.PathLog as PathLog
|
||||
|
||||
__title__ = "Property type abstraction for editing purposes"
|
||||
__author__ = "sliptonic (Brad Collette)"
|
||||
__url__ = "https://www.freecadweb.org"
|
||||
__doc__ = "Prototype objects to allow extraction of setup sheet values and editing."
|
||||
|
||||
|
||||
PathLog.setLevel(PathLog.Level.INFO, PathLog.thisModule())
|
||||
#PathLog.trackModule(PathLog.thisModule())
|
||||
|
||||
class Property(object):
|
||||
'''Base class for all prototype properties'''
|
||||
def __init__(self, name, propType, category, info):
|
||||
self.name = name
|
||||
self.propType = propType
|
||||
self.category = category
|
||||
self.info = info
|
||||
self.editorMode = 0
|
||||
self.value = None
|
||||
|
||||
def setValue(self, value):
|
||||
self.value = value
|
||||
def getValue(self):
|
||||
return self.value
|
||||
|
||||
def setEditorMode(self, mode):
|
||||
self.editorMode = mode
|
||||
|
||||
def displayString(self):
|
||||
if self.value is None:
|
||||
t = self.typeString()
|
||||
p = 'an' if t[0] in ['A', 'E', 'I', 'O', 'U'] else 'a'
|
||||
return "%s %s" % (p, t)
|
||||
return self.value
|
||||
|
||||
def typeString(self):
|
||||
return "Property"
|
||||
|
||||
def setupProperty(self, obj, name, category, value):
|
||||
created = False
|
||||
if not hasattr(obj, name):
|
||||
obj.addProperty(self.propType, name, category, self.info)
|
||||
self.initProperty(obj, name)
|
||||
created = True
|
||||
setattr(obj, name, value)
|
||||
return created
|
||||
|
||||
def initProperty(self, obj, name):
|
||||
pass
|
||||
|
||||
def setValueFromString(self, string):
|
||||
self.setValue(self.valueFromString(string))
|
||||
|
||||
def valueFromString(self, string):
|
||||
return string
|
||||
|
||||
class PropertyEnumeration(Property):
|
||||
def typeString(self):
|
||||
return "Enumeration"
|
||||
|
||||
def setValue(self, value):
|
||||
if list == type(value):
|
||||
self.enums = value # pylint: disable=attribute-defined-outside-init
|
||||
else:
|
||||
super(PropertyEnumeration, self).setValue(value)
|
||||
|
||||
def getEnumValues(self):
|
||||
return self.enums
|
||||
|
||||
def initProperty(self, obj, name):
|
||||
setattr(obj, name, self.enums)
|
||||
|
||||
class PropertyQuantity(Property):
|
||||
def displayString(self):
|
||||
if self.value is None:
|
||||
return Property.displayString(self)
|
||||
return self.value.getUserPreferred()[0]
|
||||
|
||||
class PropertyAngle(PropertyQuantity):
|
||||
def typeString(self):
|
||||
return "Angle"
|
||||
|
||||
class PropertyDistance(PropertyQuantity):
|
||||
def typeString(self):
|
||||
return "Distance"
|
||||
|
||||
class PropertyLength(PropertyQuantity):
|
||||
def typeString(self):
|
||||
return "Length"
|
||||
|
||||
class PropertyPercent(Property):
|
||||
def typeString(self):
|
||||
return "Percent"
|
||||
|
||||
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"
|
||||
|
||||
class PropertyMap(Property):
|
||||
def typeString(self):
|
||||
return "Map"
|
||||
|
||||
def displayString(self, value):
|
||||
return str(value)
|
||||
|
||||
class OpPrototype(object):
|
||||
|
||||
PropertyType = {
|
||||
'App::PropertyAngle': PropertyAngle,
|
||||
'App::PropertyBool': PropertyBool,
|
||||
'App::PropertyDistance': PropertyDistance,
|
||||
'App::PropertyEnumeration': PropertyEnumeration,
|
||||
'App::PropertyFile': PropertyString,
|
||||
'App::PropertyFloat': PropertyFloat,
|
||||
'App::PropertyFloatConstraint': Property,
|
||||
'App::PropertyFloatList': Property,
|
||||
'App::PropertyInteger': PropertyInteger,
|
||||
'App::PropertyIntegerList': PropertyInteger,
|
||||
'App::PropertyLength': PropertyLength,
|
||||
'App::PropertyLink': Property,
|
||||
'App::PropertyLinkList': Property,
|
||||
'App::PropertyLinkSubListGlobal': Property,
|
||||
'App::PropertyMap': PropertyMap,
|
||||
'App::PropertyPercent': PropertyPercent,
|
||||
'App::PropertyString': PropertyString,
|
||||
'App::PropertyStringList': Property,
|
||||
'App::PropertyVectorDistance': Property,
|
||||
'App::PropertyVectorList': Property,
|
||||
'Part::PropertyPartShape': Property,
|
||||
}
|
||||
|
||||
def __init__(self, name):
|
||||
self.Label = name
|
||||
self.properties = {}
|
||||
self.DoNotSetDefaultValues = True
|
||||
self.Proxy = None
|
||||
|
||||
def __setattr__(self, name, val):
|
||||
if name in ['Label', 'DoNotSetDefaultValues', 'properties', 'Proxy']:
|
||||
if name == 'Proxy':
|
||||
val = None # make sure the proxy is never set
|
||||
return super(OpPrototype, self).__setattr__(name, val)
|
||||
self.properties[name].setValue(val)
|
||||
|
||||
def addProperty(self, typeString, name, category, info = None):
|
||||
prop = self.PropertyType[typeString](name, typeString, category, info)
|
||||
self.properties[name] = prop
|
||||
return self
|
||||
|
||||
def setEditorMode(self, name, mode):
|
||||
self.properties[name].setEditorMode(mode)
|
||||
|
||||
def getProperty(self, name):
|
||||
return self.properties[name]
|
||||
|
||||
def setupProperties(self, setup):
|
||||
return [p for p in self.properties if p.name in setup]
|
||||
89
src/Mod/Path/PathScripts/PathPropertyContainer.py
Normal file
89
src/Mod/Path/PathScripts/PathPropertyContainer.py
Normal file
@@ -0,0 +1,89 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# ***************************************************************************
|
||||
# * Copyright (c) 2020 sliptonic <shopinthewoods@gmail.com> *
|
||||
# * *
|
||||
# * This program is free software; you can redistribute it and/or modify *
|
||||
# * it under the terms of the GNU Lesser General Public License (LGPL) *
|
||||
# * as published by the Free Software Foundation; either version 2 of *
|
||||
# * the License, or (at your option) any later version. *
|
||||
# * for detail see the LICENCE text file. *
|
||||
# * *
|
||||
# * This program is distributed in the hope that it will be useful, *
|
||||
# * but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
# * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
# * GNU Library General Public License for more details. *
|
||||
# * *
|
||||
# * You should have received a copy of the GNU Library General Public *
|
||||
# * License along with this program; if not, write to the Free Software *
|
||||
# * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 *
|
||||
# * USA *
|
||||
# * *
|
||||
# ***************************************************************************
|
||||
|
||||
import FreeCAD
|
||||
import PySide
|
||||
|
||||
__title__ = 'Generic property container to store some values.'
|
||||
__author__ = 'sliptonic (Brad Collette)'
|
||||
__url__ = 'https://www.freecadweb.org'
|
||||
__doc__ = 'A generic container for typed properties in arbitrary categories.'
|
||||
|
||||
def translate(context, text, disambig=None):
|
||||
return PySide.QtCore.QCoreApplication.translate(context, text, disambig)
|
||||
|
||||
|
||||
class PropertyContainer(object):
|
||||
'''Property container object.'''
|
||||
|
||||
CustomPropertyGroups = 'CustomPropertyGroups'
|
||||
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
|
||||
|
||||
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):
|
||||
obj.setEditorMode(self.CustomPropertyGroups, 2) # hide
|
||||
|
||||
def getCustomProperties(self):
|
||||
'''Return a list of all custom properties created in this container.'''
|
||||
return [p for p in self.obj.PropertiesList if self.obj.getGroupOfProperty(p) in self.obj.CustomPropertyGroups]
|
||||
|
||||
def addCustomProperty(self, propertyType, name, group=None, desc=None):
|
||||
'''addCustomProperty(propertyType, name, group=None, desc=None) ... adds a custom property and tracks its group.'''
|
||||
if desc is None:
|
||||
desc = ''
|
||||
if group is None:
|
||||
group = self.CustomPropertyGroupDefault
|
||||
groups = self.obj.CustomPropertyGroups
|
||||
if not group in groups:
|
||||
groups.append(group)
|
||||
self.obj.CustomPropertyGroups = groups
|
||||
self.obj.addProperty(propertyType, name, group, desc)
|
||||
|
||||
def Create(name = 'PropertyContainer'):
|
||||
obj = FreeCAD.ActiveDocument.addObject('App::FeaturePython', name)
|
||||
obj.Proxy = PropertyContainer(obj)
|
||||
return obj
|
||||
|
||||
def IsPropertyContainer(obj):
|
||||
'''Returns True if the supplied object is a property container (or its Proxy).'''
|
||||
|
||||
if type(obj) == PropertyContainer:
|
||||
return True
|
||||
if hasattr(obj, 'Proxy'):
|
||||
return IsPropertyContainer(obj.Proxy)
|
||||
return False
|
||||
|
||||
235
src/Mod/Path/PathScripts/PathPropertyContainerGui.py
Normal file
235
src/Mod/Path/PathScripts/PathPropertyContainerGui.py
Normal file
@@ -0,0 +1,235 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# ***************************************************************************
|
||||
# * Copyright (c) 2020 sliptonic <shopinthewoods@gmail.com> *
|
||||
# * *
|
||||
# * This program is free software; you can redistribute it and/or modify *
|
||||
# * it under the terms of the GNU Lesser General Public License (LGPL) *
|
||||
# * as published by the Free Software Foundation; either version 2 of *
|
||||
# * the License, or (at your option) any later version. *
|
||||
# * for detail see the LICENCE text file. *
|
||||
# * *
|
||||
# * This program is distributed in the hope that it will be useful, *
|
||||
# * but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
# * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
# * GNU Library General Public License for more details. *
|
||||
# * *
|
||||
# * You should have received a copy of the GNU Library General Public *
|
||||
# * License along with this program; if not, write to the Free Software *
|
||||
# * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 *
|
||||
# * USA *
|
||||
# * *
|
||||
# ***************************************************************************
|
||||
|
||||
import FreeCAD
|
||||
import FreeCADGui
|
||||
import PathScripts.PathGui as PathGui
|
||||
import PathScripts.PathIconViewProvider as PathIconViewProvider
|
||||
import PathScripts.PathLog as PathLog
|
||||
import PathScripts.PathPropertyContainer as PathPropertyContainer
|
||||
import PathScripts.PathPropertyEditor as PathPropertyEditor
|
||||
import PathScripts.PathUtil as PathUtil
|
||||
|
||||
from PySide import QtCore, QtGui
|
||||
|
||||
__title__ = "Property Container Editor"
|
||||
__author__ = "sliptonic (Brad Collette)"
|
||||
__url__ = "https://www.freecadweb.org"
|
||||
__doc__ = "Task panel editor for a PropertyContainer"
|
||||
|
||||
PathLog.setLevel(PathLog.Level.DEBUG, PathLog.thisModule())
|
||||
PathLog.trackModule(PathLog.thisModule())
|
||||
|
||||
# Qt translation handling
|
||||
def translate(context, text, disambig=None):
|
||||
return QtCore.QCoreApplication.translate(context, text, disambig)
|
||||
|
||||
|
||||
class ViewProvider:
|
||||
'''ViewProvider for a PropertyContainer.
|
||||
It's sole job is to provide an icon and invoke the TaskPanel on edit.'''
|
||||
|
||||
def __init__(self, vobj, name):
|
||||
PathLog.track(name)
|
||||
vobj.Proxy = self
|
||||
self.icon = name
|
||||
# mode = 2
|
||||
self.obj = None
|
||||
self.vobj = None
|
||||
|
||||
def attach(self, vobj):
|
||||
PathLog.track()
|
||||
self.vobj = vobj
|
||||
self.obj = vobj.Object
|
||||
|
||||
def getIcon(self):
|
||||
return ":/icons/Path-SetupSheet.svg"
|
||||
|
||||
def __getstate__(self):
|
||||
return None
|
||||
|
||||
def __setstate__(self, state):
|
||||
# pylint: disable=unused-argument
|
||||
return None
|
||||
|
||||
def getDisplayMode(self, mode):
|
||||
# pylint: disable=unused-argument
|
||||
return 'Default'
|
||||
|
||||
def setEdit(self, vobj, mode=0):
|
||||
# pylint: disable=unused-argument
|
||||
PathLog.track()
|
||||
taskPanel = TaskPanel(vobj)
|
||||
FreeCADGui.Control.closeDialog()
|
||||
FreeCADGui.Control.showDialog(taskPanel)
|
||||
taskPanel.setupUi()
|
||||
return True
|
||||
|
||||
def unsetEdit(self, vobj, mode):
|
||||
# pylint: disable=unused-argument
|
||||
FreeCADGui.Control.closeDialog()
|
||||
return
|
||||
|
||||
def claimChildren(self):
|
||||
return []
|
||||
|
||||
def doubleClicked(self, vobj):
|
||||
self.setEdit(vobj)
|
||||
|
||||
class Delegate(QtGui.QStyledItemDelegate):
|
||||
RoleObject = QtCore.Qt.UserRole + 1
|
||||
RoleProperty = QtCore.Qt.UserRole + 2
|
||||
RoleEditor = QtCore.Qt.UserRole + 3
|
||||
|
||||
|
||||
#def paint(self, painter, option, index):
|
||||
# #PathLog.track(index.column(), type(option))
|
||||
|
||||
def createEditor(self, parent, option, index):
|
||||
# pylint: disable=unused-argument
|
||||
editor = PathPropertyEditor.Editor(index.data(self.RoleObject), index.data(self.RoleProperty))
|
||||
index.model().setData(index, editor, self.RoleEditor)
|
||||
return editor.widget(parent)
|
||||
|
||||
def setEditorData(self, widget, index):
|
||||
PathLog.track(index.row(), index.column())
|
||||
index.data(self.RoleEditor).setEditorData(widget)
|
||||
|
||||
def setModelData(self, widget, model, index):
|
||||
# pylint: disable=unused-argument
|
||||
PathLog.track(index.row(), index.column())
|
||||
editor = index.data(self.RoleEditor)
|
||||
editor.setModelData(widget)
|
||||
index.model().setData(index, editor.displayString(), QtCore.Qt.DisplayRole)
|
||||
|
||||
def updateEditorGeometry(self, widget, option, index):
|
||||
# pylint: disable=unused-argument
|
||||
widget.setGeometry(option.rect)
|
||||
|
||||
class TaskPanel:
|
||||
ColumnName = 0
|
||||
ColumnVal = 1
|
||||
ColumnDesc = 2
|
||||
|
||||
def __init__(self, vobj):
|
||||
self.obj = vobj.Object
|
||||
self.props = sorted(self.obj.Proxy.getCustomProperties())
|
||||
self.form = FreeCADGui.PySideUic.loadUi(":panels/PropertyContainer.ui")
|
||||
|
||||
# initialized later
|
||||
self.delegate = None
|
||||
self.model = None
|
||||
FreeCAD.ActiveDocument.openTransaction(translate("PathPropertyContainer", "Edit PropertyContainer"))
|
||||
|
||||
def updateData(self, topLeft, bottomRight):
|
||||
# pylint: disable=unused-argument
|
||||
#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)
|
||||
print("index = ({}, {}) - ({}, {})".format(topLeft.row(), topLeft.column(), bottomRight.row(), bottomRight.column()))
|
||||
if topLeft.column() == self.ColumnDesc:
|
||||
obj = topLeft.data(Delegate.RoleObject)
|
||||
prop = topLeft.data(Delegate.RoleProperty)
|
||||
|
||||
def setupUi(self):
|
||||
PathLog.track()
|
||||
|
||||
self.delegate = Delegate(self.form)
|
||||
self.model = QtGui.QStandardItemModel(len(self.props), 3, self.form)
|
||||
self.model.setHorizontalHeaderLabels(['Property', 'Value', 'Description'])
|
||||
|
||||
for i,name in enumerate(self.props):
|
||||
info = self.obj.getDocumentationOfProperty(name)
|
||||
value = self.obj.getPropertyByName(name)
|
||||
self.model.setData(self.model.index(i, self.ColumnName), name, QtCore.Qt.EditRole)
|
||||
self.model.setData(self.model.index(i, self.ColumnVal), self.obj, Delegate.RoleObject)
|
||||
self.model.setData(self.model.index(i, self.ColumnVal), name, Delegate.RoleProperty)
|
||||
self.model.setData(self.model.index(i, self.ColumnVal), str(value), QtCore.Qt.DisplayRole)
|
||||
self.model.setData(self.model.index(i, self.ColumnDesc), info, QtCore.Qt.EditRole)
|
||||
|
||||
self.model.item(i, self.ColumnName).setEditable(False)
|
||||
|
||||
self.form.table.setModel(self.model)
|
||||
self.form.table.setItemDelegateForColumn(self.ColumnVal, self.delegate)
|
||||
self.form.table.resizeColumnsToContents()
|
||||
|
||||
self.model.dataChanged.connect(self.updateData)
|
||||
self.form.table.selectionModel().selectionChanged.connect(self.propertySelected)
|
||||
self.form.add.clicked.connect(self.propertyAdd)
|
||||
self.form.remove.clicked.connect(self.propertyRemove)
|
||||
self.propertySelected([])
|
||||
|
||||
def accept(self):
|
||||
#propertiesCreatedRemoved = False
|
||||
#for i,name in enumerate(self.props):
|
||||
# prop = self.prototype.getProperty(name)
|
||||
# propName = self.propertyName(name)
|
||||
# enabled = self.model.item(i, 0).checkState() == QtCore.Qt.Checked
|
||||
# if enabled and not prop.getValue() is None:
|
||||
# if prop.setupProperty(self.obj, propName, self.propertyGroup(), prop.getValue()):
|
||||
# propertiesCreatedRemoved = True
|
||||
# else:
|
||||
# if hasattr(self.obj, propName):
|
||||
# self.obj.removeProperty(propName)
|
||||
# propertiesCreatedRemoved = True
|
||||
|
||||
FreeCAD.ActiveDocument.commitTransaction()
|
||||
FreeCADGui.ActiveDocument.resetEdit()
|
||||
FreeCADGui.Control.closeDialog()
|
||||
FreeCAD.ActiveDocument.recompute()
|
||||
|
||||
def reject(self):
|
||||
FreeCAD.ActiveDocument.abortTransaction()
|
||||
FreeCADGui.Control.closeDialog()
|
||||
FreeCAD.ActiveDocument.recompute()
|
||||
|
||||
def propertySelected(self, selection):
|
||||
PathLog.track()
|
||||
if selection:
|
||||
self.form.remove.setEnabled(True)
|
||||
else:
|
||||
self.form.remove.setEnabled(False)
|
||||
|
||||
def propertyAdd(self):
|
||||
PathLog.track()
|
||||
|
||||
def propertyRemove(self):
|
||||
PathLog.track()
|
||||
rows = []
|
||||
for index in self.form.table.selectionModel().selectedIndexes():
|
||||
if not index.row() in rows:
|
||||
rows.append(index.row())
|
||||
for row in reversed(sorted(rows)):
|
||||
self.obj.removeProperty(self.model.item(row).data(QtCore.Qt.EditRole))
|
||||
self.model.removeRow(row)
|
||||
|
||||
|
||||
def Create(name = 'PropertyContainer'):
|
||||
'''Create(name = 'PropertyContainer') ... creates a new setup sheet'''
|
||||
FreeCAD.ActiveDocument.openTransaction(translate("PathPropertyContainer", "Create PropertyContainer"))
|
||||
pcont = PathPropertyContainer.Create(name)
|
||||
PathIconViewProvider.Attach(pcont.ViewObject, name)
|
||||
return pcont
|
||||
|
||||
PathIconViewProvider.RegisterViewProvider('PropertyContainer', ViewProvider)
|
||||
|
||||
219
src/Mod/Path/PathScripts/PathPropertyEditor.py
Normal file
219
src/Mod/Path/PathScripts/PathPropertyEditor.py
Normal file
@@ -0,0 +1,219 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# ***************************************************************************
|
||||
# * Copyright (c) 2020 sliptonic <shopinthewoods@gmail.com> *
|
||||
# * *
|
||||
# * This program is free software; you can redistribute it and/or modify *
|
||||
# * it under the terms of the GNU Lesser General Public License (LGPL) *
|
||||
# * as published by the Free Software Foundation; either version 2 of *
|
||||
# * the License, or (at your option) any later version. *
|
||||
# * for detail see the LICENCE text file. *
|
||||
# * *
|
||||
# * This program is distributed in the hope that it will be useful, *
|
||||
# * but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
# * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
# * GNU Library General Public License for more details. *
|
||||
# * *
|
||||
# * You should have received a copy of the GNU Library General Public *
|
||||
# * License along with this program; if not, write to the Free Software *
|
||||
# * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 *
|
||||
# * USA *
|
||||
# * *
|
||||
# ***************************************************************************
|
||||
|
||||
import FreeCAD
|
||||
import PathScripts.PathLog as PathLog
|
||||
import PathScripts.PathSetupSheetOpPrototype as PathSetupSheetOpPrototype
|
||||
|
||||
from PySide import QtCore, QtGui
|
||||
|
||||
__title__ = "Path Property Editor"
|
||||
__author__ = "sliptonic (Brad Collette)"
|
||||
__url__ = "https://www.freecadweb.org"
|
||||
__doc__ = "Task panel editor for Properties"
|
||||
|
||||
# Qt translation handling
|
||||
def translate(context, text, disambig=None):
|
||||
return QtCore.QCoreApplication.translate(context, text, disambig)
|
||||
|
||||
LOGLEVEL = False
|
||||
|
||||
if LOGLEVEL:
|
||||
PathLog.setLevel(PathLog.Level.DEBUG, PathLog.thisModule())
|
||||
PathLog.trackModule(PathLog.thisModule())
|
||||
else:
|
||||
PathLog.setLevel(PathLog.Level.INFO, PathLog.thisModule())
|
||||
|
||||
class _PropertyEditor(object):
|
||||
'''Base class of all property editors - just outlines the TableView delegate interface.'''
|
||||
def __init__(self, obj, prop):
|
||||
self.obj = obj
|
||||
self.prop = prop
|
||||
|
||||
def widget(self, parent):
|
||||
'''widget(parent) ... called by the delegate to get a new editor widget.
|
||||
Must be implemented by subclasses and return the widget.'''
|
||||
pass # pylint: disable=unnecessary-pass
|
||||
|
||||
def setEditorData(self, widget):
|
||||
'''setEditorData(widget) ... called by the delegate to initialize the editor.
|
||||
The widget is the object returned by widget().
|
||||
Must be implemented by subclasses.'''
|
||||
pass # pylint: disable=unnecessary-pass
|
||||
|
||||
def setModelData(self, widget):
|
||||
'''setModelData(widget) ... called by the delegate to store new values.
|
||||
Must be implemented by subclasses.'''
|
||||
pass # pylint: disable=unnecessary-pass
|
||||
|
||||
def propertyValue(self):
|
||||
return self.obj.getPropertyByName(self.prop)
|
||||
|
||||
def setProperty(self, value):
|
||||
setattr(self.obj, self.prop, value)
|
||||
|
||||
def displayString(self):
|
||||
return self.propertyValue()
|
||||
|
||||
class _PropertyEditorBool(_PropertyEditor):
|
||||
'''Editor for boolean values - uses a combo box.'''
|
||||
|
||||
def widget(self, parent):
|
||||
return QtGui.QComboBox(parent)
|
||||
|
||||
def setEditorData(self, widget):
|
||||
widget.clear()
|
||||
widget.addItems(['false', 'true'])
|
||||
index = 1 if self.propertyValue() else 0
|
||||
widget.setCurrentIndex(index)
|
||||
|
||||
def setModelData(self, widget):
|
||||
self.setProperty(widget.currentText() == 'true')
|
||||
|
||||
class _PropertyEditorString(_PropertyEditor):
|
||||
'''Editor for string values - uses a line edit.'''
|
||||
|
||||
def widget(self, parent):
|
||||
return QtGui.QLineEdit(parent)
|
||||
|
||||
def setEditorData(self, widget):
|
||||
text = '' if self.propertyValue() is None else self.propertyValue()
|
||||
widget.setText(text)
|
||||
|
||||
def setModelData(self, widget):
|
||||
self.setProperty(widget.text())
|
||||
|
||||
class _PropertyEditorQuantity(_PropertyEditor):
|
||||
|
||||
def widget(self, parent):
|
||||
return QtGui.QLineEdit(parent)
|
||||
|
||||
def setEditorData(self, widget):
|
||||
quantity = self.propertyValue()
|
||||
if quantity is None:
|
||||
quantity = self.defaultQuantity()
|
||||
widget.setText(quantity.getUserPreferred()[0])
|
||||
|
||||
def defaultQuantity(self):
|
||||
pass
|
||||
|
||||
def setModelData(self, widget):
|
||||
self.setProperty(FreeCAD.Units.Quantity(widget.text()))
|
||||
|
||||
def displayString(self):
|
||||
if self.propertyValue() is None:
|
||||
return ''
|
||||
return self.propertyValue().getUserPreferred()[0]
|
||||
|
||||
class _PropertyEditorAngle(_PropertyEditorQuantity):
|
||||
'''Editor for angle values - uses a line edit'''
|
||||
|
||||
def defaultQuantity(self):
|
||||
return FreeCAD.Units.Quantity(0, FreeCAD.Units.Angle)
|
||||
|
||||
class _PropertyEditorLength(_PropertyEditorQuantity):
|
||||
'''Editor for length values - uses a line edit.'''
|
||||
|
||||
def defaultQuantity(self):
|
||||
return FreeCAD.Units.Quantity(0, FreeCAD.Units.Length)
|
||||
|
||||
class _PropertyEditorPercent(_PropertyEditor):
|
||||
'''Editor for percent values - uses a spin box.'''
|
||||
|
||||
def widget(self, parent):
|
||||
return QtGui.QSpinBox(parent)
|
||||
|
||||
def setEditorData(self, widget):
|
||||
widget.setRange(0, 100)
|
||||
value = self.propertyValue()
|
||||
if value is None:
|
||||
value = 0
|
||||
widget.setValue(value)
|
||||
|
||||
def setModelData(self, widget):
|
||||
self.setProperty(widget.value())
|
||||
|
||||
class _PropertyEditorInteger(_PropertyEditor):
|
||||
'''Editor for integer values - uses a spin box.'''
|
||||
|
||||
def widget(self, parent):
|
||||
return QtGui.QSpinBox(parent)
|
||||
|
||||
def setEditorData(self, widget):
|
||||
value = self.propertyValue()
|
||||
if value is None:
|
||||
value = 0
|
||||
widget.setValue(value)
|
||||
|
||||
def setModelData(self, widget):
|
||||
self.setProperty(widget.value())
|
||||
|
||||
class _PropertyEditorFloat(_PropertyEditor):
|
||||
'''Editor for float values - uses a double spin box.'''
|
||||
|
||||
def widget(self, parent):
|
||||
return QtGui.QDoubleSpinBox(parent)
|
||||
|
||||
def setEditorData(self, widget):
|
||||
value = self.propertyValue()
|
||||
if value is None:
|
||||
value = 0.0
|
||||
widget.setValue(value)
|
||||
|
||||
def setModelData(self, widget):
|
||||
self.setProperty(widget.value())
|
||||
|
||||
class _PropertyEditorFile(_PropertyEditor):
|
||||
|
||||
def widget(self, parent):
|
||||
return QtGui.QLineEdit(parent)
|
||||
|
||||
def setEditorData(self, widget):
|
||||
text = '' if self.propertyValue() is None else self.propertyValue()
|
||||
widget.setText(text)
|
||||
|
||||
def setModelData(self, widget):
|
||||
self.setProperty(widget.text())
|
||||
|
||||
_EditorFactory = {
|
||||
'App::PropertyAngle' : _PropertyEditorAngle,
|
||||
'App::PropertyBool' : _PropertyEditorBool,
|
||||
'App::PropertyDistance' : _PropertyEditorLength,
|
||||
#'App::PropertyEnumeration' : _PropertyEditorEnum,
|
||||
#'App::PropertyFile' : _PropertyEditorFile,
|
||||
'App::PropertyFloat' : _PropertyEditorFloat,
|
||||
'App::PropertyInteger' : _PropertyEditorInteger,
|
||||
'App::PropertyLength' : _PropertyEditorLength,
|
||||
'App::PropertyPercent' : _PropertyEditorPercent,
|
||||
'App::PropertyString' : _PropertyEditorString,
|
||||
}
|
||||
|
||||
def Types():
|
||||
'''Return the types of properties supported.'''
|
||||
return [t for t in _EditorFactory]
|
||||
|
||||
def Editor(obj, prop):
|
||||
'''Returns an editor class to be used for the given property.'''
|
||||
factory = _EditorFactory[obj.getTypeIdOfProperty(prop)]
|
||||
if factory:
|
||||
return factory(obj, prop)
|
||||
return None
|
||||
Reference in New Issue
Block a user