Skip to content

Commit

Permalink
Basic property container with editor, no adding of properties yet
Browse files Browse the repository at this point in the history
  • Loading branch information
mlampert committed Jan 27, 2021
1 parent 2f731b7 commit dd3a4be
Show file tree
Hide file tree
Showing 8 changed files with 807 additions and 0 deletions.
4 changes: 4 additions & 0 deletions src/Mod/Path/CMakeLists.txt
Expand Up @@ -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
Expand Down
1 change: 1 addition & 0 deletions src/Mod/Path/Gui/Resources/Path.qrc
Expand Up @@ -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>
Expand Down
57 changes: 57 additions & 0 deletions src/Mod/Path/Gui/Resources/panels/PropertyContainer.ui
@@ -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>
1 change: 1 addition & 0 deletions src/Mod/Path/PathScripts/PathGuiInit.py
Expand Up @@ -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
Expand Down
201 changes: 201 additions & 0 deletions src/Mod/Path/PathScripts/PathProperty.py
@@ -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 changes: 89 additions & 0 deletions src/Mod/Path/PathScripts/PathPropertyContainer.py
@@ -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

0 comments on commit dd3a4be

Please sign in to comment.