mirror of
https://github.com/bancika/diy-layout-creator
synced 2026-11-10 17:22:09 +10:00
allow property edit validation
This commit is contained in:
Binary file not shown.
Binary file not shown.
+11
-7
@@ -3,6 +3,8 @@ package org.diylc.common;
|
|||||||
import java.lang.reflect.InvocationTargetException;
|
import java.lang.reflect.InvocationTargetException;
|
||||||
import java.lang.reflect.Method;
|
import java.lang.reflect.Method;
|
||||||
|
|
||||||
|
import org.diylc.core.IPropertyValidator;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Entity class for editable properties extracted from component objects.
|
* Entity class for editable properties extracted from component objects.
|
||||||
* Represents a single editable property together with it's current value.
|
* Represents a single editable property together with it's current value.
|
||||||
@@ -17,19 +19,21 @@ public class PropertyWrapper implements Cloneable {
|
|||||||
private Method setter;
|
private Method setter;
|
||||||
private Method getter;
|
private Method getter;
|
||||||
private boolean defaultable;
|
private boolean defaultable;
|
||||||
|
private IPropertyValidator validator;
|
||||||
|
|
||||||
public PropertyWrapper(String name, Class<?> type, Method getter, Method setter,
|
public PropertyWrapper(String name, Class<?> type, Method getter, Method setter,
|
||||||
boolean defaultable) {
|
boolean defaultable, IPropertyValidator validator) {
|
||||||
super();
|
super();
|
||||||
this.name = name;
|
this.name = name;
|
||||||
this.type = type;
|
this.type = type;
|
||||||
this.getter = getter;
|
this.getter = getter;
|
||||||
this.setter = setter;
|
this.setter = setter;
|
||||||
this.defaultable = defaultable;
|
this.defaultable = defaultable;
|
||||||
|
this.validator = validator;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void readFrom(Object object) throws IllegalArgumentException,
|
public void readFrom(Object object) throws IllegalArgumentException, IllegalAccessException,
|
||||||
IllegalAccessException, InvocationTargetException {
|
InvocationTargetException {
|
||||||
this.value = getter.invoke(object);
|
this.value = getter.invoke(object);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -42,8 +46,8 @@ public class PropertyWrapper implements Cloneable {
|
|||||||
// }
|
// }
|
||||||
// }
|
// }
|
||||||
|
|
||||||
public void writeTo(Object object) throws IllegalArgumentException,
|
public void writeTo(Object object) throws IllegalArgumentException, IllegalAccessException,
|
||||||
IllegalAccessException, InvocationTargetException {
|
InvocationTargetException {
|
||||||
setter.invoke(object, value);
|
setter.invoke(object, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -67,8 +71,8 @@ public class PropertyWrapper implements Cloneable {
|
|||||||
return defaultable;
|
return defaultable;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setDefaultable(boolean defaultable) {
|
public IPropertyValidator getValidator() {
|
||||||
this.defaultable = defaultable;
|
return validator;
|
||||||
}
|
}
|
||||||
|
|
||||||
// @Override
|
// @Override
|
||||||
|
|||||||
+13
@@ -0,0 +1,13 @@
|
|||||||
|
package org.diylc.core;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Validator that allows all values.
|
||||||
|
*
|
||||||
|
* @author Branislav Stojkovic
|
||||||
|
*/
|
||||||
|
public class AllowAllValidator implements IPropertyValidator {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void validate(Object value) throws ValidationException {
|
||||||
|
}
|
||||||
|
}
|
||||||
+16
@@ -0,0 +1,16 @@
|
|||||||
|
package org.diylc.core;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Interface for validating property value changes.
|
||||||
|
*
|
||||||
|
* @author Branislav Stojkovic
|
||||||
|
*/
|
||||||
|
public interface IPropertyValidator {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param value
|
||||||
|
* @throws ValidationException
|
||||||
|
* if validation fails. Message will contain the reason.
|
||||||
|
*/
|
||||||
|
void validate(Object value) throws ValidationException;
|
||||||
|
}
|
||||||
+19
-3
@@ -7,6 +7,7 @@ import java.util.List;
|
|||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
import org.diylc.core.annotations.EditableProperty;
|
import org.diylc.core.annotations.EditableProperty;
|
||||||
|
import org.diylc.core.annotations.PositiveMeasureValidator;
|
||||||
import org.diylc.core.measures.Size;
|
import org.diylc.core.measures.Size;
|
||||||
import org.diylc.core.measures.SizeUnit;
|
import org.diylc.core.measures.SizeUnit;
|
||||||
|
|
||||||
@@ -92,7 +93,7 @@ public class Project implements Serializable {
|
|||||||
this.height = height;
|
this.height = height;
|
||||||
}
|
}
|
||||||
|
|
||||||
@EditableProperty(name = "Grid spacing")
|
@EditableProperty(name = "Grid spacing", validatorClass = SpacingValidator.class)
|
||||||
public Size getGridSpacing() {
|
public Size getGridSpacing() {
|
||||||
return gridSpacing;
|
return gridSpacing;
|
||||||
}
|
}
|
||||||
@@ -118,7 +119,7 @@ public class Project implements Serializable {
|
|||||||
public Set<Set<IDIYComponent<?>>> getGroups() {
|
public Set<Set<IDIYComponent<?>>> getGroups() {
|
||||||
return groups;
|
return groups;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Set<Integer> getLockedLayers() {
|
public Set<Integer> getLockedLayers() {
|
||||||
return lockedLayers;
|
return lockedLayers;
|
||||||
}
|
}
|
||||||
@@ -177,12 +178,27 @@ public class Project implements Serializable {
|
|||||||
return false;
|
return false;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return title;
|
return title;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static class SpacingValidator extends PositiveMeasureValidator {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void validate(Object value) throws ValidationException {
|
||||||
|
super.validate(value);
|
||||||
|
Size size = (Size) value;
|
||||||
|
if (size.compareTo(new Size(1d, SizeUnit.mm)) < 0) {
|
||||||
|
throw new ValidationException("must be greater than 1mm");
|
||||||
|
}
|
||||||
|
if (size.compareTo(new Size(1d, SizeUnit.in)) > 0) {
|
||||||
|
throw new ValidationException("must be less than 1in");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// @Override
|
// @Override
|
||||||
// public Project clone() throws CloneNotSupportedException {
|
// public Project clone() throws CloneNotSupportedException {
|
||||||
// List<IDIYComponent> clonedComponents = new
|
// List<IDIYComponent> clonedComponents = new
|
||||||
|
|||||||
+11
@@ -0,0 +1,11 @@
|
|||||||
|
|
||||||
|
package org.diylc.core;
|
||||||
|
|
||||||
|
public class ValidationException extends Exception {
|
||||||
|
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
public ValidationException(String message) {
|
||||||
|
super(message);
|
||||||
|
}
|
||||||
|
}
|
||||||
+9
@@ -3,6 +3,9 @@ package org.diylc.core.annotations;
|
|||||||
import java.lang.annotation.Retention;
|
import java.lang.annotation.Retention;
|
||||||
import java.lang.annotation.RetentionPolicy;
|
import java.lang.annotation.RetentionPolicy;
|
||||||
|
|
||||||
|
import org.diylc.core.AllowAllValidator;
|
||||||
|
import org.diylc.core.IPropertyValidator;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Used to annotate editable component property. Editable property XYZ must have
|
* Used to annotate editable component property. Editable property XYZ must have
|
||||||
* both getter and setter named <code>getXYZ</code> and <code>setXYZ</code>
|
* both getter and setter named <code>getXYZ</code> and <code>setXYZ</code>
|
||||||
@@ -30,4 +33,10 @@ public @interface EditableProperty {
|
|||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
boolean defaultable() default true;
|
boolean defaultable() default true;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class of validator to use to
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
Class<? extends IPropertyValidator> validatorClass() default AllowAllValidator.class;
|
||||||
}
|
}
|
||||||
|
|||||||
+20
@@ -0,0 +1,20 @@
|
|||||||
|
package org.diylc.core.annotations;
|
||||||
|
|
||||||
|
import org.diylc.core.IPropertyValidator;
|
||||||
|
import org.diylc.core.ValidationException;
|
||||||
|
import org.diylc.core.measures.AbstractMeasure;
|
||||||
|
|
||||||
|
public class PositiveMeasureValidator implements IPropertyValidator {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void validate(Object value) throws ValidationException {
|
||||||
|
if (value instanceof AbstractMeasure) {
|
||||||
|
AbstractMeasure measure = (AbstractMeasure) value;
|
||||||
|
if (measure.getValue() <= 0) {
|
||||||
|
throw new ValidationException("must be greater than zero.");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
throw new ValidationException("wrong data type, measure expected.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+6
-1
@@ -2,7 +2,7 @@ package org.diylc.core.measures;
|
|||||||
|
|
||||||
import org.diylc.utils.Constants;
|
import org.diylc.utils.Constants;
|
||||||
|
|
||||||
public class Size extends AbstractMeasure<SizeUnit> {
|
public class Size extends AbstractMeasure<SizeUnit> implements Comparable<Size> {
|
||||||
|
|
||||||
private static final long serialVersionUID = 1L;
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
@@ -39,4 +39,9 @@ public class Size extends AbstractMeasure<SizeUnit> {
|
|||||||
}
|
}
|
||||||
throw new IllegalArgumentException("Could not parse size: " + value);
|
throw new IllegalArgumentException("Could not parse size: " + value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int compareTo(Size o) {
|
||||||
|
return new Double(value * unit.getFactor()).compareTo(o.getValue() * o.getUnit().getFactor());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+27
-6
@@ -19,6 +19,7 @@ import org.diylc.common.ComponentType;
|
|||||||
import org.diylc.common.PropertyWrapper;
|
import org.diylc.common.PropertyWrapper;
|
||||||
import org.diylc.core.CreationMethod;
|
import org.diylc.core.CreationMethod;
|
||||||
import org.diylc.core.IDIYComponent;
|
import org.diylc.core.IDIYComponent;
|
||||||
|
import org.diylc.core.IPropertyValidator;
|
||||||
import org.diylc.core.annotations.ComponentDescriptor;
|
import org.diylc.core.annotations.ComponentDescriptor;
|
||||||
import org.diylc.core.annotations.EditableProperty;
|
import org.diylc.core.annotations.EditableProperty;
|
||||||
|
|
||||||
@@ -35,7 +36,8 @@ public class ComponentProcessor {
|
|||||||
|
|
||||||
private static ComponentProcessor instance;
|
private static ComponentProcessor instance;
|
||||||
|
|
||||||
private Map<Class<?>, List<PropertyWrapper>> propertyCache;
|
private Map<String, List<PropertyWrapper>> propertyCache;
|
||||||
|
private Map<String, IPropertyValidator> propertyValidatorCache;
|
||||||
private Map<String, ComponentType> componentTypeMap;
|
private Map<String, ComponentType> componentTypeMap;
|
||||||
|
|
||||||
private Cloner cloner;
|
private Cloner cloner;
|
||||||
@@ -50,8 +52,9 @@ public class ComponentProcessor {
|
|||||||
private ComponentProcessor() {
|
private ComponentProcessor() {
|
||||||
super();
|
super();
|
||||||
this.cloner = new Cloner();
|
this.cloner = new Cloner();
|
||||||
this.propertyCache = new HashMap<Class<?>, List<PropertyWrapper>>();
|
this.propertyCache = new HashMap<String, List<PropertyWrapper>>();
|
||||||
this.componentTypeMap = new HashMap<String, ComponentType>();
|
this.componentTypeMap = new HashMap<String, ComponentType>();
|
||||||
|
this.propertyValidatorCache = new HashMap<String, IPropertyValidator>();
|
||||||
}
|
}
|
||||||
|
|
||||||
public ComponentType extractComponentTypeFrom(Class<? extends IDIYComponent<?>> clazz) {
|
public ComponentType extractComponentTypeFrom(Class<? extends IDIYComponent<?>> clazz) {
|
||||||
@@ -117,8 +120,8 @@ public class ComponentProcessor {
|
|||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
public List<PropertyWrapper> extractProperties(Class<?> clazz) {
|
public List<PropertyWrapper> extractProperties(Class<?> clazz) {
|
||||||
if (propertyCache.containsKey(clazz)) {
|
if (propertyCache.containsKey(clazz.getName())) {
|
||||||
return cloner.deepClone(propertyCache.get(clazz));
|
return cloner.deepClone(propertyCache.get(clazz.getName()));
|
||||||
}
|
}
|
||||||
List<PropertyWrapper> properties = new ArrayList<PropertyWrapper>();
|
List<PropertyWrapper> properties = new ArrayList<PropertyWrapper>();
|
||||||
for (Method method : clazz.getMethods()) {
|
for (Method method : clazz.getMethods()) {
|
||||||
@@ -133,10 +136,13 @@ public class ComponentProcessor {
|
|||||||
} else {
|
} else {
|
||||||
name = annotation.name();
|
name = annotation.name();
|
||||||
}
|
}
|
||||||
|
IPropertyValidator validator = getPropertyValidator(annotation
|
||||||
|
.validatorClass());
|
||||||
Method setter = clazz.getMethod("set" + method.getName().substring(3),
|
Method setter = clazz.getMethod("set" + method.getName().substring(3),
|
||||||
method.getReturnType());
|
method.getReturnType());
|
||||||
PropertyWrapper property = new PropertyWrapper(name,
|
PropertyWrapper property = new PropertyWrapper(name,
|
||||||
method.getReturnType(), method, setter, annotation.defaultable());
|
method.getReturnType(), method, setter, annotation.defaultable(),
|
||||||
|
validator);
|
||||||
properties.add(property);
|
properties.add(property);
|
||||||
}
|
}
|
||||||
} catch (NoSuchMethodException e) {
|
} catch (NoSuchMethodException e) {
|
||||||
@@ -146,7 +152,7 @@ public class ComponentProcessor {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
propertyCache.put(clazz, properties);
|
propertyCache.put(clazz.getName(), properties);
|
||||||
return cloner.deepClone(properties);
|
return cloner.deepClone(properties);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -187,4 +193,19 @@ public class ComponentProcessor {
|
|||||||
Collections.sort(properties, ComparatorFactory.getInstance().getPropertyNameComparator());
|
Collections.sort(properties, ComparatorFactory.getInstance().getPropertyNameComparator());
|
||||||
return properties;
|
return properties;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private IPropertyValidator getPropertyValidator(Class<? extends IPropertyValidator> clazz) {
|
||||||
|
if (propertyValidatorCache.containsKey(clazz.getName())) {
|
||||||
|
return propertyValidatorCache.get(clazz.getName());
|
||||||
|
}
|
||||||
|
IPropertyValidator validator;
|
||||||
|
try {
|
||||||
|
validator = clazz.newInstance();
|
||||||
|
} catch (Exception e) {
|
||||||
|
LOG.error("Could not instantiate validator for " + clazz.getName(), e);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
propertyValidatorCache.put(clazz.getName(), validator);
|
||||||
|
return validator;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+19
@@ -18,10 +18,12 @@ import javax.swing.JCheckBox;
|
|||||||
import javax.swing.JComponent;
|
import javax.swing.JComponent;
|
||||||
import javax.swing.JFrame;
|
import javax.swing.JFrame;
|
||||||
import javax.swing.JLabel;
|
import javax.swing.JLabel;
|
||||||
|
import javax.swing.JOptionPane;
|
||||||
import javax.swing.JPanel;
|
import javax.swing.JPanel;
|
||||||
|
|
||||||
import org.apache.log4j.Logger;
|
import org.apache.log4j.Logger;
|
||||||
import org.diylc.common.PropertyWrapper;
|
import org.diylc.common.PropertyWrapper;
|
||||||
|
import org.diylc.core.ValidationException;
|
||||||
|
|
||||||
import com.diyfever.gui.ButtonDialog;
|
import com.diyfever.gui.ButtonDialog;
|
||||||
|
|
||||||
@@ -65,6 +67,23 @@ public class PropertyEditorDialog extends ButtonDialog {
|
|||||||
// setLocationRelativeTo(owner);
|
// setLocationRelativeTo(owner);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected boolean validateInput(String button) {
|
||||||
|
if (button.equals(ButtonDialog.OK)) {
|
||||||
|
for (PropertyWrapper property : properties) {
|
||||||
|
try {
|
||||||
|
property.getValidator().validate(property.getValue());
|
||||||
|
} catch (ValidationException ve) {
|
||||||
|
JOptionPane.showMessageDialog(PropertyEditorDialog.this, "Input error for \""
|
||||||
|
+ property.getName() + "\": " + ve.getMessage(), "Error",
|
||||||
|
JOptionPane.ERROR_MESSAGE);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
private JPanel createEditorFields() {
|
private JPanel createEditorFields() {
|
||||||
JPanel editorPanel = new JPanel(new GridBagLayout());
|
JPanel editorPanel = new JPanel(new GridBagLayout());
|
||||||
editorPanel.setBorder(BorderFactory.createEmptyBorder(8, 8, 8, 8));
|
editorPanel.setBorder(BorderFactory.createEmptyBorder(8, 8, 8, 8));
|
||||||
|
|||||||
Binary file not shown.
+2
-1
@@ -12,6 +12,7 @@ import org.diylc.core.CreationMethod;
|
|||||||
import org.diylc.core.IDIYComponent;
|
import org.diylc.core.IDIYComponent;
|
||||||
import org.diylc.core.annotations.ComponentDescriptor;
|
import org.diylc.core.annotations.ComponentDescriptor;
|
||||||
import org.diylc.core.annotations.EditableProperty;
|
import org.diylc.core.annotations.EditableProperty;
|
||||||
|
import org.diylc.core.annotations.PositiveMeasureValidator;
|
||||||
import org.diylc.core.measures.Resistance;
|
import org.diylc.core.measures.Resistance;
|
||||||
import org.diylc.core.measures.ResistanceUnit;
|
import org.diylc.core.measures.ResistanceUnit;
|
||||||
import org.diylc.core.measures.Size;
|
import org.diylc.core.measures.Size;
|
||||||
@@ -36,7 +37,7 @@ public class Resistor extends AbstractLeadedComponent<Resistance> {
|
|||||||
this.borderColor = BORDER_COLOR;
|
this.borderColor = BORDER_COLOR;
|
||||||
}
|
}
|
||||||
|
|
||||||
@EditableProperty
|
@EditableProperty(validatorClass = PositiveMeasureValidator.class)
|
||||||
public Resistance getValue() {
|
public Resistance getValue() {
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user