r2740 - in trunk: jaxx-compiler/src/main/java/jaxx/compiler/finalizers jaxx-compiler/src/main/java/jaxx/compiler/tags/validator jaxx-maven-plugin/src/test/java/org/nuiton/jaxx/plugin jaxx-maven-plugin/src/test/resources/org/nuiton/jaxx/plugin/compilerValidatorTest/validator/errors jaxx-maven-plugin/src/test/resources/org/nuiton/jaxx/plugin/compilerValidatorTest/validator/ok jaxx-validator/src/main/java/jaxx/runtime/validator/swing jaxx-validator/src/main/java/jaxx/runtime/validator/swing/meta
Author: tchemit Date: 2013-10-17 17:49:11 +0200 (Thu, 17 Oct 2013) New Revision: 2740 Url: http://nuiton.org/projects/jaxx/repository/revisions/2740 Log: refs #2878: Validate more than one bean property with one editor Added: trunk/jaxx-maven-plugin/src/test/resources/org/nuiton/jaxx/plugin/compilerValidatorTest/validator/ok/FieldComponentDuplicated.jaxx Removed: trunk/jaxx-maven-plugin/src/test/resources/org/nuiton/jaxx/plugin/compilerValidatorTest/validator/errors/FieldComponentDuplicated.jaxx Modified: trunk/jaxx-compiler/src/main/java/jaxx/compiler/finalizers/ValidatorFinalizer.java trunk/jaxx-compiler/src/main/java/jaxx/compiler/tags/validator/BeanValidatorHandler.java trunk/jaxx-compiler/src/main/java/jaxx/compiler/tags/validator/ExcludeFieldValidatorHandler.java trunk/jaxx-compiler/src/main/java/jaxx/compiler/tags/validator/FieldValidatorHandler.java trunk/jaxx-maven-plugin/src/test/java/org/nuiton/jaxx/plugin/CompilerValidatorTest.java trunk/jaxx-validator/src/main/java/jaxx/runtime/validator/swing/SwingValidatorUtil.java trunk/jaxx-validator/src/main/java/jaxx/runtime/validator/swing/meta/ValidatorField.java Modified: trunk/jaxx-compiler/src/main/java/jaxx/compiler/finalizers/ValidatorFinalizer.java =================================================================== --- trunk/jaxx-compiler/src/main/java/jaxx/compiler/finalizers/ValidatorFinalizer.java 2013-10-11 13:04:20 UTC (rev 2739) +++ trunk/jaxx-compiler/src/main/java/jaxx/compiler/finalizers/ValidatorFinalizer.java 2013-10-17 15:49:11 UTC (rev 2740) @@ -25,6 +25,8 @@ package jaxx.compiler.finalizers; +import com.google.common.base.Joiner; +import com.google.common.collect.Lists; import jaxx.compiler.CompiledObject; import jaxx.compiler.CompiledObject.ChildRef; import jaxx.compiler.CompilerException; @@ -47,8 +49,8 @@ import java.lang.reflect.Modifier; import java.util.ArrayList; +import java.util.Collection; import java.util.List; -import java.util.Map; /** * To finalize validators fields. @@ -206,24 +208,38 @@ String validatorAnnotation = type + "( validatorId = " + validatorId + ")"; validatorField.addAnnotation(validatorAnnotation); - Map<String, String> fields = validator.getFields(); +// Map<String, String> fields = validator.getFields(); - for (Map.Entry<String, String> entry : fields.entrySet()) { - String propertyName = entry.getKey(); - String component = entry.getValue(); + for (String component : validator.getFieldEditors()) { - if (!validator.checkBeanProperty(compiler, propertyName)) { - // property not find on bean + Collection<String> propertyNames = validator.getFieldPropertyNames(component); + List<String> keyCodes = + Lists.newArrayListWithCapacity(propertyNames.size()); + for (String propertyName : propertyNames) { + if (!validator.checkBeanProperty(compiler, propertyName)) { + // property not find on bean + continue; + } + String keyCode = TypeManager.getJavaCode(propertyName); + keyCodes.add(keyCode); + } + + if (keyCodes.isEmpty()) { + // no property continue; } + String keyCode = Joiner.on(", ").join(keyCodes); + if (keyCodes.size()>1) { + keyCode = "{ " + keyCode+" }"; + } - String keyCode = TypeManager.getJavaCode(propertyName); +// String keyCode = TypeManager.getJavaCode(propertyName); String editorCode = TypeManager.getJavaCode(component); JavaElement editor = javaFile.getField(component); if (editor == null) { if (log.isDebugEnabled()) { String message = "Could not find editor [" + component + - "] for property [" + propertyName + + "] for property(ies) [" + propertyNames + "] for file " + javaFile.getName(); log.debug(message); } @@ -239,7 +255,7 @@ String errorMessage = "Could not find editor [" + component + - "] for property [" + propertyName + + "] for property(ies) [" + propertyNames + "] for file " + javaFile.getName(); throw new CompilerException(errorMessage); Modified: trunk/jaxx-compiler/src/main/java/jaxx/compiler/tags/validator/BeanValidatorHandler.java =================================================================== --- trunk/jaxx-compiler/src/main/java/jaxx/compiler/tags/validator/BeanValidatorHandler.java 2013-10-11 13:04:20 UTC (rev 2739) +++ trunk/jaxx-compiler/src/main/java/jaxx/compiler/tags/validator/BeanValidatorHandler.java 2013-10-17 15:49:11 UTC (rev 2740) @@ -25,6 +25,10 @@ package jaxx.compiler.tags.validator; +import com.google.common.base.Joiner; +import com.google.common.collect.ArrayListMultimap; +import com.google.common.collect.Lists; +import com.google.common.collect.Multimap; import jaxx.compiler.CompiledObject; import jaxx.compiler.CompilerException; import jaxx.compiler.JAXXCompiler; @@ -48,10 +52,11 @@ import java.io.IOException; import java.util.ArrayList; +import java.util.Collection; import java.util.HashMap; import java.util.List; import java.util.Map; -import java.util.Map.Entry; +import java.util.Set; import java.util.TreeMap; public class BeanValidatorHandler extends DefaultObjectHandler { @@ -217,8 +222,18 @@ */ public static class CompiledBeanValidator extends CompiledObject { - protected Map<String, String> fields; + /** + * Map of field to add into validator. + * <p/> + * Keys are editors, Values are bean properties. + */ + protected Multimap<String, String> fields; + /** + * Map of field to exclude. + * <p/> + * Keys are bean properties, Values are editors. + */ protected Map<String, String> excludeFields; protected String bean; @@ -252,7 +267,7 @@ //TC-20090524 otherwise can not override the validator class while generation //super(id, objectClass, compiler); super(id, getDescriptor(objectClass, compiler), compiler); - fields = new TreeMap<String, String>(); + fields = ArrayListMultimap.create(); excludeFields = new TreeMap<String, String>(); if (log.isDebugEnabled()) { log.debug("validator objectClass " + getObjectClass()); @@ -269,22 +284,77 @@ return result; } - public Map<String, String> getFields() { + public Multimap<String, String> getFields() { return fields; } - public Map<String, String> getExcludeFields() { - return excludeFields; + public boolean containsFieldEditor(String editorName) { + return fields.containsKey(editorName); } - public void setFields(Map<String, String> fields) { - this.fields = fields; + public boolean containsFieldPropertyName(String propertyName) { + return fields.containsValue(propertyName); } - public void setExcludeFields(Map<String, String> excludeFields) { - this.excludeFields = excludeFields; + public Set<String> getFieldEditors() { + return fields.keySet(); } +// public Set<String> getFieldIds() { +// return fields.values(); +// } + + public boolean containsExcludeFieldEditor(String editorName) { + return excludeFields.containsValue(editorName); + } + + protected boolean containsExcludeFieldPropertyName(String editorName) { + return excludeFields.containsKey(editorName); + } + +// public Map<String, String> getExcludeFields() { +// return excludeFields; +// } + +// public Set<String> getExcludeFieldEditors() { +// return new HashSet<String>(excludeFields.values()); +// } + + public Set<String> getExcludeFieldPropertyNames() { + return excludeFields.keySet(); + } + + protected void removeFieldPropertyName(String propertyName) { + //must find the editor for this property + for (String editor : fields.keySet()) { + if (fields.containsEntry(editor, propertyName)) { + + fields.remove(editor, propertyName); + break; + } + } + } + + public void addField(String propertyName, String editor) { + fields.put(editor, propertyName); + } + + public void addExcludeField(String propertyName, String editor) { + excludeFields.put(propertyName, editor); + } + + public Collection<String> getFieldPropertyNames(String editor) { + return fields.get(editor); + } + +// public void setFields(Map<String, String> fields) { +// this.fields = fields; +// } + +// public void setExcludeFields(Map<String, String> excludeFields) { +// this.excludeFields = excludeFields; +// } + @Override public void addProperty(String property, String value) { @@ -418,7 +488,7 @@ public JAXXBeanInfo getBeanDescriptor(JAXXCompiler compiler) { if (beanDescriptor == null && foundBean()) { - String beanClassName = null; +// String beanClassName = null; try { //TC-20090111 beanClass is mandatory // get the real bean class name (from bean or beanClass) @@ -438,7 +508,7 @@ } catch (Exception e) { compiler.reportError( - "could not load class " + beanClassName); + "could not load class " + beanClass); } } return beanDescriptor; @@ -809,52 +879,70 @@ ids = new ArrayList<String>(); validatedComponents.put(compiler, ids); } - ids.addAll(compiledBeanValidator.getFields().values()); +// ids.addAll(compiledBeanValidator.getFields().values()); + ids.addAll(compiledBeanValidator.getFieldEditors()); } - /** - * Register in buffer all field representation to init (and to record in method {@link JAXXValidator#registerValidatorFields()} - * - * @param compiler the compiler used - * @param javaFile generated file - * @param buffer the buffer where to add code - * @since 2.2.1 - */ - public void addFieldRepresentations(JAXXCompiler compiler, - JavaFile javaFile, - StringBuilder buffer) { - for (Entry<String, String> entry : fields.entrySet()) { - String propertyName = entry.getKey(); - String component = entry.getValue(); - if (!checkBeanProperty(compiler, propertyName)) { - // property not find on bean - continue; - } - String validatorId = TypeManager.getJavaCode(getId()); - String keyCode = TypeManager.getJavaCode(propertyName); - String editorCode = TypeManager.getJavaCode(component); - JavaField editor = javaFile.getField(component); - String annotation = ValidatorField.class.getSimpleName() + - "( validatorId = " + validatorId + "," + - " propertyName = " + keyCode + "," + - " editorName = " + editorCode + "" + - ")"; - editor.addAnnotation(annotation); - -// if (!compiler.checkReference(tag, component, true, null)) { -// // editor component not find on ui +// /** +// * Register in buffer all field representation to init (and to record in method {@link JAXXValidator#registerValidatorFields()} +// * +// * @param compiler the compiler used +// * @param javaFile generated file +// * @param buffer the buffer where to add code +// * @since 2.2.1 +// */ +// public void addFieldRepresentations(JAXXCompiler compiler, +// JavaFile javaFile, +// StringBuilder buffer) { +// for (String component : fields.keySet()) { +//// String component = entry.getKey(); +// Collection<String> propertyNames = fields.get(component); +// List<String> keyCodes = +// Lists.newArrayListWithCapacity(propertyNames.size()); +// for (String propertyName : propertyNames) { +// if (!checkBeanProperty(compiler, propertyName)) { +// // property not find on bean +// continue; +// } +// String keyCode = TypeManager.getJavaCode(propertyName); +// keyCodes.add(keyCode); +// } +// +// if (keyCodes.isEmpty()) { +// // no property // continue; // } +// String keyCode = Joiner.on(", ").join(keyCodes); +// if (keyCodes.size()>1) { +// keyCode = "{ " + keyCode+" }"; +// } +//// String propertyName = entry.getKey(); +// +// String validatorId = TypeManager.getJavaCode(getId()); +// +// String editorCode = TypeManager.getJavaCode(component); +// JavaField editor = javaFile.getField(component); +// String annotation = ValidatorField.class.getSimpleName() + +// "( validatorId = " + validatorId + "," + +// " propertyName = " + keyCode + "," + +// " editorName = " + editorCode + "" + +// ")"; +// editor.addAnnotation(annotation); +// +//// if (!compiler.checkReference(tag, component, true, null)) { +//// // editor component not find on ui +//// continue; +//// } +// +//// buffer.append(getJavaCode()); +//// buffer.append(".setFieldRepresentation("); +//// buffer.append(keyCode); +//// buffer.append(", "); +//// buffer.append(component); +//// buffer.append(");\n"); +// } +// } -// buffer.append(getJavaCode()); -// buffer.append(".setFieldRepresentation("); -// buffer.append(keyCode); -// buffer.append(", "); -// buffer.append(component); -// buffer.append(");\n"); - } - } - protected void registerAutoFieldBean(Element tag, JAXXCompiler compiler, JAXXBeanInfo beanInfo) { @@ -870,11 +958,13 @@ // read-only property continue; } - if (fields.containsKey(descriptionName)) { +// if (fields.containsKey(descriptionName)) { + if (containsFieldPropertyName(descriptionName)) { // already defined in field continue; } - if (excludeFields.containsKey(descriptionName)) { +// if (excludeFields.containsKey(descriptionName)) { + if (containsExcludeFieldPropertyName(descriptionName)) { // exclude field continue; } @@ -889,15 +979,18 @@ registerField(descriptionName, descriptionName, compiler); } - for (Entry<String, String> entry : excludeFields.entrySet()) { - String key = entry.getKey(); - if (fields.containsKey(key)) { +// for (Entry<String, String> entry : excludeFields.entrySet()) { + for (String key : getExcludeFieldPropertyNames()) { +// String key = entry.getKey(); +// if (fields.containsKey(key)) { + if (containsFieldPropertyName(key)) { compiler.reportWarning( "field '" + key + "' can not be used and " + "excluded at same time ! (field is skipped) " + "for validator " + this ); - fields.remove(key); +// fields.remove(key); + removeFieldPropertyName(key); } } } @@ -905,28 +998,33 @@ public void registerField(String id, String component, JAXXCompiler compiler) { - if (fields.containsKey(id)) { +// if (fields.containsKey(id)) { + if (containsFieldPropertyName(id)) { compiler.reportError( "duplicate field '" + id + "' for validator " + this); } else { if (log.isDebugEnabled()) { log.debug("add field <" + id + ":" + component + ">"); } - fields.put(id, component); +// fields.put(id, component); + addField(id, component); + } } public void registerExcludeField(String id, String component, JAXXCompiler compiler) { - if (excludeFields.containsKey(id)) { +// if (excludeFields.containsKey(id)) { + if (containsExcludeFieldPropertyName(id)) { compiler.reportError( "duplicate field '" + id + "' for validator " + this); } else { if (log.isDebugEnabled()) { log.debug("add excludeField <" + id + ":" + component + ">"); } - excludeFields.put(id, component); +// excludeFields.put(id, component); + addExcludeField(id, component); } } @@ -959,7 +1057,7 @@ * @param compiler current compiler to use * @param beanId the bean to test * @return <code>true</code> if the given bean is attached to a validator, - * <code>false</code> otherwise + * <code>false</code> otherwise */ public static boolean isBeanUsedByValidator(JAXXCompiler compiler, String beanId) { @@ -977,7 +1075,7 @@ /** * @param compiler compiler to use * @return <code>true</code> if some validators were detected, - * <code>false</code> otherwise + * <code>false</code> otherwise */ public static boolean hasValidator(JAXXCompiler compiler) { List<CompiledBeanValidator> beanValidatorList = @@ -991,7 +1089,7 @@ * @param compiler compiler to use * @param componentId the compiled object to test * @return <code>true</code> if the given compiled object is attached to - * a validator, <code>false</code> otherwise + * a validator, <code>false</code> otherwise */ public static boolean isComponentUsedByValidator(JAXXCompiler compiler, String componentId) { Modified: trunk/jaxx-compiler/src/main/java/jaxx/compiler/tags/validator/ExcludeFieldValidatorHandler.java =================================================================== --- trunk/jaxx-compiler/src/main/java/jaxx/compiler/tags/validator/ExcludeFieldValidatorHandler.java 2013-10-11 13:04:20 UTC (rev 2739) +++ trunk/jaxx-compiler/src/main/java/jaxx/compiler/tags/validator/ExcludeFieldValidatorHandler.java 2013-10-17 15:49:11 UTC (rev 2740) @@ -102,13 +102,15 @@ component = component.trim(); // check component is not already used by this compiled object - if (info.getFields().containsValue(component)) { +// if (info.getFields().containsValue(component)) { + if (info.containsFieldEditor(component)) { compiler.reportError(TAG + " tag found a attribute " + COMPONENT_ATTRIBUTE + " [" + component + "] already used in this validator"); return; } - if (info.getExcludeFields().containsValue(component)) { +// if (info.getExcludeFields().containsValue(component)) { + if (info.containsExcludeFieldEditor(component)) { compiler.reportError(TAG + " tag found a attribute " + COMPONENT_ATTRIBUTE + " [" + component + "] already used in this validator"); Modified: trunk/jaxx-compiler/src/main/java/jaxx/compiler/tags/validator/FieldValidatorHandler.java =================================================================== --- trunk/jaxx-compiler/src/main/java/jaxx/compiler/tags/validator/FieldValidatorHandler.java 2013-10-11 13:04:20 UTC (rev 2739) +++ trunk/jaxx-compiler/src/main/java/jaxx/compiler/tags/validator/FieldValidatorHandler.java 2013-10-17 15:49:11 UTC (rev 2740) @@ -116,12 +116,13 @@ } // check component is not already used by this compiled object - if (info.getFields().containsValue(component)) { - compiler.reportError( - TAG + " tag found a attribute " + COMPONENT_ATTRIBUTE + - " [" + component + "] already used in this validator"); - return; - } +// if (info.getFields().containsValue(component)) { +// if (info.containsFieldEditor(component)) { +// compiler.reportError( +// TAG + " tag found a attribute " + COMPONENT_ATTRIBUTE + +// " [" + component + "] already used in this validator"); +// return; +// } if (complexType) { String binding = DataBindingHelper.processDataBindings(component); Modified: trunk/jaxx-maven-plugin/src/test/java/org/nuiton/jaxx/plugin/CompilerValidatorTest.java =================================================================== --- trunk/jaxx-maven-plugin/src/test/java/org/nuiton/jaxx/plugin/CompilerValidatorTest.java 2013-10-11 13:04:20 UTC (rev 2739) +++ trunk/jaxx-maven-plugin/src/test/java/org/nuiton/jaxx/plugin/CompilerValidatorTest.java 2013-10-17 15:49:11 UTC (rev 2740) @@ -45,7 +45,7 @@ @Test public void ValidatorOk() throws Exception { getMojo().execute(); - assertNumberJaxxFiles(2); + assertNumberJaxxFiles(3); } @@ -56,7 +56,7 @@ GenerateMojo mojo = getMojo(); mojo.init(); String[] files = mojo.files; - assertNumberJaxxFiles(19); + assertNumberJaxxFiles(18); mojo.setLog(new SystemStreamLog() { @Override Deleted: trunk/jaxx-maven-plugin/src/test/resources/org/nuiton/jaxx/plugin/compilerValidatorTest/validator/errors/FieldComponentDuplicated.jaxx =================================================================== --- trunk/jaxx-maven-plugin/src/test/resources/org/nuiton/jaxx/plugin/compilerValidatorTest/validator/errors/FieldComponentDuplicated.jaxx 2013-10-11 13:04:20 UTC (rev 2739) +++ trunk/jaxx-maven-plugin/src/test/resources/org/nuiton/jaxx/plugin/compilerValidatorTest/validator/errors/FieldComponentDuplicated.jaxx 2013-10-17 15:49:11 UTC (rev 2740) @@ -1,31 +0,0 @@ -<!-- - #%L - JAXX :: Maven plugin - - $Id$ - $HeadURL$ - %% - Copyright (C) 2008 - 2010 CodeLutin - %% - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as - published by the Free Software Foundation, either version 3 of the - License, or (at your option) any later version. - - 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 General Lesser Public License for more details. - - You should have received a copy of the GNU General Lesser Public - License along with this program. If not, see - <http://www.gnu.org/licenses/lgpl-3.0.html>. - #L% - --> -<Application> - <BeanValidator beanClass="org.nuiton.jaxx.plugin.compilerValidatorTest.validator.errors.Model"> - <field name="text2" component="text"/> - <field name="text" component="text"/> - </BeanValidator> - <JTextField id='text'/> -</Application> Copied: trunk/jaxx-maven-plugin/src/test/resources/org/nuiton/jaxx/plugin/compilerValidatorTest/validator/ok/FieldComponentDuplicated.jaxx (from rev 2737, trunk/jaxx-maven-plugin/src/test/resources/org/nuiton/jaxx/plugin/compilerValidatorTest/validator/errors/FieldComponentDuplicated.jaxx) =================================================================== --- trunk/jaxx-maven-plugin/src/test/resources/org/nuiton/jaxx/plugin/compilerValidatorTest/validator/ok/FieldComponentDuplicated.jaxx (rev 0) +++ trunk/jaxx-maven-plugin/src/test/resources/org/nuiton/jaxx/plugin/compilerValidatorTest/validator/ok/FieldComponentDuplicated.jaxx 2013-10-17 15:49:11 UTC (rev 2740) @@ -0,0 +1,31 @@ +<!-- + #%L + JAXX :: Maven plugin + + $Id$ + $HeadURL$ + %% + Copyright (C) 2008 - 2010 CodeLutin + %% + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation, either version 3 of the + License, or (at your option) any later version. + + 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 General Lesser Public License for more details. + + You should have received a copy of the GNU General Lesser Public + License along with this program. If not, see + <http://www.gnu.org/licenses/lgpl-3.0.html>. + #L% + --> +<Application> + <BeanValidator beanClass="org.nuiton.jaxx.plugin.compilerValidatorTest.validator.errors.Model"> + <field name="text2" component="text"/> + <field name="text" component="text"/> + </BeanValidator> + <JTextField id='text'/> +</Application> Modified: trunk/jaxx-validator/src/main/java/jaxx/runtime/validator/swing/SwingValidatorUtil.java =================================================================== --- trunk/jaxx-validator/src/main/java/jaxx/runtime/validator/swing/SwingValidatorUtil.java 2013-10-11 13:04:20 UTC (rev 2739) +++ trunk/jaxx-validator/src/main/java/jaxx/runtime/validator/swing/SwingValidatorUtil.java 2013-10-17 15:49:11 UTC (rev 2740) @@ -234,8 +234,7 @@ try { for (String validatorId : ui.getValidatorIds()) { - SwingValidator<?> validator = - (SwingValidator<?>) ui.getValidator(validatorId); + SwingValidator<?> validator = ui.getValidator(validatorId); for (Map.Entry<JComponent, ValidatorField> entry : editors.entrySet()) { @@ -246,13 +245,15 @@ // not good validator, skip this field continue; } - String propertyName = fieldAnnotation.propertyName(); - if (log.isInfoEnabled()) { - log.info("Detects for validator [" + validatorId + - "] property " + propertyName + - " for editor " + fieldAnnotation.editorName()); + String[] propertyNames = fieldAnnotation.propertyName(); + for (String propertyName : propertyNames) { + if (log.isInfoEnabled()) { + log.info("Detects for validator [" + validatorId + + "] property " + propertyName + + " for editor " + fieldAnnotation.editorName()); + } + validator.setFieldRepresentation(propertyName, editor); } - validator.setFieldRepresentation(propertyName, editor); } } Modified: trunk/jaxx-validator/src/main/java/jaxx/runtime/validator/swing/meta/ValidatorField.java =================================================================== --- trunk/jaxx-validator/src/main/java/jaxx/runtime/validator/swing/meta/ValidatorField.java 2013-10-11 13:04:20 UTC (rev 2739) +++ trunk/jaxx-validator/src/main/java/jaxx/runtime/validator/swing/meta/ValidatorField.java 2013-10-17 15:49:11 UTC (rev 2740) @@ -46,11 +46,11 @@ String validatorId(); /** - * Obtain the name of the bean property to validate. + * Obtain the name of the bean property(ies) to validate. * - * @return the name of the property to validate + * @return the name of the property(ies) to validate */ - String propertyName(); + String[] propertyName(); /** * Obtain the name of the property editor.
participants (1)
-
tchemit@users.nuiton.org