refactor component transformation

This commit is contained in:
bancika
2017-01-06 15:24:55 +01:00
parent 8a3f017468
commit af39da27aa
64 changed files with 411 additions and 215 deletions
@@ -29,13 +29,13 @@ public class ComponentType {
private boolean stretchable;
private BomPolicy bomPolicy;
private boolean autoEdit;
private boolean rotatable;
private IComponentTransformer transformer;
private KeywordPolicy keywordPolicy;
private String keywordTag;
public ComponentType(String name, String description, CreationMethod creationMethod, String category,
String namePrefix, String author, Icon icon, Class<? extends IDIYComponent<?>> instanceClass, double zOrder,
boolean flexibleZOrder, boolean stretchable, BomPolicy bomPolicy, boolean autoEdit, boolean rotatable,
boolean flexibleZOrder, boolean stretchable, BomPolicy bomPolicy, boolean autoEdit, IComponentTransformer transformer,
KeywordPolicy keywordPolicy, String keywordTag) {
super();
this.name = name;
@@ -51,7 +51,7 @@ public class ComponentType {
this.stretchable = stretchable;
this.bomPolicy = bomPolicy;
this.autoEdit = autoEdit;
this.rotatable = rotatable;
this.transformer = transformer;
this.keywordPolicy = keywordPolicy;
this.keywordTag = keywordTag;
}
@@ -108,8 +108,8 @@ public class ComponentType {
return autoEdit;
}
public boolean isRotatable() {
return rotatable;
public IComponentTransformer getTransformer() {
return transformer;
}
public KeywordPolicy getKeywordPolicy() {
@@ -0,0 +1,27 @@
package org.diylc.common;
import java.awt.Point;
import org.diylc.core.IDIYComponent;
public class DefaultTransformer implements IComponentTransformer {
@Override
public boolean canRotate(IDIYComponent<?> component) {
return false;
}
@Override
public boolean canMirror(IDIYComponent<?> component) {
return false;
}
@Override
public void rotate(IDIYComponent<?> component, Point center, int direction) {
}
@Override
public void mirror(IDIYComponent<?> component, Point center, int direction) {
}
}
@@ -0,0 +1,22 @@
package org.diylc.common;
import java.awt.Point;
import org.diylc.core.IDIYComponent;
public interface IComponentTransformer {
public static final int CLOCKWISE = 1;
public static final int COUNTER_CLOCKWISE = 1;
public static final int HORIZONTAL = 0;
public static final int VERTICAL = 1;
boolean canRotate(IDIYComponent<?> component);
boolean canMirror(IDIYComponent<?> component);
void rotate(IDIYComponent<?> component, Point center, int direction);
void mirror(IDIYComponent<?> component, Point center, int direction);
}
@@ -8,12 +8,6 @@ import org.diylc.core.ExpansionMode;
import org.diylc.core.IDIYComponent;
public interface ISelectionProcessor {
public static final int CLOCKWISE = 1;
public static final int COUNTER_CLOCKWISE = 1;
public static final int HORIZONTAL = 0;
public static final int VERTICAL = 1;
/**
* Returns the current {@link ComponentTransferable}.
@@ -17,7 +17,7 @@ public interface ITemplateProcessor {
void applyTemplateToSelection(Template template);
void deleteTemplate(String categoryName, String componentTypeName, String templateName);
void setTemplateDefault(String categoryName, String componentTypeName, String templateName, boolean defaultFlag);
public class TemplateAlreadyExistsException extends Exception {
@@ -0,0 +1,42 @@
package org.diylc.common;
import java.awt.Point;
import java.awt.geom.AffineTransform;
import org.diylc.core.IDIYComponent;
public class SimpleComponentTransformer implements IComponentTransformer {
@Override
public boolean canRotate(IDIYComponent<?> component) {
return true;
}
@Override
public boolean canMirror(IDIYComponent<?> component) {
return true;
}
@Override
public void rotate(IDIYComponent<?> component, Point center, int direction) {
AffineTransform rotate = AffineTransform.getRotateInstance(Math.PI / 2 * direction, center.x, center.y);
for (int index = 0; index < component.getControlPointCount(); index++) {
Point p = new Point(component.getControlPoint(index));
rotate.transform(p, p);
component.setControlPoint(p, index);
}
}
@Override
public void mirror(IDIYComponent<?> component, Point center, int direction) {
for (int i = 0; i < component.getControlPointCount(); i++) {
Point p = component.getControlPoint(i);
if (direction == IComponentTransformer.HORIZONTAL) {
component.setControlPoint(new Point(p.x - 2 * (p.x - center.x), p.y), i);
} else {
component.setControlPoint(new Point(p.x, p.y - 2 * (p.y - center.y)), i);
}
}
}
}
@@ -3,6 +3,8 @@ package org.diylc.core.annotations;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import org.diylc.common.DefaultTransformer;
import org.diylc.common.IComponentTransformer;
import org.diylc.core.CreationMethod;
import org.diylc.core.IDIYComponent;
@@ -77,10 +79,9 @@ public @interface ComponentDescriptor {
boolean autoEdit() default true;
/**
* @return true if component may be rotated, false otherwise
* @return
* @return if the component can be rotated and/or mirrored, returns a class of the transformer that can do it
*/
boolean rotatable() default true;
Class<? extends IComponentTransformer> transformer() default DefaultTransformer.class;
/**
* Defines if and how a component should appear in auto-generated project keywords. See
@@ -17,6 +17,7 @@ import javax.swing.ImageIcon;
import org.apache.log4j.Logger;
import org.diylc.common.ComponentType;
import org.diylc.common.IComponentTransformer;
import org.diylc.common.PropertyWrapper;
import org.diylc.core.CreationMethod;
import org.diylc.core.IDIYComponent;
@@ -40,6 +41,7 @@ public class ComponentProcessor {
private Map<String, List<PropertyWrapper>> propertyCache;
private Map<String, IPropertyValidator> propertyValidatorCache;
private Map<String, ComponentType> componentTypeMap;
private Map<String, IComponentTransformer> componentTransformerMap;
public static ComponentProcessor getInstance() {
if (instance == null) {
@@ -53,6 +55,7 @@ public class ComponentProcessor {
this.propertyCache = new HashMap<String, List<PropertyWrapper>>();
this.componentTypeMap = new HashMap<String, ComponentType>();
this.propertyValidatorCache = new HashMap<String, IPropertyValidator>();
this.componentTransformerMap = new HashMap<String, IComponentTransformer>();
}
public ComponentType extractComponentTypeFrom(Class<? extends IDIYComponent<?>> clazz) {
@@ -71,7 +74,7 @@ public class ComponentProcessor {
boolean stretchable;
BomPolicy bomPolicy;
boolean autoEdit;
boolean rotatable;
IComponentTransformer transformer;
KeywordPolicy keywordPolicy;
String keywordTag;
if (clazz.isAnnotationPresent(ComponentDescriptor.class)) {
@@ -87,7 +90,7 @@ public class ComponentProcessor {
stretchable = annotation.stretchable();
bomPolicy = annotation.bomPolicy();
autoEdit = annotation.autoEdit();
rotatable = annotation.rotatable();
transformer = getComponentTransformer(annotation.transformer());
keywordPolicy = annotation.keywordPolicy();
keywordTag = annotation.keywordTag();
} else { // default
@@ -102,7 +105,7 @@ public class ComponentProcessor {
stretchable = true;
bomPolicy = BomPolicy.SHOW_ALL_NAMES;
autoEdit = true;
rotatable = true;
transformer = null;
keywordPolicy = KeywordPolicy.NEVER_SHOW;
keywordTag = null;
}
@@ -124,7 +127,7 @@ public class ComponentProcessor {
}
ComponentType componentType =
new ComponentType(name, description, creationMethod, category, namePrefix, author, icon, clazz, zOrder,
flexibleZOrder, stretchable, bomPolicy, autoEdit, rotatable, keywordPolicy, keywordTag);
flexibleZOrder, stretchable, bomPolicy, autoEdit, transformer, keywordPolicy, keywordTag);
componentTypeMap.put(clazz.getName(), componentType);
return componentType;
}
@@ -186,14 +189,15 @@ public class ComponentProcessor {
* @param selectedComponents
* @return
*/
public List<PropertyWrapper> getMutualSelectionProperties(Collection<IDIYComponent<?>> selectedComponents) throws Exception {
public List<PropertyWrapper> getMutualSelectionProperties(Collection<IDIYComponent<?>> selectedComponents)
throws Exception {
if (selectedComponents.isEmpty()) {
return null;
}
List<PropertyWrapper> properties = new ArrayList<PropertyWrapper>();
List<IDIYComponent<?>> selectedList = new ArrayList<IDIYComponent<?>>(selectedComponents);
List<IDIYComponent<?>> selectedList = new ArrayList<IDIYComponent<?>>(selectedComponents);
IDIYComponent<?> firstComponent = selectedList.get(0);
properties.addAll(extractProperties(firstComponent.getClass()));
// Initialize values
@@ -242,4 +246,21 @@ public class ComponentProcessor {
propertyValidatorCache.put(clazz.getName(), validator);
return validator;
}
private IComponentTransformer getComponentTransformer(Class<? extends IComponentTransformer> clazz) {
if (clazz == null)
return null;
if (componentTransformerMap.containsKey(clazz.getName())) {
return componentTransformerMap.get(clazz.getName());
}
IComponentTransformer transformer;
try {
transformer = clazz.newInstance();
} catch (Exception e) {
LOG.error("Could not instantiate validator for " + clazz.getName(), e);
return null;
}
componentTransformerMap.put(clazz.getName(), transformer);
return transformer;
}
}
@@ -41,7 +41,7 @@ public class InstantiationManager {
private static final ComponentType clipboardType = new ComponentType("Clipboard contents",
"Components from the clipboard", CreationMethod.SINGLE_CLICK, "Multi", "", "", null, null, 0, false, false, null,
false, true, KeywordPolicy.NEVER_SHOW, null);
false, null, KeywordPolicy.NEVER_SHOW, null);
public InstantiationManager() {}
@@ -6,7 +6,6 @@ import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.dnd.DnDConstants;
import java.awt.geom.AffineTransform;
import java.awt.geom.Area;
import java.awt.geom.Point2D;
import java.io.BufferedInputStream;
@@ -38,12 +37,10 @@ import org.diylc.common.ComponentType;
import org.diylc.common.DrawOption;
import org.diylc.common.EventType;
import org.diylc.common.IComponentFiler;
import org.diylc.common.IComponentTransformer;
import org.diylc.common.IKeyProcessor;
import org.diylc.common.IPlugIn;
import org.diylc.common.IPlugInPort;
import org.diylc.common.ISelectionProcessor;
import org.diylc.common.Orientation;
import org.diylc.common.OrientationHV;
import org.diylc.common.PropertyWrapper;
import org.diylc.core.ExpansionMode;
import org.diylc.core.IDIYComponent;
@@ -612,10 +609,10 @@ public class Presenter implements IPlugInPort {
rotateComponents(this.selectedComponents, -1, snapToGrid);
} else if (key == IKeyProcessor.VK_H) {
oldProject = currentProject.clone();
mirrorSelection(ISelectionProcessor.HORIZONTAL);
mirrorComponents(this.selectedComponents, IComponentTransformer.HORIZONTAL, snapToGrid);
} else if (key == IKeyProcessor.VK_V) {
oldProject = currentProject.clone();
mirrorSelection(ISelectionProcessor.VERTICAL);
mirrorComponents(this.selectedComponents, IComponentTransformer.VERTICAL, snapToGrid);
} else
return false;
messageDispatcher.dispatchMessage(EventType.PROJECT_MODIFIED, oldProject, currentProject.clone(),
@@ -1082,105 +1079,100 @@ public class Presenter implements IPlugInPort {
private void rotateComponents(Collection<IDIYComponent<?>> components, int direction, boolean snapToGrid) {
Point center = getCenterOf(components, snapToGrid);
AffineTransform rotate = AffineTransform.getRotateInstance(Math.PI / 2 * direction, center.x, center.y);
// Update all points to new location.
for (IDIYComponent<?> component : components) {
drawingManager.invalidateComponent(component);
boolean canRotate = true;
for (IDIYComponent<?> component : selectedComponents) {
ComponentType type =
ComponentProcessor.getInstance().extractComponentTypeFrom(
(Class<? extends IDIYComponent<?>>) component.getClass());
if (type.isRotatable()) {
for (int index = 0; index < component.getControlPointCount(); index++) {
Point p = new Point(component.getControlPoint(index));
rotate.transform(p, p);
component.setControlPoint(p, index);
}
// If component has orientation, change it too
List<PropertyWrapper> newProperties = ComponentProcessor.getInstance().extractProperties(component.getClass());
for (PropertyWrapper property : newProperties) {
if (property.getType() == Orientation.class) {
try {
property.readFrom(component);
Orientation orientation = (Orientation) property.getValue();
Orientation[] values = Orientation.values();
int newIndex = orientation.ordinal() + direction;
if (newIndex < 0)
newIndex = values.length - 1;
else if (newIndex >= values.length)
newIndex = 0;
property.setValue(values[newIndex]);
property.writeTo(component);
} catch (Exception e) {
LOG.error("Could not change component orientation for " + component.getName(), e);
}
} else if (property.getType() == OrientationHV.class) {
try {
property.readFrom(component);
OrientationHV orientation = (OrientationHV) property.getValue();
property.setValue(OrientationHV.values()[1 - orientation.ordinal()]);
property.writeTo(component);
} catch (Exception e) {
LOG.error("Could not change component orientation for " + component.getName(), e);
}
}
}
} else {
// Non-rotatable
Point componentCenter = getCenterOf(Arrays.asList(new IDIYComponent<?>[] {component}), false);
Point rotatedComponentCenter = new Point();
rotate.transform(componentCenter, rotatedComponentCenter);
for (int index = 0; index < component.getControlPointCount(); index++) {
Point p = new Point(component.getControlPoint(index));
p.translate(rotatedComponentCenter.x - componentCenter.x, rotatedComponentCenter.y - componentCenter.y);
component.setControlPoint(p, index);
}
if (type.getTransformer() == null || !type.getTransformer().canRotate(component)) {
canRotate = false;
break;
}
}
if (!canRotate)
if (view.showConfirmDialog("Selection contains components that cannot be rotated. Do you want to exclude them?",
"Mirror Selection", IView.YES_NO_OPTION, IView.QUESTION_MESSAGE) != IView.YES_OPTION)
return;
for (IDIYComponent<?> component : selectedComponents) {
ComponentType type =
ComponentProcessor.getInstance().extractComponentTypeFrom(
(Class<? extends IDIYComponent<?>>) component.getClass());
if (type.getTransformer() != null && type.getTransformer().canRotate(component)) {
drawingManager.invalidateComponent(component);
type.getTransformer().rotate(component, center, direction);
}
}
// AffineTransform rotate = AffineTransform.getRotateInstance(Math.PI / 2 * direction, center.x,
// center.y);
//
// // Update all points to new location.
// for (IDIYComponent<?> component : components) {
// drawingManager.invalidateComponent(component);
// ComponentType type =
// ComponentProcessor.getInstance().extractComponentTypeFrom(
// (Class<? extends IDIYComponent<?>>) component.getClass());
// if (type.isRotatable()) {
// for (int index = 0; index < component.getControlPointCount(); index++) {
// Point p = new Point(component.getControlPoint(index));
// rotate.transform(p, p);
// component.setControlPoint(p, index);
// }
// // If component has orientation, change it too
// List<PropertyWrapper> newProperties =
// ComponentProcessor.getInstance().extractProperties(component.getClass());
// for (PropertyWrapper property : newProperties) {
// if (property.getType() == Orientation.class) {
// try {
// property.readFrom(component);
// Orientation orientation = (Orientation) property.getValue();
// Orientation[] values = Orientation.values();
// int newIndex = orientation.ordinal() + direction;
// if (newIndex < 0)
// newIndex = values.length - 1;
// else if (newIndex >= values.length)
// newIndex = 0;
// property.setValue(values[newIndex]);
// property.writeTo(component);
// } catch (Exception e) {
// LOG.error("Could not change component orientation for " + component.getName(), e);
// }
// } else if (property.getType() == OrientationHV.class) {
// try {
// property.readFrom(component);
// OrientationHV orientation = (OrientationHV) property.getValue();
// property.setValue(OrientationHV.values()[1 - orientation.ordinal()]);
// property.writeTo(component);
// } catch (Exception e) {
// LOG.error("Could not change component orientation for " + component.getName(), e);
// }
// }
// }
// } else {
// // Non-rotatable
// Point componentCenter = getCenterOf(Arrays.asList(new IDIYComponent<?>[] {component}),
// false);
// Point rotatedComponentCenter = new Point();
// rotate.transform(componentCenter, rotatedComponentCenter);
// for (int index = 0; index < component.getControlPointCount(); index++) {
// Point p = new Point(component.getControlPoint(index));
// p.translate(rotatedComponentCenter.x - componentCenter.x, rotatedComponentCenter.y -
// componentCenter.y);
// component.setControlPoint(p, index);
// }
// }
// }
}
@SuppressWarnings("unchecked")
@Override
public void mirrorSelection(int direction) {
if (!selectedComponents.isEmpty()) {
LOG.trace("Mirroring selected components");
Project oldProject = currentProject.clone();
Point center = getCenterOf(selectedComponents, isSnapToGrid());
boolean canMirror = true;
for (IDIYComponent<?> component : selectedComponents) {
ComponentType type =
ComponentProcessor.getInstance().extractComponentTypeFrom(
(Class<? extends IDIYComponent<?>>) component.getClass());
if (!type.isStretchable() && component.getControlPointCount() > 1) {
canMirror = false;
break;
}
}
if (!canMirror)
if (view.showConfirmDialog(
"Selection contains components that cannot bi mirrored. Do you want to exclude them?", "Mirror Selection",
IView.YES_NO_OPTION, IView.QUESTION_MESSAGE) != IView.YES_OPTION)
return;
for (IDIYComponent<?> component : selectedComponents) {
ComponentType type =
ComponentProcessor.getInstance().extractComponentTypeFrom(
(Class<? extends IDIYComponent<?>>) component.getClass());
if (type.isStretchable() || component.getControlPointCount() == 1) {
drawingManager.invalidateComponent(component);
for (int i = 0; i < component.getControlPointCount(); i++) {
Point p = component.getControlPoint(i);
if (direction == ISelectionProcessor.HORIZONTAL) {
component.setControlPoint(new Point(p.x - 2 * (p.x - center.x), p.y), i);
} else {
component.setControlPoint(new Point(p.x, p.y - 2 * (p.y - center.y)), i);
}
}
}
}
mirrorComponents(selectedComponents, direction, isSnapToGrid());
messageDispatcher.dispatchMessage(EventType.PROJECT_MODIFIED, oldProject, currentProject.clone(),
"Mirror Selection");
@@ -1188,6 +1180,39 @@ public class Presenter implements IPlugInPort {
}
}
@SuppressWarnings("unchecked")
private void mirrorComponents(Collection<IDIYComponent<?>> components, int direction, boolean snapToGrid) {
Point center = getCenterOf(components, snapToGrid);
boolean canMirror = true;
for (IDIYComponent<?> component : components) {
ComponentType type =
ComponentProcessor.getInstance().extractComponentTypeFrom(
(Class<? extends IDIYComponent<?>>) component.getClass());
if (type.getTransformer() == null || !type.getTransformer().canMirror(component)) {
canMirror = false;
break;
}
}
if (!canMirror)
if (view.showConfirmDialog("Selection contains components that cannot be mirrored. Do you want to exclude them?",
"Mirror Selection", IView.YES_NO_OPTION, IView.QUESTION_MESSAGE) != IView.YES_OPTION)
return;
for (IDIYComponent<?> component : components) {
ComponentType type =
ComponentProcessor.getInstance().extractComponentTypeFrom(
(Class<? extends IDIYComponent<?>>) component.getClass());
if (type.isStretchable() || component.getControlPointCount() == 1) {
drawingManager.invalidateComponent(component);
if (type.getTransformer() != null && type.getTransformer().canMirror(component)) {
type.getTransformer().mirror(component, center, direction);
}
}
}
}
private Point getCenterOf(Collection<IDIYComponent<?>> components, boolean snapToGrid) {
// Determine center of rotation
int minX = Integer.MAX_VALUE;