| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| |
|
| | from PySide.QtCore import QT_TRANSLATE_NOOP |
| | import FreeCAD |
| | import Path |
| | import re |
| |
|
| | __title__ = "Generic property container to store some values." |
| | __author__ = "sliptonic (Brad Collette)" |
| | __url__ = "https://www.freecad.org" |
| | __doc__ = "A generic container for typed properties in arbitrary categories." |
| |
|
| | if False: |
| | Path.Log.setLevel(Path.Log.Level.DEBUG, Path.Log.thisModule()) |
| | Path.Log.trackModule(Path.Log.thisModule()) |
| | else: |
| | Path.Log.setLevel(Path.Log.Level.INFO, Path.Log.thisModule()) |
| |
|
| |
|
| | translate = FreeCAD.Qt.translate |
| |
|
| |
|
| | 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 getPropertyTypeName(o): |
| | for typ in SupportedPropertyType: |
| | if SupportedPropertyType[typ] == o: |
| | return typ |
| | raise IndexError() |
| |
|
| |
|
| | class PropertyBag(object): |
| | """Property container object.""" |
| |
|
| | CustomPropertyGroups = "CustomPropertyGroups" |
| | CustomPropertyGroupDefault = "User" |
| |
|
| | def __init__(self, obj): |
| | |
| | if not hasattr(obj, self.CustomPropertyGroups): |
| | obj.addProperty( |
| | "App::PropertyEnumeration", |
| | self.CustomPropertyGroups, |
| | "Base", |
| | QT_TRANSLATE_NOOP("App::Property", "List of custom property groups"), |
| | ) |
| | self.onDocumentRestored(obj) |
| |
|
| | def dumps(self): |
| | return None |
| |
|
| | def loads(self, state): |
| | return None |
| |
|
| | def __sanitizePropertyName(self, name): |
| | if len(name) == 0: |
| | return |
| | clean = name[0] |
| | for i in range(1, len(name)): |
| | if name[i] == " ": |
| | clean += name[i + 1].upper() |
| | i += 1 |
| | elif name[i - 1] != " ": |
| | clean += name[i] |
| | return clean |
| |
|
| | def onDocumentRestored(self, obj): |
| | self.obj = obj |
| | cpg = getattr(obj, self.CustomPropertyGroups, None) |
| | |
| | if isinstance(cpg, list): |
| | vals = cpg |
| | try: |
| | obj.removeProperty(self.CustomPropertyGroups) |
| | except Exception: |
| | |
| | pass |
| | obj.addProperty( |
| | "App::PropertyEnumeration", |
| | self.CustomPropertyGroups, |
| | "Base", |
| | QT_TRANSLATE_NOOP("App::Property", "List of custom property groups"), |
| | ) |
| | if hasattr(obj, "setEnumerationsOfProperty"): |
| | obj.setEnumerationsOfProperty(self.CustomPropertyGroups, vals) |
| | else: |
| | |
| | setattr(obj, self.CustomPropertyGroups, vals) |
| | if hasattr(obj, "setEditorMode"): |
| | obj.setEditorMode(self.CustomPropertyGroups, 2) |
| | elif hasattr(obj, "getEnumerationsOfProperty"): |
| | if hasattr(obj, "setEditorMode"): |
| | obj.setEditorMode(self.CustomPropertyGroups, 2) |
| |
|
| | def getCustomProperties(self): |
| | """Return a list of all custom properties created in this container.""" |
| | groups = [] |
| | if hasattr(self.obj, "getEnumerationsOfProperty"): |
| | groups = list(self.obj.getEnumerationsOfProperty(self.CustomPropertyGroups)) |
| | else: |
| | groups = list(getattr(self.obj, self.CustomPropertyGroups, [])) |
| | return [p for p in self.obj.PropertiesList if self.obj.getGroupOfProperty(p) in groups] |
| |
|
| | 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 |
| |
|
| | |
| | if hasattr(self.obj, "getEnumerationsOfProperty"): |
| | groups = list(self.obj.getEnumerationsOfProperty(self.CustomPropertyGroups)) |
| | else: |
| | groups = list(getattr(self.obj, self.CustomPropertyGroups, [])) |
| |
|
| | name = self.__sanitizePropertyName(name) |
| | if not re.match("^[A-Za-z0-9_]*$", name): |
| | raise ValueError("Property Name can only contain letters and numbers") |
| |
|
| | if group not in groups: |
| | groups.append(group) |
| | if hasattr(self.obj, "setEnumerationsOfProperty"): |
| | self.obj.setEnumerationsOfProperty(self.CustomPropertyGroups, groups) |
| | else: |
| | setattr(self.obj, self.CustomPropertyGroups, groups) |
| | self.obj.addProperty(propertyType, name, group, desc) |
| | return name |
| |
|
| | def refreshCustomPropertyGroups(self): |
| | """refreshCustomPropertyGroups() ... removes empty property groups, should be called after deleting properties.""" |
| | customGroups = [] |
| | for p in self.obj.PropertiesList: |
| | group = self.obj.getGroupOfProperty(p) |
| | if hasattr(self.obj, "getEnumerationsOfProperty"): |
| | groups = list(self.obj.getEnumerationsOfProperty(self.CustomPropertyGroups)) |
| | else: |
| | groups = list(getattr(self.obj, self.CustomPropertyGroups, [])) |
| | if group in groups and group not in customGroups: |
| | customGroups.append(group) |
| | if hasattr(self.obj, "setEnumerationsOfProperty"): |
| | self.obj.setEnumerationsOfProperty(self.CustomPropertyGroups, customGroups) |
| | else: |
| | setattr(self.obj, self.CustomPropertyGroups, customGroups) |
| |
|
| |
|
| | def Create(name="PropertyBag"): |
| | obj = FreeCAD.ActiveDocument.addObject("App::FeaturePython", name) |
| | obj.Proxy = PropertyBag(obj) |
| | return obj |
| |
|
| |
|
| | def IsPropertyBag(obj): |
| | """Returns True if the supplied object is a property container (or its Proxy).""" |
| |
|
| | if type(obj) == PropertyBag: |
| | return True |
| | if hasattr(obj, "Proxy"): |
| | return IsPropertyBag(obj.Proxy) |
| | return False |
| |
|