From 78146228fcf115075b8bb0a7a053f35c55353856 Mon Sep 17 00:00:00 2001 From: Suzanne Soy Date: Sat, 6 Mar 2021 04:07:27 +0000 Subject: [PATCH] 02021-03-06 stream: convert XForms select1 to a FreeCad PropertyEnumeration --- XternalAppsParametricTool.py | 61 ++++++++++++++++++++++++++---------- myTool.xforms | 1 + 2 files changed, 46 insertions(+), 16 deletions(-) diff --git a/XternalAppsParametricTool.py b/XternalAppsParametricTool.py index bdf3dc6..9bd8988 100644 --- a/XternalAppsParametricTool.py +++ b/XternalAppsParametricTool.py @@ -4,8 +4,12 @@ import FreeCADGui from lxml import etree import ExternalAppsList from ToolXML import * +from collections import namedtuple import re +XFormsInput = namedtuple('XFormsInput', ['input', 'modelElement', 'type', 'maybeEnum']) +XFormsEnum = namedtuple('XFormsEnum', ['labels', 'values']) + def CreateCommand(appName, toolName): App.ActiveDocument.openTransaction('Create parametric %s from %s'%(toolName, appName)) FreeCADGui.addModule("XternalAppsParametricTool") @@ -25,10 +29,12 @@ typeToFreeCADTypeDict = { 'xsd:string': 'App::PropertyString', } -def typeToFreeCADType(type): - if type.startswith('mime:'): +def typeToFreeCADType(type, maybeEnum): + if maybeEnum is not None: + return 'App::PropertyEnumeration' + elif type.startswith('mime:'): return MIMETypeToFreeCADType(MIMEType[5:]) - if type in typeToFreeCADTypeDict: + elif type in typeToFreeCADTypeDict: return typeToFreeCADTypeDict[type] else: raise ArgumentException('Unsupported XForms type') @@ -47,10 +53,24 @@ class XternalAppsParametricTool(): obj.Proxy = self self.createPropertiesFromXML(obj) + def interpretFormElement(self, xmlXFormsElement, xml, instanceDocument, types): + # TODO: is it safe to pass input unprotected here? + modelElement = instanceDocument.find(xmlXFormsElement.attrib['ref'], + namespaces=xmlXFormsElement.nsmap) + if modelElement is None: + raise Exception('Could not find ' + xmlXFormsElement.attrib['ref'] \ + + ' in instance document with namespaces=' + repr(xmlXFormsElement.nsmap)) + type = types.get(instanceDocument.getpath(modelElement)) + if type is None: + raise Exception('Could not find type for ' + instanceDocument.getpath(modelElement)) + path = xml.getpath(xmlXFormsElement) + return (path, xmlXFormsElement, modelElement, type) + def interpretXML(self): - """Parse the self.Tool.XForms document, and return the parsed xml, - a dictionary types[path] = "type", and a dictionary - inputs[path] = (xml_input_element, xml_model_element, type).""" + """Parse the self.Tool.XForms document, and return + * the parsed xml, + * a dictionary types[path] = "type" + * a dictionary inputs[path] = (xml_input_element, xml_model_element, type).""" types = {} modelInstance = {} inputs = {} @@ -77,24 +97,33 @@ class XternalAppsParametricTool(): # register all inputs to inputs[pathToElement] for group in xml.findall('./xforms:group', ns): for input in group.findall('./xforms:input', ns): - # TODO: is it safe to pass input unprotected here? - modelElement = instanceDocument.find(input.attrib['ref'], namespaces=input.nsmap) - if modelElement is None: - raise Exception('Could not find ' + input.attrib['ref'] \ - + ' in instance document with namespaces=' + repr(input.nsmap)) - type = types[instanceDocument.getpath(modelElement)] - inputs[xml.getpath(input)] = (input, modelElement, type) + path, xmlXFormsElement, modelElement, type = self.interpretFormElement(input, xml, instanceDocument, types) + inputs[path] = XFormsInput(input=xmlXFormsElement, modelElement=modelElement, type=type, maybeEnum=None) + for select1 in group.findall('./xforms:select1', ns): + path, xmlXFormsElement, modelElement, type = self.interpretFormElement(select1, xml, instanceDocument, types) + # Gather the allowed elements for the enum + enum = {} + for item in select1.findall('./xforms:item', ns): + enum[item.attrib['label']] = item.attrib['value'] + inputs[path] = XFormsInput(input=xmlXFormsElement, modelElement=modelElement, type=type, maybeEnum=enum) return (xml, types, modelInstance, inputs) + def toSimpleName(self, name): + return re.sub(r'( |[^-a-zA-Z0-9])+', ' ', name).title().replace(' ', '') + def createPropertiesFromXML(self, obj): xml, types, modelInstance, inputs = self.interpretXML() - for (input, modelElement, type) in inputs.values(): - simpleName = re.sub(r'( |[^-a-zA-Z0-9])+', ' ', input.attrib['label']).title().replace(' ', '') + for (input, modelElement, type, maybeEnum) in inputs.values(): + simpleName = self.toSimpleName(input.attrib['label']) group = "/".join(input.xpath('ancestor-or-self::xforms:group/xforms:label/text()', namespaces=ns)) or None - obj.addProperty(typeToFreeCADType(type), + print((simpleName, typeToFreeCADType(type, maybeEnum), maybeEnum)) + obj.addProperty(typeToFreeCADType(type, maybeEnum), simpleName, group, input.attrib['label'] + '\nA value of type ' + type) + if maybeEnum is not None: + setattr(obj, simpleName, [self.toSimpleName(k) for k in maybeEnum.keys()]) + # TODO: have a converter from the labels to the values @property def Tool(self): diff --git a/myTool.xforms b/myTool.xforms index 472fac2..c58450b 100644 --- a/myTool.xforms +++ b/myTool.xforms @@ -24,6 +24,7 @@ +