package renamed

This commit is contained in:
bancika
2011-01-04 18:44:00 +00:00
parent b38bb5526e
commit 4e935aecc9
163 changed files with 305 additions and 265 deletions
@@ -0,0 +1,240 @@
package org.diylc.presenter;
import java.awt.Point;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.apache.log4j.Logger;
import org.diylc.common.ControlPointWrapper;
import org.diylc.common.PropertyWrapper;
import org.diylc.model.IComponentInstance;
import org.diylc.model.annotations.BomName;
import org.diylc.model.annotations.BomValue;
import org.diylc.model.annotations.ControlPoint;
import org.diylc.model.annotations.EditableProperty;
import com.rits.cloning.Cloner;
/**
* Utility class with component processing methods.
*
* @author Branislav Stojkovic
*/
public class ComponentProcessor {
private static final Logger LOG = Logger.getLogger(ComponentProcessor.class);
private static ComponentProcessor instance;
private Map<Class<?>, List<PropertyWrapper>> propertyCache;
private Map<Class<?>, List<ControlPointWrapper>> controlPointCache;
private Cloner cloner;
public static ComponentProcessor getInstance() {
if (instance == null) {
instance = new ComponentProcessor();
}
return instance;
}
private ComponentProcessor() {
super();
this.cloner = new Cloner();
this.propertyCache = new HashMap<Class<?>, List<PropertyWrapper>>();
this.controlPointCache = new HashMap<Class<?>, List<ControlPointWrapper>>();
}
/**
* Extracts all editable properties from the component class.
*
* @param clazz
* @return
*/
public List<PropertyWrapper> extractProperties(Class<? extends IComponentInstance> clazz) {
if (propertyCache.containsKey(clazz)) {
return cloner.deepClone(propertyCache.get(clazz));
}
List<PropertyWrapper> properties = new ArrayList<PropertyWrapper>();
for (Method method : clazz.getMethods()) {
if (method.getName().startsWith("get")) {
try {
Method setter = clazz.getMethod("set" + method.getName().substring(3), method
.getReturnType());
if (method.isAnnotationPresent(EditableProperty.class)) {
EditableProperty annotation = method.getAnnotation(EditableProperty.class);
String name;
if (annotation.name().equals("")) {
name = method.getName().substring(3);
} else {
name = annotation.name();
}
PropertyWrapper property = new PropertyWrapper(name,
method.getReturnType(), method, setter, annotation.defaultable());
properties.add(property);
}
} catch (NoSuchMethodException e) {
LOG.debug("No matching setter found for \"" + method.getName()
+ "\". Skipping...");
}
}
}
propertyCache.put(clazz, properties);
return cloner.deepClone(properties);
}
/**
* Reads all control points from the specified component class. Note than
* control points are cached, so it may happen that control points returned
* already have their values populated. Always use
* {@link ControlPointWrapper#readFrom(IComponentInstance)} to update their
* state from an actual component.
*
* @param clazz
* @return
*/
public List<ControlPointWrapper> extractControlPoints(Class<? extends IComponentInstance> clazz) {
if (controlPointCache.containsKey(clazz)) {
return cloner.deepClone(controlPointCache.get(clazz));
}
List<ControlPointWrapper> controlPoints = new ArrayList<ControlPointWrapper>();
for (Method method : clazz.getMethods()) {
if (method.getName().startsWith("get")) {
try {
Method setter = clazz.getMethod("set" + method.getName().substring(3), method
.getReturnType());
if (method.isAnnotationPresent(ControlPoint.class)) {
if (method.getReturnType().equals(Point.class)) {
ControlPoint annotation = method.getAnnotation(ControlPoint.class);
ControlPointWrapper controlPoint = new ControlPointWrapper(method
.getName().substring(3), method, setter, annotation.editable(),
annotation.sticky(), annotation.visibilityPolicy());
controlPoints.add(controlPoint);
} else {
LOG.debug("Control point return type must be java.awt.Point.");
}
}
} catch (NoSuchMethodException e) {
LOG.debug("No matching setter found for \"" + method.getName()
+ "\". Skipping...");
}
}
}
controlPointCache.put(clazz, controlPoints);
return cloner.deepClone(controlPoints);
}
/**
* Returns properties mutual for all the selected components.
*
* @param selectedComponents
* @return
*/
public List<PropertyWrapper> getMutualSelectionProperties(
List<IComponentInstance> selectedComponents) {
if (selectedComponents.isEmpty()) {
return null;
}
List<PropertyWrapper> properties = new ArrayList<PropertyWrapper>();
IComponentInstance firstComponent = selectedComponents.get(0);
properties.addAll(extractProperties(firstComponent.getClass()));
// Initialize values
for (PropertyWrapper property : properties) {
try {
property.readFrom(firstComponent);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
for (int i = 1; i < selectedComponents.size(); i++) {
IComponentInstance component = selectedComponents.get(i);
List<PropertyWrapper> newProperties = extractProperties(component.getClass());
for (PropertyWrapper property : newProperties) {
try {
property.readFrom(component);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
properties.retainAll(newProperties);
// for (PropertyWrapper property : properties) {
// try {
// property.readUniqueFrom(component);
// } catch (Exception e) {
// // TODO Auto-generated catch block
// e.printStackTrace();
// }
// }
}
return properties;
}
/**
* Finds the method annotated with {@link BomName} annotations and calls it
* to retrieve component name.
*
* @param component
* @return
*/
public String extractBomName(IComponentInstance component) {
String name = null;
for (Method method : component.getClass().getMethods()) {
if (method.isAnnotationPresent(BomName.class)) {
try {
name = method.invoke(component).toString();
} catch (Exception e) {
name = null;
}
}
}
return name;
}
/**
* Finds the method annotated with {@link BomName} and it's matching setter
* and calls the setter to update the component name.
*
* @param component
* @param newBomName
*/
public void writeBomName(IComponentInstance component, String newBomName) {
for (Method method : component.getClass().getMethods()) {
if (method.isAnnotationPresent(BomName.class)) {
try {
Method setter = component.getClass().getMethod(
method.getName().replaceFirst("get", "set"), String.class);
setter.invoke(component, newBomName);
} catch (Exception e) {
}
}
}
}
/**
* Finds the method annotated with {@link BomValue} annotations and calls it
* to retrieve component value.
*
* @param component
* @return
*/
public String extractBomValue(IComponentInstance component) {
String value = null;
for (Method method : component.getClass().getMethods()) {
if (method.isAnnotationPresent(BomValue.class)) {
try {
value = method.invoke(component).toString();
} catch (Exception e) {
value = null;
}
}
}
return value;
}
}
@@ -0,0 +1,483 @@
package org.diylc.presenter;
import java.awt.Color;
import java.awt.Composite;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GraphicsConfiguration;
import java.awt.Image;
import java.awt.Paint;
import java.awt.Polygon;
import java.awt.Rectangle;
import java.awt.RenderingHints;
import java.awt.Shape;
import java.awt.Stroke;
import java.awt.RenderingHints.Key;
import java.awt.font.FontRenderContext;
import java.awt.font.GlyphVector;
import java.awt.geom.AffineTransform;
import java.awt.geom.Arc2D;
import java.awt.geom.Area;
import java.awt.geom.Ellipse2D;
import java.awt.geom.RoundRectangle2D;
import java.awt.image.BufferedImage;
import java.awt.image.BufferedImageOp;
import java.awt.image.ImageObserver;
import java.awt.image.RenderedImage;
import java.awt.image.renderable.RenderableImage;
import java.text.AttributedCharacterIterator;
import java.util.Map;
/**
* {@link Graphics2D} wrapper that keeps track of all drawing actions and
* creates an {@link Area} that corresponds to drawn objects. Before each
* component is drawn, {@link #startedDrawingComponent()} should be called.
* After the component is drawn, area may be retrieved using
* {@link #finishedDrawingComponent()}.
*
* @author Branislav Stojkovic
*/
class G2DWrapper extends Graphics2D {
private Graphics2D canvasGraphics;
private Stroke originalStroke;
private Color originalColor;
private Composite originalComposite;
private AffineTransform originalTx;
private AffineTransform currentTx;
private Area currentArea;
/**
* Creates a wrapper around specified {@link Graphics2D} object.
*
* @param canvasGraphics
*/
public G2DWrapper(Graphics2D canvasGraphics) {
super();
this.canvasGraphics = canvasGraphics;
startedDrawingComponent();
}
/**
* Clears out the current area and caches canvas settings.
*/
public void startedDrawingComponent() {
currentArea = new Area();
originalStroke = canvasGraphics.getStroke();
originalColor = canvasGraphics.getColor();
originalTx = canvasGraphics.getTransform();
originalComposite = canvasGraphics.getComposite();
currentTx = new AffineTransform();
}
/**
* Reverts {@link Graphics2D} settings and returns area drawn by component
* in the meantime.
*
* @return
*/
public Area finishedDrawingComponent() {
canvasGraphics.setStroke(originalStroke);
canvasGraphics.setColor(originalColor);
canvasGraphics.setTransform(originalTx);
canvasGraphics.setComposite(originalComposite);
return currentArea;
}
private void appendShape(Shape s) {
Area area = new Area(s);
area.transform(currentTx);
currentArea.add(area);
}
@Override
public void addRenderingHints(Map<?, ?> hints) {
canvasGraphics.addRenderingHints(hints);
}
@Override
public void clip(Shape s) {
canvasGraphics.clip(s);
}
@Override
public void draw(Shape s) {
canvasGraphics.draw(s);
appendShape(s);
}
@Override
public void drawGlyphVector(GlyphVector g, float x, float y) {
canvasGraphics.drawGlyphVector(g, x, y);
}
@Override
public boolean drawImage(Image img, AffineTransform xform, ImageObserver obs) {
// FIXME: process map
return canvasGraphics.drawImage(img, xform, obs);
}
@Override
public void drawImage(BufferedImage img, BufferedImageOp op, int x, int y) {
canvasGraphics.drawImage(img, op, x, y);
// FIXME: process map
}
@Override
public void drawRenderableImage(RenderableImage img, AffineTransform xform) {
canvasGraphics.drawRenderableImage(img, xform);
// FIXME: process map
}
@Override
public void drawRenderedImage(RenderedImage img, AffineTransform xform) {
canvasGraphics.drawRenderedImage(img, xform);
// FIXME: process map
}
@Override
public void drawString(String str, int x, int y) {
canvasGraphics.drawString(str, x, y);
// FIXME: process map
}
@Override
public void drawString(String str, float x, float y) {
canvasGraphics.drawString(str, x, y);
// FIXME: process map
}
@Override
public void drawString(AttributedCharacterIterator iterator, int x, int y) {
canvasGraphics.drawString(iterator, x, y);
// FIXME: process map
}
@Override
public void drawString(AttributedCharacterIterator iterator, float x, float y) {
canvasGraphics.drawString(iterator, x, y);
// FIXME: process map
}
@Override
public void fill(Shape s) {
canvasGraphics.fill(s);
appendShape(s);
}
@Override
public Color getBackground() {
return canvasGraphics.getBackground();
}
@Override
public Composite getComposite() {
return canvasGraphics.getComposite();
}
@Override
public GraphicsConfiguration getDeviceConfiguration() {
return canvasGraphics.getDeviceConfiguration();
}
@Override
public FontRenderContext getFontRenderContext() {
return canvasGraphics.getFontRenderContext();
}
@Override
public Paint getPaint() {
return canvasGraphics.getPaint();
}
@Override
public Object getRenderingHint(Key hintKey) {
return canvasGraphics.getRenderingHint(hintKey);
}
@Override
public RenderingHints getRenderingHints() {
return canvasGraphics.getRenderingHints();
}
@Override
public Stroke getStroke() {
return canvasGraphics.getStroke();
}
@Override
public AffineTransform getTransform() {
return canvasGraphics.getTransform();
}
@Override
public boolean hit(Rectangle rect, Shape s, boolean onStroke) {
return canvasGraphics.hit(rect, s, onStroke);
}
@Override
public void rotate(double theta) {
canvasGraphics.rotate(theta);
currentTx.rotate(theta);
}
@Override
public void rotate(double theta, double x, double y) {
canvasGraphics.rotate(theta, x, y);
currentTx.rotate(theta, x, y);
}
@Override
public void scale(double sx, double sy) {
canvasGraphics.scale(sx, sy);
currentTx.scale(sx, sy);
}
@Override
public void setBackground(Color color) {
canvasGraphics.setBackground(color);
// FIXME: fix map
}
@Override
public void setComposite(Composite comp) {
canvasGraphics.setComposite(comp);
// FIXME: check this.
}
@Override
public void setPaint(Paint paint) {
canvasGraphics.setPaint(paint);
// FIXME: check this
}
@Override
public void setRenderingHint(Key hintKey, Object hintValue) {
canvasGraphics.setRenderingHint(hintKey, hintValue);
// FIXME: check this
}
@Override
public void setRenderingHints(Map<?, ?> hints) {
canvasGraphics.setRenderingHints(hints);
// FIXME: check this
}
@Override
public void setStroke(Stroke s) {
canvasGraphics.setStroke(s);
}
@Override
public void setTransform(AffineTransform Tx) {
canvasGraphics.setTransform(Tx);
currentTx = Tx;
}
@Override
public void shear(double shx, double shy) {
canvasGraphics.shear(shx, shy);
currentTx.shear(shx, shy);
}
@Override
public void transform(AffineTransform Tx) {
canvasGraphics.transform(Tx);
currentTx.concatenate(Tx);
}
@Override
public void translate(int x, int y) {
canvasGraphics.translate(x, y);
currentTx.translate(x, y);
}
@Override
public void translate(double tx, double ty) {
canvasGraphics.translate(tx, ty);
currentTx.translate(tx, ty);
}
@Override
public void clearRect(int x, int y, int width, int height) {
canvasGraphics.clearRect(x, y, width, height);
}
@Override
public void clipRect(int x, int y, int width, int height) {
canvasGraphics.clipRect(x, y, width, height);
}
@Override
public void copyArea(int x, int y, int width, int height, int dx, int dy) {
canvasGraphics.copyArea(x, y, width, height, dx, dy);
}
@Override
public Graphics create() {
return canvasGraphics.create();
}
@Override
public void dispose() {
canvasGraphics.dispose();
}
@Override
public void drawArc(int x, int y, int width, int height, int startAngle, int arcAngle) {
canvasGraphics.drawArc(x, y, width, height, startAngle, arcAngle);
}
@Override
public boolean drawImage(Image img, int x, int y, ImageObserver observer) {
// FIXME: map
return canvasGraphics.drawImage(img, x, y, observer);
}
@Override
public boolean drawImage(Image img, int x, int y, Color bgcolor, ImageObserver observer) {
// FIXME: map
return canvasGraphics.drawImage(img, x, y, bgcolor, observer);
}
@Override
public boolean drawImage(Image img, int x, int y, int width, int height, ImageObserver observer) {
// FIXME: map
return canvasGraphics.drawImage(img, x, y, width, height, observer);
}
@Override
public boolean drawImage(Image img, int x, int y, int width, int height, Color bgcolor,
ImageObserver observer) {
// FIXME: map
return canvasGraphics.drawImage(img, x, y, width, height, bgcolor, observer);
}
@Override
public boolean drawImage(Image img, int dx1, int dy1, int dx2, int dy2, int sx1, int sy1,
int sx2, int sy2, ImageObserver observer) {
// FIXME: map
return canvasGraphics.drawImage(img, dx1, dy1, dx2, dy2, sx1, sy1, sx2, sy2, observer);
}
@Override
public boolean drawImage(Image img, int dx1, int dy1, int dx2, int dy2, int sx1, int sy1,
int sx2, int sy2, Color bgcolor, ImageObserver observer) {
// FIXME: map
return drawImage(img, dx1, dy1, dx2, dy2, sx1, sy1, sx2, sy2, bgcolor, observer);
}
@Override
public void drawLine(int x1, int y1, int x2, int y2) {
canvasGraphics.drawLine(x1, y1, x2, y2);
}
@Override
public void drawOval(int x, int y, int width, int height) {
canvasGraphics.drawOval(x, y, width, height);
appendShape(new Ellipse2D.Double(x, y, width, height));
}
@Override
public void drawPolygon(int[] points, int[] points2, int points3) {
canvasGraphics.drawPolygon(points, points2, points3);
}
@Override
public void drawPolyline(int[] points, int[] points2, int points3) {
canvasGraphics.drawPolyline(points, points2, points3);
}
@Override
public void drawRoundRect(int x, int y, int width, int height, int arcWidth, int arcHeight) {
canvasGraphics.drawRoundRect(x, y, width, height, arcWidth, arcHeight);
appendShape(new RoundRectangle2D.Double(x, y, width, height, arcWidth, arcHeight));
}
@Override
public void fillArc(int x, int y, int width, int height, int startAngle, int arcAngle) {
canvasGraphics.fillArc(x, y, width, height, startAngle, arcAngle);
appendShape(new Arc2D.Double(x, y, width, height, startAngle, arcAngle, Arc2D.PIE));
}
@Override
public void fillOval(int x, int y, int width, int height) {
canvasGraphics.fillOval(x, y, width, height);
appendShape(new Ellipse2D.Double(x, y, width, height));
}
@Override
public void fillPolygon(int[] points, int[] points2, int points3) {
canvasGraphics.fillPolygon(points, points2, points3);
appendShape(new Polygon(points, points2, points3));
}
@Override
public void fillRect(int x, int y, int width, int height) {
canvasGraphics.fillRect(x, y, width, height);
appendShape(new Rectangle(x, y, width, height));
}
@Override
public void fillRoundRect(int x, int y, int width, int height, int arcWidth, int arcHeight) {
canvasGraphics.fillRoundRect(x, y, width, height, arcWidth, arcHeight);
appendShape(new RoundRectangle2D.Double(x, y, width, height, arcWidth, arcHeight));
}
@Override
public Shape getClip() {
return canvasGraphics.getClip();
}
@Override
public Rectangle getClipBounds() {
return canvasGraphics.getClipBounds();
}
@Override
public Color getColor() {
return canvasGraphics.getColor();
}
@Override
public Font getFont() {
return canvasGraphics.getFont();
}
@Override
public FontMetrics getFontMetrics(Font f) {
return canvasGraphics.getFontMetrics(f);
}
@Override
public void setClip(Shape clip) {
canvasGraphics.setClip(clip);
}
@Override
public void setClip(int x, int y, int width, int height) {
canvasGraphics.setClip(x, y, width, height);
}
@Override
public void setColor(Color c) {
canvasGraphics.setColor(c);
}
@Override
public void setFont(Font font) {
canvasGraphics.setFont(font);
}
@Override
public void setPaintMode() {
canvasGraphics.setPaintMode();
}
@Override
public void setXORMode(Color c1) {
canvasGraphics.setXORMode(c1);
}
}
@@ -0,0 +1,780 @@
package org.diylc.presenter;
import java.awt.AlphaComposite;
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Composite;
import java.awt.Cursor;
import java.awt.Dimension;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.RenderingHints;
import java.awt.geom.AffineTransform;
import java.awt.geom.Area;
import java.awt.geom.Point2D;
import java.util.ArrayList;
import java.util.EnumSet;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.Map.Entry;
import javax.swing.Action;
import javax.swing.JComponent;
import org.apache.log4j.Logger;
import org.diylc.common.BadPositionException;
import org.diylc.common.ComponentSelection;
import org.diylc.common.ControlPointWrapper;
import org.diylc.common.DrawOption;
import org.diylc.common.EventType;
import org.diylc.common.IPlugIn;
import org.diylc.common.IPlugInPort;
import org.diylc.common.PropertyWrapper;
import org.diylc.gui.IView;
import org.diylc.model.ComponentLayer;
import org.diylc.model.ComponentState;
import org.diylc.model.IComponentInstance;
import org.diylc.model.IComponentType;
import org.diylc.model.Project;
import org.diylc.model.VisibilityPolicy;
import org.diylc.utils.Constants;
import com.diyfever.gui.miscutils.ConfigurationManager;
import com.diyfever.gui.miscutils.JarScanner;
import com.diyfever.gui.miscutils.Utils;
import com.diyfever.gui.simplemq.MessageDispatcher;
import com.diyfever.gui.update.VersionNumber;
import com.rits.cloning.Cloner;
/**
* The main presenter class.
*
* @author Branislav Stojkovic
*/
public class Presenter implements IPlugInPort {
private static final Logger LOG = Logger.getLogger(Presenter.class);
private static final VersionNumber CURRENT_VERSION = new VersionNumber(0, 0, 0);
private static final String DEFAULTS_KEY = "defaults";
private static final int CONTROL_POINT_SENSITIVITY = 4;
private double zoomLevel = 1;
private Map<IComponentInstance, Area> componentAreaMap;
private Project currentProject;
private Map<String, List<IComponentType>> componentTypes;
private List<IPlugIn> plugIns;
private ComponentSelection selectedComponents;
// List of components that have at least one of their control points
// under the last recorded mouse position.
private Map<IComponentInstance, ControlPointWrapper> componentControlPointMap;
private Cloner cloner;
private Rectangle selectionRect;
private final IView view;
private MessageDispatcher<EventType> messageDispatcher;
// Layers
private Set<ComponentLayer> lockedLayers;
private Set<ComponentLayer> visibleLayers;
// D&D
private boolean dragInProgress = false;
// Previous mouse location, not scaled for zoom factor.
private Point previousDragPoint = null;
private Project preDragProject = null;
private IComponentType componentSlot;
public Presenter(IView view) {
super();
this.view = view;
componentAreaMap = new HashMap<IComponentInstance, Area>();
plugIns = new ArrayList<IPlugIn>();
messageDispatcher = new MessageDispatcher<EventType>();
selectedComponents = new ComponentSelection();
currentProject = new Project();
cloner = new Cloner();
lockedLayers = EnumSet.noneOf(ComponentLayer.class);
visibleLayers = EnumSet.allOf(ComponentLayer.class);
}
public void installPlugin(IPlugIn plugIn) {
LOG.debug(String.format("installPlugin(%s)", plugIn.getClass().getSimpleName()));
plugIns.add(plugIn);
plugIn.connect(this);
messageDispatcher.registerListener(plugIn);
}
public void dispose() {
for (IPlugIn plugIn : plugIns) {
messageDispatcher.unregisterListener(plugIn);
}
}
// IPlugInPort
@Override
public double getZoomLevel() {
return zoomLevel;
}
@Override
public void setZoomLevel(double zoomLevel) {
LOG.debug(String.format("setZoomLevel(%s)", zoomLevel));
this.zoomLevel = zoomLevel;
messageDispatcher.dispatchMessage(EventType.ZOOM_CHANGED, zoomLevel);
messageDispatcher.dispatchMessage(EventType.REPAINT);
}
@Override
public Cursor getCursorAt(Point point) {
// Only change the cursor if we're not making a new component.
if (componentSlot == null) {
// Scale point to remove zoom factor.
Point2D scaledPoint = scalePoint(point);
for (Map.Entry<IComponentInstance, Area> entry : componentAreaMap.entrySet()) {
if (entry.getValue().contains(scaledPoint)) {
return Cursor.getPredefinedCursor(Cursor.HAND_CURSOR);
}
}
if (componentControlPointMap != null && !componentControlPointMap.isEmpty()) {
return Cursor.getPredefinedCursor(Cursor.HAND_CURSOR);
}
}
return Cursor.getDefaultCursor();
}
@Override
public Dimension getCanvasDimensions(boolean useZoom) {
double width = currentProject.getWidth().convertToPixels();
int height = currentProject.getHeight().convertToPixels();
if (useZoom) {
width *= zoomLevel;
height *= zoomLevel;
}
return new Dimension((int) width, (int) height);
}
@Override
public Project getCurrentProject() {
return currentProject;
}
@Override
public void loadProject(Project project, boolean freshStart) {
LOG.info("Loading project: " + project.getTitle());
this.currentProject = project;
selectedComponents.clear();
messageDispatcher.dispatchMessage(EventType.PROJECT_LOADED, project, freshStart);
messageDispatcher.dispatchMessage(EventType.REPAINT);
}
@Override
public Map<String, List<IComponentType>> getComponentTypes() {
if (componentTypes == null) {
LOG.info("Loading component types.");
componentTypes = new HashMap<String, List<IComponentType>>();
List<Class<?>> componentTypeClasses = JarScanner.getInstance().scanFolder("library/",
IComponentType.class);
for (Class<?> clazz : componentTypeClasses) {
try {
IComponentType componentType = (IComponentType) clazz.newInstance();
List<IComponentType> nestedList;
if (componentTypes.containsKey(componentType.getCategory())) {
nestedList = componentTypes.get(componentType.getCategory());
} else {
nestedList = new ArrayList<IComponentType>();
componentTypes.put(componentType.getCategory(), nestedList);
}
nestedList.add(componentType);
} catch (InstantiationException e) {
LOG.warn("Could not instantiate: " + clazz.getName());
} catch (IllegalAccessException e) {
LOG.warn("Could not access: " + clazz.getName());
}
}
}
return componentTypes;
}
@Override
public void draw(Graphics2D g2d, Set<DrawOption> drawOptions) {
if (currentProject == null) {
return;
}
G2DWrapper g2dWrapper = new G2DWrapper(g2d);
if (drawOptions.contains(DrawOption.ANTIALIASING)) {
g2d
.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
}
AffineTransform initialTx = g2d.getTransform();
Dimension d = getCanvasDimensions(drawOptions.contains(DrawOption.ZOOM));
g2dWrapper.setColor(Color.white);
g2dWrapper.fillRect(0, 0, d.width, d.height);
if (drawOptions.contains(DrawOption.GRID)) {
double zoomStep = Constants.GRID * zoomLevel;
// Point2D p = new Point2D.Double(step, 0);
// g2d.getTransform().transform(p, p);
// System.out.println(p);
g2dWrapper.setColor(Constants.GRID_COLOR);
for (double i = zoomStep; i < d.width; i += zoomStep) {
g2dWrapper.drawLine((int) i, 0, (int) i, d.height - 1);
}
for (double j = zoomStep; j < d.height; j += zoomStep) {
g2dWrapper.drawLine(0, (int) j, d.width - 1, (int) j);
}
}
if ((drawOptions.contains(DrawOption.ZOOM)) && (Math.abs(1.0 - zoomLevel) > 1e-4)) {
g2dWrapper.scale(zoomLevel, zoomLevel);
}
Composite mainComposite = g2d.getComposite();
Composite alphaComposite = AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.5f);
// g2dWrapper.resetTx();
List<IComponentInstance> components = getCurrentProject().getComponents();
componentAreaMap.clear();
if (components != null) {
for (IComponentInstance component : components) {
g2dWrapper.startedDrawingComponent();
ComponentState state = ComponentState.NORMAL;
if (drawOptions.contains(DrawOption.SELECTION)
&& selectedComponents.contains(component)) {
if (dragInProgress) {
state = ComponentState.DRAGGING;
} else {
state = ComponentState.SELECTED;
}
}
// If the component is being dragged, draw it in a separate
// composite.
if (state == ComponentState.DRAGGING) {
g2dWrapper.setComposite(alphaComposite);
}
// Draw the component through the g2dWrapper.
component.draw(g2dWrapper, state);
// Restore the composite if needed.
if (state == ComponentState.DRAGGING) {
g2dWrapper.setComposite(mainComposite);
}
componentAreaMap.put(component, g2dWrapper.finishedDrawingComponent());
// Draw control points
if (drawOptions.contains(DrawOption.CONTROL_POINTS)) {
List<ControlPointWrapper> controlPoints = ComponentProcessor.getInstance()
.extractControlPoints(component.getClass());
for (ControlPointWrapper controlPoint : controlPoints) {
try {
controlPoint.readFrom(component);
if (shouldShowControlPoint(controlPoint, component)) {
g2d.setColor(Color.blue);
g2d.setStroke(new BasicStroke(2));
g2d.drawOval(controlPoint.getValue().x - 2,
controlPoint.getValue().y - 2, 4, 4);
// g2d.fillOval(point.getValue().x - 2, point
// .getValue().y - 2, 5, 5);
}
} catch (Exception e) {
LOG.error("Could not obtain control points for component of type "
+ component.getClass().getName());
}
}
}
}
}
g2d.setTransform(initialTx);
if ((drawOptions.contains(DrawOption.ZOOM)) && (Math.abs(1.0 - zoomLevel) > 1e-4)) {
g2d.scale(zoomLevel, zoomLevel);
}
// At the end draw selection rectangle if needed.
if (drawOptions.contains(DrawOption.SELECTION) && (selectionRect != null)) {
g2d.setColor(Color.white);
g2d.draw(selectionRect);
g2d.setColor(Color.black);
g2d.setStroke(Constants.dashedStroke);
g2d.draw(selectionRect);
}
// // Draw component area for test
// g2d.setStroke(new BasicStroke());
// g2d.setColor(Color.red);
// for (Area area : componentAreaMap.values()) {
// g2d.draw(area);
// }
}
@Override
public void injectGUIComponent(JComponent component, int position) throws BadPositionException {
view.addComponent(component, position);
}
@Override
public void injectMenuAction(Action action, String menuName) {
view.addMenuAction(action, menuName);
}
// @Override
// public void setCursorIcon(Icon icon) {
// view.setCursorIcon(icon);
// }
/**
* Finds all components whose areas include the specified {@link Point}.
* Point is <b>not</b> scaled by the zoom factor.
*
* @return
*/
private List<IComponentInstance> findComponentsAt(Point point) {
List<IComponentInstance> components = new ArrayList<IComponentInstance>();
for (Map.Entry<IComponentInstance, Area> entry : componentAreaMap.entrySet()) {
if (entry.getValue().contains(point)) {
components.add(entry.getKey());
}
}
return components;
}
@Override
public void mouseClicked(Point point, boolean ctrlDown, boolean shiftDown, boolean altDown) {
LOG.debug(String
.format("mouseClicked(%s, %s, %s, %s)", point, ctrlDown, shiftDown, altDown));
Point scaledPoint = scalePoint(point);
if (componentSlot != null) {
try {
instantiateComponent(componentSlot.getComponentInstanceClass(), componentSlot
.getName(), componentSlot.getInstanceNamePrefix(), scaledPoint);
} catch (Exception e) {
LOG.error("Error instatiating component of type: "
+ componentSlot.getComponentInstanceClass().getName());
}
setNewComponentSlot(null);
} else {
List<IComponentInstance> components = findComponentsAt(scaledPoint);
// If there's nothing under mouse cursor deselect all.
if (components.isEmpty()) {
selectedComponents.clear();
} else {
IComponentInstance component = components.get(0);
// If ctrl is pressed just toggle the component under mouse
// cursor.
if (ctrlDown) {
if (selectedComponents.contains(component)) {
selectedComponents.remove(component);
} else {
selectedComponents.add(component);
}
} else {
// Otherwise just select that one component.
selectedComponents.clear();
selectedComponents.add(component);
}
}
messageDispatcher.dispatchMessage(EventType.SELECTION_CHANGED, selectedComponents);
messageDispatcher.dispatchMessage(EventType.REPAINT);
}
}
@Override
public void mouseMoved(Point point, boolean ctrlDown, boolean shiftDown, boolean altDown) {
Map<IComponentInstance, ControlPointWrapper> components = new HashMap<IComponentInstance, ControlPointWrapper>();
Point scaledPoint = scalePoint(point);
for (IComponentInstance component : currentProject.getComponents()) {
List<ControlPointWrapper> currentPoints = ComponentProcessor.getInstance()
.extractControlPoints(component.getClass());
for (ControlPointWrapper controlPoint : currentPoints) {
if (shouldShowControlPoint(controlPoint, component)) {
try {
controlPoint.readFrom(component);
if (scaledPoint.distance(controlPoint.getValue()) < CONTROL_POINT_SENSITIVITY) {
components.put(component, controlPoint);
break;
}
} catch (Exception e) {
LOG.warn("Error reading control point for component of type: "
+ component.getClass().getName());
}
}
}
// If CTRL is pressed, we only care about the top most component.
if (altDown && components.size() > 0) {
break;
}
}
if (!components.equals(componentControlPointMap)) {
componentControlPointMap = components;
messageDispatcher.dispatchMessage(EventType.AVAILABLE_CTRL_POINTS_CHANGED, components);
}
}
@Override
public ComponentSelection getSelectedComponents() {
return new ComponentSelection(selectedComponents);
}
@Override
public Area getComponentArea(IComponentInstance component) {
return componentAreaMap.get(component);
}
@Override
public VersionNumber getCurrentVersionNumber() {
return CURRENT_VERSION;
}
@Override
public void dragStarted(Point point) {
LOG.debug(String.format("dragStarted(%s)", point));
dragInProgress = true;
preDragProject = cloner.deepClone(currentProject);
Point scaledPoint = scalePoint(point);
previousDragPoint = scaledPoint;
List<IComponentInstance> components = findComponentsAt(scaledPoint);
if (!componentControlPointMap.isEmpty()) {
// If we're dragging control points reset selection.
selectedComponents.clear();
selectedComponents.addAll(componentControlPointMap.keySet());
messageDispatcher.dispatchMessage(EventType.SELECTION_CHANGED, selectedComponents);
messageDispatcher.dispatchMessage(EventType.REPAINT);
} else if (components.isEmpty()) {
// If there are no components are under the cursor, reset selection.
selectedComponents.clear();
messageDispatcher.dispatchMessage(EventType.SELECTION_CHANGED, selectedComponents);
messageDispatcher.dispatchMessage(EventType.REPAINT);
} else {
IComponentInstance component = components.get(0);
// If the component under the cursor is not already selected, make
// it into the only selected component.
if (!selectedComponents.contains(component)) {
selectedComponents.clear();
selectedComponents.add(component);
messageDispatcher.dispatchMessage(EventType.SELECTION_CHANGED, selectedComponents);
messageDispatcher.dispatchMessage(EventType.REPAINT);
}
}
}
@Override
public boolean dragOver(Point point) {
if (point == null) {
return false;
}
Point scaledPoint = scalePoint(point);
if (!componentControlPointMap.isEmpty()) {
// We're dragging control point(s).
IComponentInstance firstComponent = componentControlPointMap.keySet().iterator().next();
ControlPointWrapper controlPoint = componentControlPointMap.get(firstComponent);
if (controlPoint == null) {
LOG.warn("Control point not found in the map!");
}
// Re-read the value just in case.
try {
controlPoint.readFrom(firstComponent);
} catch (Exception e) {
e.printStackTrace();
}
int x = (int) (Math
.round((controlPoint.getValue().x + scaledPoint.x - previousDragPoint.x)
/ Constants.GRID) * Constants.GRID);
int y = (int) (Math
.round((controlPoint.getValue().y + scaledPoint.y - previousDragPoint.y)
/ Constants.GRID) * Constants.GRID);
previousDragPoint.setLocation(x, y);
for (Entry<IComponentInstance, ControlPointWrapper> entry : componentControlPointMap
.entrySet()) {
try {
controlPoint = entry.getValue();
IComponentInstance component = entry.getKey();
controlPoint.readFrom(component);
if (controlPoint.isEditable()) {
controlPoint.getValue().setLocation(x, y);
}
controlPoint.writeTo(component);
} catch (Exception e) {
}
}
// dragStartPoint = point;
} else if (selectedComponents.isEmpty()) {
// If there's no selection, the only thing to do is update the
// selection rectangle and refresh.
this.selectionRect = Utils.createRectangle(scaledPoint, previousDragPoint);
// messageDispatcher.dispatchMessage(EventType.SELECTION_RECT_CHANGED,
// selectionRect);
} else {
// If there are components selected translate their control points.
translateSelectedComponents(previousDragPoint, scaledPoint);
// dragStartPoint = point;
}
messageDispatcher.dispatchMessage(EventType.REPAINT);
return true;
}
@Override
public void dragEnded(Point point) {
LOG.debug(String.format("dragEnded(%s)", point));
if (!dragInProgress) {
return;
}
Point scaledPoint = scalePoint(point);
if (selectedComponents.isEmpty()) {
// If there's no selection finalize selectionRect and see which
// components intersect with it.
if (scaledPoint != null) {
this.selectionRect = Utils.createRectangle(scaledPoint, previousDragPoint);
}
selectedComponents.clear();
for (IComponentInstance component : currentProject.getComponents()) {
Area area = componentAreaMap.get(component);
if ((area != null) && area.intersects(selectionRect)) {
selectedComponents.add(component);
}
}
selectionRect = null;
messageDispatcher.dispatchMessage(EventType.SELECTION_CHANGED, selectedComponents);
}
// There is selection, so we need to finalize the drag&drop
// operation.
if (!preDragProject.equals(currentProject)) {
messageDispatcher.dispatchMessage(EventType.PROJECT_MODIFIED, preDragProject, cloner
.deepClone(currentProject), "Move");
}
messageDispatcher.dispatchMessage(EventType.REPAINT);
dragInProgress = false;
}
private void translateSelectedComponents(Point fromPoint, Point toPoint) {
if (toPoint == null) {
LOG.debug("Drag ended outside the drawing area.");
return;
}
int dx = (int) (Math.round((toPoint.x - fromPoint.x) / zoomLevel / Constants.GRID) * Constants.GRID);
int dy = (int) (Math.round((toPoint.y - fromPoint.y) / zoomLevel / Constants.GRID) * Constants.GRID);
fromPoint.translate(dx, dy);
for (IComponentInstance component : selectedComponents) {
List<ControlPointWrapper> controlPoints = ComponentProcessor.getInstance()
.extractControlPoints(component.getClass());
for (ControlPointWrapper controlPoint : controlPoints) {
try {
controlPoint.readFrom(component);
if (controlPoint.isEditable()) {
translateControlPoint(controlPoint, dx, dy);
}
controlPoint.writeTo(component);
} catch (Exception e) {
LOG.error("Could not translate control points: " + e.getMessage());
}
}
}
}
private void translateControlPoint(ControlPointWrapper controlPoint, int dx, int dy) {
int x = controlPoint.getValue().x + dx;
int y = controlPoint.getValue().y + dy;
controlPoint.getValue().setLocation(x, y);
}
@Override
public void addComponents(List<IComponentInstance> components, Point preferredPoint) {
LOG.debug(String.format("addComponents(%s)", components));
Project oldProject = cloner.deepClone(currentProject);
currentProject.getComponents().addAll(components);
messageDispatcher.dispatchMessage(EventType.PROJECT_MODIFIED, oldProject, cloner
.deepClone(currentProject), "Add");
messageDispatcher.dispatchMessage(EventType.REPAINT);
}
public boolean isLayerLocked(ComponentLayer layer) {
return lockedLayers.contains(layer);
}
public void setLayerLocked(ComponentLayer layer, boolean locked) {
LOG.debug(String.format("setLayerLocked(%s, %s)", layer, locked));
if (locked) {
lockedLayers.add(layer);
} else {
lockedLayers.remove(layer);
}
}
public boolean isLayerVisible(ComponentLayer layer) {
return visibleLayers.contains(layer);
}
public void setLayerVisible(ComponentLayer layer, boolean visible) {
LOG.debug(String.format("setLayerVisible(%s, %s)", layer, visible));
if (visible) {
visibleLayers.add(layer);
} else {
visibleLayers.remove(layer);
}
}
@SuppressWarnings("unchecked")
@Override
// @Override
// public Object getDefaultPropertyValue(
// Class<? extends IComponentInstance> componentClass,
// String propertyName) {
// return configuration.getDefaultPropertyValues().get(
// componentClass.getName() + ":" + propertyName);
// }
public void setDefaultPropertyValue(String propertyName, Object value) {
LOG.debug(String.format("setDefaultPropertyValue(%s, %s)", propertyName, value));
Map<String, Object> defaultMap = (Map<String, Object>) ConfigurationManager.getInstance()
.getConfigurationItem(DEFAULTS_KEY);
if (defaultMap == null) {
defaultMap = new HashMap<String, Object>();
ConfigurationManager.getInstance().setConfigurationItem(DEFAULTS_KEY, defaultMap);
}
for (IComponentInstance component : selectedComponents) {
String className = component.getClass().getName();
LOG.debug("Default property value set for " + className + ":" + propertyName);
defaultMap.put(className + ":" + propertyName, value);
}
}
@SuppressWarnings("unchecked")
private void instantiateComponent(Class<? extends IComponentInstance> componentClass,
String componentTypeName, String namePrefix, Point point) throws Exception {
LOG.info("Instatiating component of type: " + componentClass.getName());
Project oldProject = cloner.deepClone(currentProject);
// Instantiate the component.
IComponentInstance component = componentClass.newInstance();
// Find the next available name for the component.
int i = 0;
boolean exists = true;
while (exists) {
i++;
String name = namePrefix + i;
exists = false;
for (IComponentInstance c : currentProject.getComponents()) {
String cName = ComponentProcessor.getInstance().extractBomName(c);
if (cName.equals(name)) {
exists = true;
break;
}
}
}
ComponentProcessor.getInstance().writeBomName(component, namePrefix + i);
// Add it to the project.
currentProject.getComponents().add(component);
// Extract control points.
List<ControlPointWrapper> controlPoints = ComponentProcessor.getInstance()
.extractControlPoints(componentClass);
// Translate them to the desired location.
if (point != null) {
for (ControlPointWrapper controlPoint : controlPoints) {
controlPoint.readFrom(component);
int x = controlPoint.getValue().x + point.x;
int y = controlPoint.getValue().y + point.y;
x = (int) (Math.round(x / Constants.GRID) * Constants.GRID);
y = (int) (Math.round(y / Constants.GRID) * Constants.GRID);
controlPoint.getValue().setLocation(x, y);
controlPoint.writeTo(component);
}
}
// Extract properties.
List<PropertyWrapper> properties = ComponentProcessor.getInstance().extractProperties(
componentClass);
// Override with default values if available.
for (PropertyWrapper property : properties) {
Object defaultValue = null;
Map<String, Object> defaultMap = (Map<String, Object>) ConfigurationManager
.getInstance().getConfigurationItem(DEFAULTS_KEY);
if (defaultMap != null) {
defaultValue = defaultMap.get(componentClass.getName() + ":" + property.getName());
}
if (defaultValue != null) {
property.setValue(cloner.deepClone(defaultValue));
property.writeTo(component);
}
}
// Notify the listeners.
if (!oldProject.equals(currentProject)) {
messageDispatcher.dispatchMessage(EventType.PROJECT_MODIFIED, oldProject, cloner
.deepClone(currentProject), "Add " + componentTypeName);
}
messageDispatcher.dispatchMessage(EventType.REPAINT);
}
@Override
public List<PropertyWrapper> getMutualSelectionProperties() {
return ComponentProcessor.getInstance().getMutualSelectionProperties(selectedComponents);
}
@Override
public void applyPropertiesToSelection(List<PropertyWrapper> properties) throws Exception {
LOG.debug(String.format("applyPropertiesToSelection(%s)", properties));
Project oldProject = cloner.deepClone(currentProject);
try {
for (IComponentInstance component : selectedComponents) {
for (PropertyWrapper property : properties) {
property.writeTo(component);
}
}
} finally {
// Notify the listeners.
if (!oldProject.equals(currentProject)) {
messageDispatcher.dispatchMessage(EventType.PROJECT_MODIFIED, oldProject, cloner
.deepClone(currentProject), "Edit");
}
messageDispatcher.dispatchMessage(EventType.REPAINT);
}
}
@Override
public void setNewComponentSlot(IComponentType componentType) {
LOG.debug(String.format("setNewComponentSlot(%s)", componentType == null ? null
: componentType.getName()));
this.componentSlot = componentType;
selectedComponents.clear();
messageDispatcher.dispatchMessage(EventType.SELECTION_CHANGED);
messageDispatcher.dispatchMessage(EventType.SLOT_CHANGED, componentSlot);
}
/**
* Scales point from display base to actual base.
*
* @param point
* @return
*/
private Point scalePoint(Point point) {
return point == null ? null : new Point((int) (point.x / zoomLevel),
(int) (point.y / zoomLevel));
}
private boolean shouldShowControlPoint(ControlPointWrapper controlPoint,
IComponentInstance component) {
return controlPoint.getVisibilityPolicy().equals(VisibilityPolicy.ALWAYS)
|| ((controlPoint.getVisibilityPolicy().equals(VisibilityPolicy.WHEN_SELECTED)) && (getSelectedComponents()
.contains(component)));
}
}