[Improvement] Improved overall performance

[Bug Fix] Should be more stable under OSX and not crash unexpectedly
This commit is contained in:
bancika
2012-08-21 08:29:27 +00:00
parent 246decdf7c
commit 3f9caf9918
17 changed files with 183 additions and 84 deletions
@@ -7,11 +7,11 @@
<classpathentry kind="lib" path="lib/xstream-1.3.1.jar"/>
<classpathentry kind="lib" path="lib/junit-4.7.jar"/>
<classpathentry kind="lib" path="lib/iText-2.1.7.jar"/>
<classpathentry kind="lib" path="lib/cloning-1.5.jar"/>
<classpathentry kind="lib" path="lib/objenesis-1.1.jar"/>
<classpathentry kind="lib" path="lib/jettison-1.0.1.jar"/>
<classpathentry kind="lib" path="lib/poi-3.5-FINAL-20090928.jar"/>
<classpathentry kind="lib" path="library/main.jar"/>
<classpathentry kind="lib" path="lib/app-framework.jar"/>
<classpathentry combineaccessrules="false" kind="src" path="/app-framework"/>
<classpathentry kind="lib" path="lib/cloning-1.8.1.jar"/>
<classpathentry kind="lib" path="lib/objenesis-1.2.jar"/>
<classpathentry kind="output" path="bin"/>
</classpath>
@@ -4,20 +4,30 @@ import java.awt.Color;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.Shape;
import java.awt.font.FontRenderContext;
import java.awt.font.GlyphVector;
import java.lang.reflect.Array;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import org.diylc.common.HorizontalAlignment;
import org.diylc.common.VerticalAlignment;
import org.diylc.core.IDIYComponent;
import org.diylc.core.annotations.EditableProperty;
import com.rits.cloning.CloningException;
/**
* Abstract implementation of {@link IDIYComponent} that contains component name
* and toString.
*
* IMPORTANT: to improve performance, all fields except for <code>Point</code>
* and <code>Point</code> arrays should be immutable. Failing to comply with
* this can result in annoying and hard to trace bugs.
*
* @author Branislav Stojkovic
*
* @param <T>
@@ -80,9 +90,11 @@ public abstract class AbstractComponent<T> implements IDIYComponent<T> {
}
protected void drawCenteredText(Graphics2D g2d, String text, int x, int y,
HorizontalAlignment horizontalAlignment, VerticalAlignment verticalAlignment) {
HorizontalAlignment horizontalAlignment,
VerticalAlignment verticalAlignment) {
FontMetrics fontMetrics = g2d.getFontMetrics();
Rectangle stringBounds = fontMetrics.getStringBounds(text, g2d).getBounds();
Rectangle stringBounds = fontMetrics.getStringBounds(text, g2d)
.getBounds();
Font font = g2d.getFont();
FontRenderContext renderContext = g2d.getFontRenderContext();
@@ -117,4 +129,55 @@ public abstract class AbstractComponent<T> implements IDIYComponent<T> {
g2d.drawString(text, textX, textY);
}
@SuppressWarnings("unchecked")
public IDIYComponent<T> clone() throws CloneNotSupportedException {
try {
// Instantiate object of the same type
AbstractComponent<T> newInstance = (AbstractComponent<T>) this
.getClass().getConstructors()[0].newInstance();
Class<?> clazz = this.getClass();
while (AbstractComponent.class.isAssignableFrom(clazz)) {
Field[] fields = clazz.getDeclaredFields();
clazz = clazz.getSuperclass();
// fields = this.getClass().getDeclaredFields();
// Copy over all non-static, non-final fields that are declared
// in
// AbstractComponent or one of it's child classes
for (Field field : fields) {
if (!Modifier.isStatic(field.getModifiers())
&& !Modifier.isFinal(field.getModifiers())) {
field.setAccessible(true);
Object value = field.get(this);
// Deep copy point arrays.
// TODO: something nicer
if (value != null
&& value.getClass().isArray()
&& value.getClass().getComponentType()
.isAssignableFrom(Point.class)) {
Object newArray = Array.newInstance(value
.getClass().getComponentType(), Array
.getLength(value));
for (int i = 0; i < Array.getLength(value); i++) {
Point p = (Point) Array.get(value, i);
Array.set(newArray, i, new Point(p));
}
value = newArray;
}
// Deep copy points.
// TODO: something nicer
if (value != null && value instanceof Point) {
value = new Point((Point) value);
}
field.set(newInstance, value);
}
}
}
return newInstance;
} catch (Exception e) {
throw new CloningException("Could not clone the component", e);
}
}
}
@@ -107,7 +107,8 @@ public interface IDIYComponent<T> extends Serializable {
* @param project
* @param drawingObserver
*/
void draw(Graphics2D g2d, ComponentState componentState, boolean outlineMode, Project project,
void draw(Graphics2D g2d, ComponentState componentState,
boolean outlineMode, Project project,
IDrawingObserver drawingObserver);
/**
@@ -119,4 +120,11 @@ public interface IDIYComponent<T> extends Serializable {
* @param height
*/
void drawIcon(Graphics2D g2d, int width, int height);
/**
* Clones the component.
*
* @return
*/
IDIYComponent<T> clone() throws CloneNotSupportedException;
}
@@ -2,8 +2,10 @@ package org.diylc.core;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.diylc.appframework.update.VersionNumber;
@@ -210,15 +212,37 @@ public class Project implements Serializable {
}
}
// @Override
// public Project clone() throws CloneNotSupportedException {
// List<IDIYComponent> clonedComponents = new
// ArrayList<IDIYComponent>();
// for (IDIYComponent component : components) {
// clonedComponents.add(component.clone());
// }
// Project project = new Project(title, author, description,
// width.clone(), height.clone(), clonedComponents);
// return project;
// }
@Override
public Project clone() {
Project project = new Project();
project.setTitle(this.getTitle());
project.setAuthor(this.getAuthor());
project.setDescription(this.getDescription());
project.setFileVersion(this.getFileVersion());
project.setGridSpacing(this.getGridSpacing());
project.setHeight(this.getHeight());
project.setWidth(this.getWidth());
project.getLockedLayers().addAll(this.getLockedLayers());
Map<IDIYComponent<?>, IDIYComponent<?>> cloneMap = new HashMap<IDIYComponent<?>, IDIYComponent<?>>();
for (IDIYComponent<?> component : this.components) {
try {
IDIYComponent<?> clone = component.clone();
project.getComponents().add(clone);
cloneMap.put(component, clone);
} catch (CloneNotSupportedException e) {
throw new RuntimeException(e);
}
}
for (Set<IDIYComponent<?>> group : this.groups) {
Set<IDIYComponent<?>> cloneGroup = new HashSet<IDIYComponent<?>>();
for (IDIYComponent<?> component : group) {
cloneGroup.add(cloneMap.get(component));
}
project.groups.add(cloneGroup);
}
return project;
}
}
@@ -4,6 +4,13 @@ import java.io.Serializable;
import java.text.DecimalFormat;
import java.text.Format;
/***
* Immutable measure class.
*
* @author bancika
*
* @param <T>
*/
public class AbstractMeasure<T extends Enum<? extends Unit>> implements Serializable, Cloneable {
private static final long serialVersionUID = 1L;
@@ -13,8 +20,8 @@ public class AbstractMeasure<T extends Enum<? extends Unit>> implements Serializ
protected Double value;
protected T unit;
public AbstractMeasure() {
}
// public AbstractMeasure() {
// }
public AbstractMeasure(Double value, T unit) {
super();
@@ -26,22 +33,22 @@ public class AbstractMeasure<T extends Enum<? extends Unit>> implements Serializ
return value;
}
public void setValue(Double value) {
this.value = value;
}
// public void setValue(Double value) {
// this.value = value;
// }
public T getUnit() {
return unit;
}
public void setUnit(T multiplier) {
this.unit = multiplier;
}
// public void setUnit(T multiplier) {
// this.unit = multiplier;
// }
@Override
public Object clone() throws CloneNotSupportedException {
return super.clone();
}
// @Override
// public Object clone() throws CloneNotSupportedException {
// return super.clone();
// }
@Override
public int hashCode() {
@@ -4,10 +4,10 @@ public class Capacitance extends AbstractMeasure<CapacitanceUnit> {
private static final long serialVersionUID = 1L;
public Capacitance() {
super();
// TODO Auto-generated constructor stub
}
// public Capacitance() {
// super();
// // TODO Auto-generated constructor stub
// }
public Capacitance(Double value, CapacitanceUnit unit) {
super(value, unit);
@@ -4,10 +4,10 @@ public class Inductance extends AbstractMeasure<InductanceUnit> {
private static final long serialVersionUID = 1L;
public Inductance() {
super();
// TODO Auto-generated constructor stub
}
// public Inductance() {
// super();
// // TODO Auto-generated constructor stub
// }
public Inductance(Double value, InductanceUnit unit) {
super(value, unit);
@@ -4,10 +4,10 @@ public class Power extends AbstractMeasure<PowerUnit> {
private static final long serialVersionUID = 1L;
public Power() {
super();
// TODO Auto-generated constructor stub
}
// public Power() {
// super();
// // TODO Auto-generated constructor stub
// }
public Power(Double value, PowerUnit unit) {
super(value, unit);
@@ -15,10 +15,10 @@ public class Resistance extends AbstractMeasure<ResistanceUnit> {
Color.decode("#FFB90F"), Color.black, Color.decode("#8B4513"), Color.red, Color.orange,
Color.yellow, Color.decode("#76EE00"), Color.blue };
public Resistance() {
super();
// TODO Auto-generated constructor stub
}
// public Resistance() {
// super();
// // TODO Auto-generated constructor stub
// }
public Resistance(Double value, ResistanceUnit multiplier) {
super(value, multiplier);
@@ -6,10 +6,10 @@ public class Size extends AbstractMeasure<SizeUnit> implements Comparable<Size>
private static final long serialVersionUID = 1L;
public Size() {
super();
// TODO Auto-generated constructor stub
}
// public Size() {
// super();
// // TODO Auto-generated constructor stub
// }
public Size(Double value, SizeUnit unit) {
super(value, unit);
@@ -4,10 +4,10 @@ public class Voltage extends AbstractMeasure<VoltageUnit> {
private static final long serialVersionUID = 1L;
public Voltage() {
super();
// TODO Auto-generated constructor stub
}
// public Voltage() {
// super();
// // TODO Auto-generated constructor stub
// }
public Voltage(Double value, VoltageUnit unit) {
super(value, unit);
@@ -47,8 +47,6 @@ import org.diylc.core.Theme;
import org.diylc.core.measures.SizeUnit;
import org.diylc.utils.Constants;
import com.rits.cloning.Cloner;
/**
* The main presenter class, contains core app logic and drawing routines.
*
@@ -58,7 +56,7 @@ public class Presenter implements IPlugInPort {
private static final Logger LOG = Logger.getLogger(Presenter.class);
public static final VersionNumber CURRENT_VERSION = new VersionNumber(3, 9,
public static final VersionNumber CURRENT_VERSION = new VersionNumber(3, 10,
0);
public static final String DEFAULTS_KEY_PREFIX = "default.";
@@ -79,7 +77,7 @@ public class Presenter implements IPlugInPort {
private Set<IDIYComponent<?>> lockedComponents;
// Utilities
private Cloner cloner;
//private Cloner cloner;
private DrawingManager drawingManager;
private ProjectFileManager projectFileManager;
private InstantiationManager instantiationManager;
@@ -109,7 +107,7 @@ public class Presenter implements IPlugInPort {
selectedComponents = new ArrayList<IDIYComponent<?>>();
lockedComponents = new HashSet<IDIYComponent<?>>();
currentProject = new Project();
cloner = new Cloner();
//cloner = new Cloner();
drawingManager = new DrawingManager(messageDispatcher);
projectFileManager = new ProjectFileManager(messageDispatcher);
instantiationManager = new InstantiationManager();
@@ -412,7 +410,7 @@ public class Presenter implements IPlugInPort {
// Keep the reference to component type for later.
ComponentType componentTypeSlot = instantiationManager
.getComponentTypeSlot();
Project oldProject = cloner.deepClone(currentProject);
Project oldProject = currentProject.clone();
switch (componentTypeSlot.getCreationMethod()) {
case SINGLE_CLICK:
try {
@@ -505,8 +503,7 @@ public class Presenter implements IPlugInPort {
// Notify the listeners.
if (!oldProject.equals(currentProject)) {
messageDispatcher.dispatchMessage(
EventType.PROJECT_MODIFIED, oldProject, cloner
.deepClone(currentProject), "Add "
EventType.PROJECT_MODIFIED, oldProject, currentProject.clone(), "Add "
+ componentTypeSlot.getName());
projectFileManager.notifyFileChange();
}
@@ -612,10 +609,10 @@ public class Presenter implements IPlugInPort {
return false;
}
Project oldProject = cloner.deepClone(currentProject);
Project oldProject = currentProject.clone();
moveSelectedComponents(controlPointMap, dx, dy, snapToGrid);
messageDispatcher.dispatchMessage(EventType.PROJECT_MODIFIED,
oldProject, cloner.deepClone(currentProject), "Move Selection");
oldProject, currentProject.clone(), "Move Selection");
messageDispatcher.dispatchMessage(EventType.REPAINT);
return true;
}
@@ -760,7 +757,7 @@ public class Presenter implements IPlugInPort {
}
this.dragInProgress = true;
this.dragAction = dragAction;
this.preDragProject = cloner.deepClone(currentProject);
this.preDragProject = currentProject.clone();
Point scaledPoint = scalePoint(point);
this.previousDragPoint = scaledPoint;
List<IDIYComponent<?>> components = findComponentsAtScaled(scaledPoint);
@@ -1067,7 +1064,7 @@ public class Presenter implements IPlugInPort {
if (!preDragProject.equals(currentProject)) {
messageDispatcher.dispatchMessage(EventType.PROJECT_MODIFIED,
preDragProject, cloner.deepClone(currentProject), "Drag");
preDragProject, currentProject.clone(), "Drag");
projectFileManager.notifyFileChange();
}
messageDispatcher.dispatchMessage(EventType.REPAINT);
@@ -1077,7 +1074,7 @@ public class Presenter implements IPlugInPort {
@Override
public void pasteComponents(List<IDIYComponent<?>> components) {
LOG.info(String.format("addComponents(%s)", components));
Project oldProject = cloner.deepClone(currentProject);
Project oldProject = currentProject.clone();
for (IDIYComponent<?> component : components) {
for (int i = 0; i < component.getControlPointCount(); i++) {
Point point = new Point(component.getControlPoint(i));
@@ -1096,7 +1093,7 @@ public class Presenter implements IPlugInPort {
.getClass()), false);
}
messageDispatcher.dispatchMessage(EventType.PROJECT_MODIFIED,
oldProject, cloner.deepClone(currentProject), "Add");
oldProject, currentProject.clone(), "Add");
projectFileManager.notifyFileChange();
updateSelection(new ArrayList<IDIYComponent<?>>(components));
messageDispatcher.dispatchMessage(EventType.REPAINT);
@@ -1109,7 +1106,7 @@ public class Presenter implements IPlugInPort {
LOG.debug("Nothing to delete");
return;
}
Project oldProject = cloner.deepClone(currentProject);
Project oldProject = currentProject.clone();
// Remove selected components from any groups.
ungroupComponents(selectedComponents);
// Remove from area map.
@@ -1118,7 +1115,7 @@ public class Presenter implements IPlugInPort {
}
currentProject.getComponents().removeAll(selectedComponents);
messageDispatcher.dispatchMessage(EventType.PROJECT_MODIFIED,
oldProject, cloner.deepClone(currentProject), "Delete");
oldProject, currentProject.clone(), "Delete");
projectFileManager.notifyFileChange();
updateSelection(EMPTY_SELECTION);
messageDispatcher.dispatchMessage(EventType.REPAINT);
@@ -1160,7 +1157,7 @@ public class Presenter implements IPlugInPort {
@Override
public void groupSelectedComponents() {
LOG.info("groupSelectedComponents()");
Project oldProject = cloner.deepClone(currentProject);
Project oldProject = currentProject.clone();
// First remove the selected components from other groups.
ungroupComponents(selectedComponents);
// Then group them together.
@@ -1170,7 +1167,7 @@ public class Presenter implements IPlugInPort {
messageDispatcher.dispatchMessage(EventType.REPAINT);
if (!oldProject.equals(currentProject)) {
messageDispatcher.dispatchMessage(EventType.PROJECT_MODIFIED,
oldProject, cloner.deepClone(currentProject), "Group");
oldProject, currentProject.clone(), "Group");
projectFileManager.notifyFileChange();
}
}
@@ -1178,13 +1175,13 @@ public class Presenter implements IPlugInPort {
@Override
public void ungroupSelectedComponents() {
LOG.info("ungroupSelectedComponents()");
Project oldProject = cloner.deepClone(currentProject);
Project oldProject = currentProject.clone();
ungroupComponents(selectedComponents);
// Notify the listeners.
messageDispatcher.dispatchMessage(EventType.REPAINT);
if (!oldProject.equals(currentProject)) {
messageDispatcher.dispatchMessage(EventType.PROJECT_MODIFIED,
oldProject, cloner.deepClone(currentProject), "Ungroup");
oldProject, currentProject.clone(), "Ungroup");
projectFileManager.notifyFileChange();
}
}
@@ -1206,7 +1203,7 @@ public class Presenter implements IPlugInPort {
@Override
public void sendSelectionToBack() {
LOG.info("sendSelectionToBack()");
Project oldProject = cloner.deepClone(currentProject);
Project oldProject = currentProject.clone();
for (IDIYComponent<?> component : selectedComponents) {
ComponentType componentType = ComponentProcessor.getInstance()
.extractComponentTypeFrom(
@@ -1235,7 +1232,7 @@ public class Presenter implements IPlugInPort {
}
if (!oldProject.equals(currentProject)) {
messageDispatcher.dispatchMessage(EventType.PROJECT_MODIFIED,
oldProject, cloner.deepClone(currentProject),
oldProject, currentProject.clone(),
"Send to Back");
projectFileManager.notifyFileChange();
messageDispatcher.dispatchMessage(EventType.REPAINT);
@@ -1245,7 +1242,7 @@ public class Presenter implements IPlugInPort {
@Override
public void bringSelectionToFront() {
LOG.info("bringSelectionToFront()");
Project oldProject = cloner.deepClone(currentProject);
Project oldProject = currentProject.clone();
for (IDIYComponent<?> component : selectedComponents) {
ComponentType componentType = ComponentProcessor.getInstance()
.extractComponentTypeFrom(
@@ -1274,7 +1271,7 @@ public class Presenter implements IPlugInPort {
}
if (!oldProject.equals(currentProject)) {
messageDispatcher.dispatchMessage(EventType.PROJECT_MODIFIED,
oldProject, cloner.deepClone(currentProject),
oldProject, currentProject.clone(),
"Bring to Front");
projectFileManager.notifyFileChange();
messageDispatcher.dispatchMessage(EventType.REPAINT);
@@ -1303,7 +1300,7 @@ public class Presenter implements IPlugInPort {
if (getSelectedComponents().isEmpty()) {
return;
}
Project oldProject = cloner.deepClone(currentProject);
Project oldProject = currentProject.clone();
List<IDIYComponent<?>> components = new ArrayList<IDIYComponent<?>>(
getSelectedComponents());
// Sort components by their location.
@@ -1369,7 +1366,7 @@ public class Presenter implements IPlugInPort {
}
messageDispatcher.dispatchMessage(EventType.PROJECT_MODIFIED,
oldProject, cloner.deepClone(currentProject),
oldProject, currentProject.clone(),
"Renumber selection");
projectFileManager.notifyFileChange();
messageDispatcher.dispatchMessage(EventType.REPAINT);
@@ -1593,7 +1590,7 @@ public class Presenter implements IPlugInPort {
private void applyPropertiesToSelection(List<PropertyWrapper> properties) {
LOG.debug(String.format("applyPropertiesToSelection(%s)", properties));
Project oldProject = cloner.deepClone(currentProject);
Project oldProject = currentProject.clone();
try {
for (IDIYComponent<?> component : selectedComponents) {
drawingManager.invalidateComponent(component);
@@ -1613,7 +1610,7 @@ public class Presenter implements IPlugInPort {
// Notify the listeners.
if (!oldProject.equals(currentProject)) {
messageDispatcher.dispatchMessage(EventType.PROJECT_MODIFIED,
oldProject, cloner.deepClone(currentProject),
oldProject, currentProject.clone(),
"Edit Selection");
projectFileManager.notifyFileChange();
}
@@ -1641,7 +1638,7 @@ public class Presenter implements IPlugInPort {
@Override
public void applyPropertiesToProject(List<PropertyWrapper> properties) {
LOG.debug(String.format("applyPropertiesToProject(%s)", properties));
Project oldProject = cloner.deepClone(currentProject);
Project oldProject = currentProject.clone();
try {
for (PropertyWrapper property : properties) {
property.writeTo(currentProject);
@@ -1656,7 +1653,7 @@ public class Presenter implements IPlugInPort {
// Notify the listeners.
if (!oldProject.equals(currentProject)) {
messageDispatcher.dispatchMessage(EventType.PROJECT_MODIFIED,
oldProject, cloner.deepClone(currentProject),
oldProject, currentProject.clone(),
"Edit Project");
projectFileManager.notifyFileChange();
}
@@ -19,7 +19,7 @@ import org.diylc.core.measures.Size;
import org.diylc.core.measures.SizeUnit;
@ComponentDescriptor(name = "Mock", author = "bancika", category = "Sample", instanceNamePrefix = "M", description = "test", zOrder = IDIYComponent.COMPONENT)
public class MockDIYComponent implements IDIYComponent<Capacitance> {
public class MockDIYComponent extends AbstractComponent<Capacitance> {
private static final long serialVersionUID = 1L;