diff --git a/diylc/diylc-core/src/org/diylc/common/PropertyWrapper.java b/diylc/diylc-core/src/org/diylc/common/PropertyWrapper.java index e5faf898..999f221c 100644 --- a/diylc/diylc-core/src/org/diylc/common/PropertyWrapper.java +++ b/diylc/diylc-core/src/org/diylc/common/PropertyWrapper.java @@ -75,12 +75,19 @@ public class PropertyWrapper implements Cloneable { // } public void writeTo(Object object) throws IllegalArgumentException, IllegalAccessException, - InvocationTargetException, SecurityException, NoSuchMethodException { + InvocationTargetException, SecurityException, NoSuchMethodException { + // nothing to do if no setter + if (setter == null) + return; object.getClass().getMethod(setter, type).invoke(object, this.value); } public Method getGetter() throws SecurityException, NoSuchMethodException { return getOwnerObject().getClass().getMethod(getter); + } + + public boolean isReadOnly() { + return setter == null; } public String getName() { diff --git a/diylc/diylc-core/src/org/diylc/components/AbstractCurvedComponent.java b/diylc/diylc-core/src/org/diylc/components/AbstractCurvedComponent.java index 9d60ddee..8b48a42a 100644 --- a/diylc/diylc-core/src/org/diylc/components/AbstractCurvedComponent.java +++ b/diylc/diylc-core/src/org/diylc/components/AbstractCurvedComponent.java @@ -24,7 +24,10 @@ import java.awt.Graphics2D; import java.awt.Point; import java.awt.geom.CubicCurve2D; import java.awt.geom.Path2D; +import java.awt.geom.Point2D; +import org.diylc.appframework.miscutils.ConfigurationManager; +import org.diylc.common.IPlugInPort; import org.diylc.common.LineStyle; import org.diylc.common.ObjectCache; import org.diylc.core.ComponentState; @@ -299,7 +302,7 @@ public abstract class AbstractCurvedComponent extends AbstractTransparentComp public void setStyle(LineStyle style) { this.style = style; - } + } @EditableProperty public Boolean getSmooth() { @@ -321,6 +324,32 @@ public abstract class AbstractCurvedComponent extends AbstractTransparentComp // } // } } + + @EditableProperty + public Size getLength() { + double d = 0; + Point[] p = getControlPoints(); + if (getPointCount() == PointCount.TWO) { + d = p[0].distance(p[1]); + } else if (getPointCount() == PointCount.THREE) { + d = calculateLength(p[0], p[1], p[1], p[2]); + } else if (getPointCount() == PointCount.FOUR) { + d = calculateLength(p[0], p[1], p[2], p[3]); + } else if (getPointCount() == PointCount.FIVE) { + d = calculateLength(p[0], p[1], p[2]) + calculateLength(p[2], p[3], p[4]); + } else if (getPointCount() == PointCount.SEVEN) { + d = calculateLength(p[0], p[1], p[2], p[3]) + calculateLength(p[3], p[4], p[5], p[6]); + } + + SizeUnit unit; + if (ConfigurationManager.getInstance().readBoolean(IPlugInPort.METRIC_KEY, true)) + unit = SizeUnit.mm; + else + unit = SizeUnit.in; + + d = d * SizeUnit.px.getFactor() / unit.getFactor(); + return new Size(d, unit); + } public enum PointCount { TWO(2), THREE(3), FOUR(4), FIVE(5), SEVEN(7); @@ -336,4 +365,44 @@ public abstract class AbstractCurvedComponent extends AbstractTransparentComp return name().substring(0, 1) + name().substring(1).toLowerCase(); } } + + // calculate length of quad curve + private double calculateLength(Point2D a, Point2D b, Point2D c) { + double vx = 2 * (b.getX() - a.getX()); + double vy = 2 * (b.getY() - a.getY()); + double wx = c.getX() - 2 * b.getX() + a.getX(); + double wy = c.getY() - 2 * b.getY() + a.getY(); + + double uu = 4 * (wx * wx + wy * wy); + + if (uu < 0.00001) { + return (float) Math.sqrt((c.getX() - a.getX()) * (c.getX() - a.getX()) + (c.getY() - a.getY()) * (c.getY() - a.getY())); + } + + double vv = 4 * (vx * wx + vy * wy); + double ww = vx * vx + vy * vy; + + double t1 = (float) (2 * Math.sqrt(uu * (uu + vv + ww))); + double t2 = 2 * uu + vv; + double t3 = vv * vv - 4 * uu * ww; + double t4 = (float) (2 * Math.sqrt(uu * ww)); + + return (float) ((t1 * t2 - t3 * Math.log(t2 + t1) - (vv * t4 - t3 * Math.log(vv + t4))) + / (8 * Math.pow(uu, 1.5))); + } + + private double curveThreshold = 10; + + // approximately calculate length of Bezier curves by subdivision + private double calculateLength(Point2D a, Point2D b, Point2D c, Point2D d) { + double distance = a.distance(d); + if (distance < curveThreshold) + return distance; + CubicCurve2D curve = new CubicCurve2D.Double(a.getX(), a.getY(), b.getX(), b.getY(), c.getX(), c.getY(), d.getX(), d.getY()); + CubicCurve2D left = new CubicCurve2D.Double(); + CubicCurve2D right = new CubicCurve2D.Double(); + curve.subdivide(left, right); + return calculateLength(left.getP1(), left.getCtrlP1(), left.getCtrlP2(), left.getP2()) + + calculateLength(right.getP1(), right.getCtrlP1(), right.getCtrlP2(), right.getP2()); + } } diff --git a/diylc/diylc-core/src/org/diylc/core/measures/AbstractMeasure.java b/diylc/diylc-core/src/org/diylc/core/measures/AbstractMeasure.java index 8b1153c5..2a599e0e 100644 --- a/diylc/diylc-core/src/org/diylc/core/measures/AbstractMeasure.java +++ b/diylc/diylc-core/src/org/diylc/core/measures/AbstractMeasure.java @@ -41,9 +41,6 @@ public class AbstractMeasure> implements Serializ protected Double value; protected T unit; - // public AbstractMeasure() { - // } - public AbstractMeasure(Double value, T unit) { super(); this.value = value; @@ -54,23 +51,19 @@ public class AbstractMeasure> implements Serializ return value; } - // public void setValue(Double value) { - // this.value = value; - // } - public T getUnit() { return unit; + } + + /*** + * Flag that designates if measure value should be converted between different units. eg. 2.54mm <-> 0.1in + * + * @return + */ + public boolean isConvertible() { + return false; } - // public void setUnit(T multiplier) { - // this.unit = multiplier; - // } - - // @Override - // public Object clone() throws CloneNotSupportedException { - // return super.clone(); - // } - @Override public int hashCode() { final int prime = 31; diff --git a/diylc/diylc-core/src/org/diylc/core/measures/Size.java b/diylc/diylc-core/src/org/diylc/core/measures/Size.java index 378f64b0..7536e291 100644 --- a/diylc/diylc-core/src/org/diylc/core/measures/Size.java +++ b/diylc/diylc-core/src/org/diylc/core/measures/Size.java @@ -65,5 +65,10 @@ public class Size extends AbstractMeasure implements Comparable @Override public int compareTo(Size o) { return new Double(value * unit.getFactor()).compareTo(o.getValue() * o.getUnit().getFactor()); + } + + @Override + public boolean isConvertible() { + return true; } } diff --git a/diylc/diylc-core/src/org/diylc/presenter/ComparatorFactory.java b/diylc/diylc-core/src/org/diylc/presenter/ComparatorFactory.java index e5326b8f..fa823733 100644 --- a/diylc/diylc-core/src/org/diylc/presenter/ComparatorFactory.java +++ b/diylc/diylc-core/src/org/diylc/presenter/ComparatorFactory.java @@ -98,7 +98,11 @@ public class ComparatorFactory { propertyNameComparator = new Comparator() { @Override - public int compare(PropertyWrapper o1, PropertyWrapper o2) { + public int compare(PropertyWrapper o1, PropertyWrapper o2) { + if (o1.isReadOnly() && !o2.isReadOnly()) + return 1; + if (!o1.isReadOnly() && o2.isReadOnly()) + return -1; int comp = new Integer(o1.getSortOrder()).compareTo(o2.getSortOrder()); if (comp != 0) return comp; diff --git a/diylc/diylc-core/src/org/diylc/presenter/ComponentProcessor.java b/diylc/diylc-core/src/org/diylc/presenter/ComponentProcessor.java index 61250022..6726c576 100644 --- a/diylc/diylc-core/src/org/diylc/presenter/ComponentProcessor.java +++ b/diylc/diylc-core/src/org/diylc/presenter/ComponentProcessor.java @@ -151,7 +151,7 @@ public class ComponentProcessor { List properties = new ArrayList(); for (Method getter : clazz.getMethods()) { if (getter.getName().startsWith("get")) { - try { + if (getter.isAnnotationPresent(EditableProperty.class) && !getter.isAnnotationPresent(Deprecated.class) // since Java 8 in generic classes we get properties of both the generic type and Object // added this condition to skip Object property that we do not need @@ -163,16 +163,20 @@ public class ComponentProcessor { } else { name = annotation.name(); } - IPropertyValidator validator = getPropertyValidator(annotation.validatorClass()); - Method setter = clazz.getMethod("set" + getter.getName().substring(3), getter.getReturnType()); + IPropertyValidator validator = getPropertyValidator(annotation.validatorClass()); + + String setterName = null; + try { + Method setter = clazz.getMethod("set" + getter.getName().substring(3), getter.getReturnType()); + setterName = setter.getName(); + } catch (NoSuchMethodException e) { + LOG.debug("No matching setter found for \"" + getter.getName() + "\". Skipping..."); + } PropertyWrapper property = - new PropertyWrapper(name, getter.getReturnType(), getter.getName(), setter.getName(), + new PropertyWrapper(name, getter.getReturnType(), getter.getName(), setterName, annotation.defaultable(), validator, annotation.sortOrder()); properties.add(property); - } - } catch (NoSuchMethodException e) { - LOG.debug("No matching setter found for \"" + getter.getName() + "\". Skipping..."); - } + } } } diff --git a/diylc/diylc-core/src/org/diylc/presenter/update.xml b/diylc/diylc-core/src/org/diylc/presenter/update.xml index 9c860d4d..33e85ecf 100644 --- a/diylc/diylc-core/src/org/diylc/presenter/update.xml +++ b/diylc/diylc-core/src/org/diylc/presenter/update.xml @@ -2726,6 +2726,10 @@ NEW_FEATURE Added ability to collapse and expand the component tree panel to the left edge of the screen + + NEW_FEATURE + Added read-only "Length" property to curved components (i.e. "Hookup Wire") that calculates total length of the curve + NEW_FEATURE Added "Renumber On Paste" option in the "Config" menu diff --git a/diylc/diylc-library/lib/diylc-core.jar b/diylc/diylc-library/lib/diylc-core.jar index bd67c822..e341f4bc 100644 Binary files a/diylc/diylc-library/lib/diylc-core.jar and b/diylc/diylc-library/lib/diylc-core.jar differ diff --git a/diylc/diylc-swing/build.xml b/diylc/diylc-swing/build.xml index dda18738..087f2a67 100644 --- a/diylc/diylc-swing/build.xml +++ b/diylc/diylc-swing/build.xml @@ -134,6 +134,9 @@ + + + @@ -144,11 +147,12 @@ - + + - + diff --git a/diylc/diylc-swing/icons/diylc.png b/diylc/diylc-swing/icons/diylc.png deleted file mode 100644 index 500a419e..00000000 Binary files a/diylc/diylc-swing/icons/diylc.png and /dev/null differ diff --git a/diylc/diylc-swing/lib/diylc-core.jar b/diylc/diylc-swing/lib/diylc-core.jar index bd67c822..e341f4bc 100644 Binary files a/diylc/diylc-swing/lib/diylc-core.jar and b/diylc/diylc-swing/lib/diylc-core.jar differ diff --git a/diylc/diylc-swing/library/main.jar b/diylc/diylc-swing/library/main.jar index 5bfde7a9..413e7255 100644 Binary files a/diylc/diylc-swing/library/main.jar and b/diylc/diylc-swing/library/main.jar differ diff --git a/diylc/diylc-swing/src/org/diylc/swing/gui/editor/BooleanEditor.java b/diylc/diylc-swing/src/org/diylc/swing/gui/editor/BooleanEditor.java index 01bb8cdf..42daad09 100644 --- a/diylc/diylc-swing/src/org/diylc/swing/gui/editor/BooleanEditor.java +++ b/diylc/diylc-swing/src/org/diylc/swing/gui/editor/BooleanEditor.java @@ -38,7 +38,9 @@ public class BooleanEditor extends JCheckBox { public BooleanEditor(final PropertyWrapper property) { super(); - setSelected((Boolean) property.getValue()); + setSelected((Boolean) property.getValue()); + if (property.isReadOnly()) + setEnabled(false); addActionListener(new ActionListener() { @Override diff --git a/diylc/diylc-swing/src/org/diylc/swing/gui/editor/ByteEditor.java b/diylc/diylc-swing/src/org/diylc/swing/gui/editor/ByteEditor.java index 0f200a50..edda1a22 100644 --- a/diylc/diylc-swing/src/org/diylc/swing/gui/editor/ByteEditor.java +++ b/diylc/diylc-swing/src/org/diylc/swing/gui/editor/ByteEditor.java @@ -63,7 +63,12 @@ public class ByteEditor extends JPanel { } final JSlider slider = new JSlider(); - final DoubleTextField valueField = new DoubleTextField(); + final DoubleTextField valueField = new DoubleTextField(); + + if (property.isReadOnly()) { + slider.setEnabled(false); + valueField.setEnabled(false); + } final double percentFactor = (double) default100Percent / _100PercentValue; diff --git a/diylc/diylc-swing/src/org/diylc/swing/gui/editor/ColorEditor.java b/diylc/diylc-swing/src/org/diylc/swing/gui/editor/ColorEditor.java index 9b107bf7..523ae599 100644 --- a/diylc/diylc-swing/src/org/diylc/swing/gui/editor/ColorEditor.java +++ b/diylc/diylc-swing/src/org/diylc/swing/gui/editor/ColorEditor.java @@ -72,7 +72,12 @@ public class ColorEditor extends JPanel { gbc.gridx++; gbc.insets = new Insets(0, 0, 0, 0); - add(getColorField(), gbc); + add(getColorField(), gbc); + + if (property.isReadOnly()) { + getColorField().setEnabled(false); + getColorLabel().setEnabled(false); + } } public JLabel getColorLabel() { diff --git a/diylc/diylc-swing/src/org/diylc/swing/gui/editor/EnumEditor.java b/diylc/diylc-swing/src/org/diylc/swing/gui/editor/EnumEditor.java index a7906ce4..d5dec1c7 100644 --- a/diylc/diylc-swing/src/org/diylc/swing/gui/editor/EnumEditor.java +++ b/diylc/diylc-swing/src/org/diylc/swing/gui/editor/EnumEditor.java @@ -41,7 +41,9 @@ public class EnumEditor extends JComboBox { public EnumEditor(final PropertyWrapper property) { this.property = property; - Object[] values = property.getType().getEnumConstants(); + Object[] values = property.getType().getEnumConstants(); + if (property.isReadOnly()) + setEnabled(false); setModel(new DefaultComboBoxModel(values)); setSelectedItem(property.getValue()); addItemListener(new ItemListener() { diff --git a/diylc/diylc-swing/src/org/diylc/swing/gui/editor/FontEditor.java b/diylc/diylc-swing/src/org/diylc/swing/gui/editor/FontEditor.java index 5ac4c894..37195844 100644 --- a/diylc/diylc-swing/src/org/diylc/swing/gui/editor/FontEditor.java +++ b/diylc/diylc-swing/src/org/diylc/swing/gui/editor/FontEditor.java @@ -42,7 +42,9 @@ public class FontEditor extends FontChooserComboBox { private final PropertyWrapper property; public FontEditor(final PropertyWrapper property) { - this.property = property; + this.property = property; + if (property.isReadOnly()) + setEnabled(false); ((JTextField) getEditor().getEditorComponent()).setBorder(BorderFactory.createCompoundBorder( ((JTextField) getEditor().getEditorComponent()).getBorder(), BorderFactory.createEmptyBorder(0, 2, 0, 0))); setSelectedItem(((Font) property.getValue()).getName()); diff --git a/diylc/diylc-swing/src/org/diylc/swing/gui/editor/ImageEditor.java b/diylc/diylc-swing/src/org/diylc/swing/gui/editor/ImageEditor.java index 49635646..40569b5f 100644 --- a/diylc/diylc-swing/src/org/diylc/swing/gui/editor/ImageEditor.java +++ b/diylc/diylc-swing/src/org/diylc/swing/gui/editor/ImageEditor.java @@ -41,7 +41,9 @@ public class ImageEditor extends JButton { private static final String title = "Click to load image file"; public ImageEditor(final PropertyWrapper property) { - super(property.isUnique() ? title : ("(multi value) " + title)); + super(property.isUnique() ? title : ("(multi value) " + title)); + if (property.isReadOnly()) + setEnabled(false); addActionListener(new ActionListener() { @Override diff --git a/diylc/diylc-swing/src/org/diylc/swing/gui/editor/IntEditor.java b/diylc/diylc-swing/src/org/diylc/swing/gui/editor/IntEditor.java index 8030a166..1345c84d 100644 --- a/diylc/diylc-swing/src/org/diylc/swing/gui/editor/IntEditor.java +++ b/diylc/diylc-swing/src/org/diylc/swing/gui/editor/IntEditor.java @@ -37,7 +37,9 @@ public class IntEditor extends DoubleTextField { private Color oldBg = getBackground(); public IntEditor(final PropertyWrapper property) { - setLayout(new BorderLayout()); + setLayout(new BorderLayout()); + if (property.isReadOnly()) + setEnabled(false); setValue((double) (Integer) property.getValue()); addPropertyChangeListener(DoubleTextField.VALUE_PROPERTY, new PropertyChangeListener() { diff --git a/diylc/diylc-swing/src/org/diylc/swing/gui/editor/MeasureArrayEditor.java b/diylc/diylc-swing/src/org/diylc/swing/gui/editor/MeasureArrayEditor.java index f7ea5e87..19979797 100644 --- a/diylc/diylc-swing/src/org/diylc/swing/gui/editor/MeasureArrayEditor.java +++ b/diylc/diylc-swing/src/org/diylc/swing/gui/editor/MeasureArrayEditor.java @@ -63,6 +63,8 @@ public class MeasureArrayEditor extends Container { values[i] = measure[i] == null ? null : measure[i].getValue(); } valueField = new DoubleArrayTextField(measure == null ? null : values); + if (property.isReadOnly()) + valueField.setEnabled(false); oldBg = valueField.getBackground(); valueField.addPropertyChangeListener( DoubleArrayTextField.VALUE_PROPERTY, diff --git a/diylc/diylc-swing/src/org/diylc/swing/gui/editor/MeasureEditor.java b/diylc/diylc-swing/src/org/diylc/swing/gui/editor/MeasureEditor.java index d98c2531..97d07b3e 100644 --- a/diylc/diylc-swing/src/org/diylc/swing/gui/editor/MeasureEditor.java +++ b/diylc/diylc-swing/src/org/diylc/swing/gui/editor/MeasureEditor.java @@ -56,7 +56,7 @@ public class MeasureEditor extends Container { @SuppressWarnings("unchecked") public MeasureEditor(final PropertyWrapper property) { setLayout(new BorderLayout()); - final AbstractMeasure measure = ((AbstractMeasure) property.getValue()); + final AbstractMeasure measure = ((AbstractMeasure) property.getValue()); valueField = new DoubleTextField(measure == null ? null : measure.getValue()); oldBg = valueField.getBackground(); valueField.addPropertyChangeListener(DoubleTextField.VALUE_PROPERTY, new PropertyChangeListener() { @@ -87,9 +87,16 @@ public class MeasureEditor extends Container { @Override public void actionPerformed(ActionEvent evt) { try { - Constructor ctor = property.getType().getConstructors()[0]; + Constructor ctor = property.getType().getConstructors()[0]; + Double newValue = valueField.getValue(); + if (newValue != null && property.isReadOnly() && measure.isConvertible()) { + double oldFactor = ((Unit)((AbstractMeasure)property.getValue()).getUnit()).getFactor(); + double newFactor = ((Unit)unitBox.getSelectedItem()).getFactor(); + newValue = newValue * oldFactor / newFactor; + valueField.setValue(newValue); + } AbstractMeasure newMeasure = - (AbstractMeasure) ctor.newInstance(valueField.getValue(), + (AbstractMeasure) ctor.newInstance(newValue, (Enum) unitBox.getSelectedItem()); property.setValue(newMeasure); property.setChanged(true); @@ -100,7 +107,12 @@ public class MeasureEditor extends Container { } } }); - add(unitBox, BorderLayout.EAST); + add(unitBox, BorderLayout.EAST); + + if (property.isReadOnly()) { + valueField.setEnabled(false); + unitBox.setEnabled(measure.isConvertible()); + } if (!property.isUnique()) { valueField.setBackground(Constants.MULTI_VALUE_COLOR); diff --git a/diylc/diylc-swing/src/org/diylc/swing/gui/editor/MultiLineStringEditor.java b/diylc/diylc-swing/src/org/diylc/swing/gui/editor/MultiLineStringEditor.java index 918f3ee8..24b1f9dd 100644 --- a/diylc/diylc-swing/src/org/diylc/swing/gui/editor/MultiLineStringEditor.java +++ b/diylc/diylc-swing/src/org/diylc/swing/gui/editor/MultiLineStringEditor.java @@ -50,7 +50,9 @@ public class MultiLineStringEditor extends JScrollPane { public MultiLineStringEditor(PropertyWrapper property) { super(); this.property = property; - setViewportView(getTextArea()); + setViewportView(getTextArea()); + if (property.isReadOnly()) + getTextArea().setEnabled(false); setPreferredSize(new Dimension(192, 64)); setBorder(border); } diff --git a/diylc/diylc-swing/src/org/diylc/swing/gui/editor/PropertyEditorDialog.java b/diylc/diylc-swing/src/org/diylc/swing/gui/editor/PropertyEditorDialog.java index 4fd5a83e..6da46f9d 100644 --- a/diylc/diylc-swing/src/org/diylc/swing/gui/editor/PropertyEditorDialog.java +++ b/diylc/diylc-swing/src/org/diylc/swing/gui/editor/PropertyEditorDialog.java @@ -134,7 +134,7 @@ public class PropertyEditorDialog extends ButtonDialog { gbc.fill = GridBagConstraints.NONE; gbc.weightx = 0; - if (saveDefaults) { + if (saveDefaults && !property.isReadOnly()) { editorPanel.add(createDefaultCheckBox(property), gbc); } } diff --git a/diylc/diylc-swing/src/org/diylc/swing/gui/editor/StringEditor.java b/diylc/diylc-swing/src/org/diylc/swing/gui/editor/StringEditor.java index cb57c03b..1aee281c 100644 --- a/diylc/diylc-swing/src/org/diylc/swing/gui/editor/StringEditor.java +++ b/diylc/diylc-swing/src/org/diylc/swing/gui/editor/StringEditor.java @@ -40,7 +40,9 @@ public class StringEditor extends JTextField { public StringEditor(PropertyWrapper property) { super(property.getValue() == null ? "" : (String) property.getValue()); - this.property = property; + this.property = property; + if (property.isReadOnly()) + setEnabled(false); this.setColumns(32); getDocument().addDocumentListener(new DocumentListener() { diff --git a/diylc/diylc-swing/src/org/diylc/swing/gui/editor/StringListEditor.java b/diylc/diylc-swing/src/org/diylc/swing/gui/editor/StringListEditor.java index c8581f12..d3be56c7 100644 --- a/diylc/diylc-swing/src/org/diylc/swing/gui/editor/StringListEditor.java +++ b/diylc/diylc-swing/src/org/diylc/swing/gui/editor/StringListEditor.java @@ -42,7 +42,9 @@ public class StringListEditor extends JComboBox { private final PropertyWrapper property; public StringListEditor(final PropertyWrapper property) throws Exception { - this.property = property; + this.property = property; + if (property.isReadOnly()) + setEnabled(false); String listFunctionName = property.getGetter().getAnnotation(DynamicList.class).availableValueFunction(); Method function = property.getOwnerObject().getClass().getMethod(listFunctionName); Object[] values = (Object[]) function.invoke(property.getOwnerObject());