X-Git-Url: https://git.gag.com/?a=blobdiff_plain;f=core%2Fsrc%2Fnet%2Fsf%2Fopenrocket%2Fgui%2Fadaptors%2FDoubleModel.java;h=3216f0a7d7bf7d36f6c995b2b346736e0752cd8a;hb=refs%2Fheads%2Fupstream;hp=820a54a66c4508d3f9f67ac3afd79c50106bb42c;hpb=8654c7d5a9d56274a296500d40c7f74229cdf6f1;p=debian%2Fopenrocket diff --git a/core/src/net/sf/openrocket/gui/adaptors/DoubleModel.java b/core/src/net/sf/openrocket/gui/adaptors/DoubleModel.java index 820a54a6..3216f0a7 100644 --- a/core/src/net/sf/openrocket/gui/adaptors/DoubleModel.java +++ b/core/src/net/sf/openrocket/gui/adaptors/DoubleModel.java @@ -10,10 +10,10 @@ import java.util.EventListener; import java.util.EventObject; import javax.swing.AbstractAction; +import javax.swing.AbstractSpinnerModel; import javax.swing.Action; import javax.swing.BoundedRangeModel; import javax.swing.SpinnerModel; -import javax.swing.SpinnerNumberModel; import javax.swing.event.ChangeEvent; import javax.swing.event.ChangeListener; @@ -23,6 +23,8 @@ import net.sf.openrocket.unit.Unit; import net.sf.openrocket.unit.UnitGroup; import net.sf.openrocket.util.BugException; import net.sf.openrocket.util.ChangeSource; +import net.sf.openrocket.util.ExpressionParser; +import net.sf.openrocket.util.InvalidExpressionException; import net.sf.openrocket.util.Invalidatable; import net.sf.openrocket.util.Invalidator; import net.sf.openrocket.util.MathUtil; @@ -48,20 +50,25 @@ import net.sf.openrocket.util.StateChangeListener; public class DoubleModel implements StateChangeListener, ChangeSource, Invalidatable { private static final LogHelper log = Application.getLogger(); - + public static final DoubleModel ZERO = new DoubleModel(0); //////////// JSpinner Model //////////// /** - * Model suitable for JSpinner using JSpinner.NumberEditor. It extends SpinnerNumberModel + * Model suitable for JSpinner. + * Note: Previously used using JSpinner.NumberEditor and extended SpinnerNumberModel * to be compatible with the NumberEditor, but only has the necessary methods defined. + * This is still the design, but now extends AbstractSpinnerModel to allow other characters + * to be entered so that fractional units and expressions can be used. */ - private class ValueSpinnerModel extends SpinnerNumberModel implements Invalidatable { + public class ValueSpinnerModel extends AbstractSpinnerModel implements Invalidatable { + + private ExpressionParser parser = new ExpressionParser(); @Override public Object getValue() { - return currentUnit.toUnit(DoubleModel.this.getValue()); + return currentUnit.toString(DoubleModel.this.getValue()); } @Override @@ -72,14 +79,41 @@ public class DoubleModel implements StateChangeListener, ChangeSource, Invalidat " value=" + value + ", currently firing events"); return; } - Number num = (Number) value; - double newValue = num.doubleValue(); - double converted = currentUnit.fromUnit(newValue); - log.user("SpinnerModel setValue called for " + DoubleModel.this.toString() + " newValue=" + newValue + - " converted=" + converted); - DoubleModel.this.setValue(converted); + Number num = Double.NaN; + + // Set num if possible + if (value instanceof Number) { + num = (Number) value; + } + else if (value instanceof String) { + try { + String newValString = (String) value; + num = parser.parse(newValString); + } catch (InvalidExpressionException e) { + // Ignore + } + } + // Update the doublemodel with the new number or return to the last number if not possible + if (((Double) num).isNaN()) { + DoubleModel.this.setValue(lastValue); + log.user("SpinnerModel could not set value for " + DoubleModel.this.toString() + ". Could not convert " + value.toString()); + } + else { + double newValue = num.doubleValue(); + double converted = currentUnit.fromUnit(newValue); + + log.user("SpinnerModel setValue called for " + DoubleModel.this.toString() + " newValue=" + newValue + + " converted=" + converted); + DoubleModel.this.setValue(converted); + } + + // Force a refresh if text doesn't match up exactly with the stored value + if (!((Double) lastValue).toString().equals(this.getValue().toString())) { + DoubleModel.this.fireStateChanged(); + log.debug("SpinnerModel " + DoubleModel.this.toString() + " refresh forced because string did not match actual value."); + } } @Override @@ -106,18 +140,6 @@ public class DoubleModel implements StateChangeListener, ChangeSource, Invalidat return d; } - - @Override - public Comparable getMinimum() { - return currentUnit.toUnit(minValue); - } - - @Override - public Comparable getMaximum() { - return currentUnit.toUnit(maxValue); - } - - @Override public void addChangeListener(ChangeListener l) { DoubleModel.this.addChangeListener(l); @@ -144,10 +166,6 @@ public class DoubleModel implements StateChangeListener, ChangeSource, Invalidat return new ValueSpinnerModel(); } - - - - //////////// JSlider model //////////// private class ValueSliderModel implements BoundedRangeModel, StateChangeListener, Invalidatable { @@ -157,7 +175,8 @@ public class DoubleModel implements StateChangeListener, ChangeSource, Invalidat * Use linear scale value = linear1 * x + linear0 when x < linearPosition * Use quadratic scale value = quad2 * x^2 + quad1 * x + quad0 otherwise */ - + private final boolean islinear; + // Linear in range x <= linearPosition private final double linearPosition; @@ -169,11 +188,10 @@ public class DoubleModel implements StateChangeListener, ChangeSource, Invalidat //private final double linear0; // Non-linear multiplier, exponent and constant - private final double quad2, quad1, quad0; + private double quad2, quad1, quad0; - - public ValueSliderModel(DoubleModel min, DoubleModel max) { + this.islinear = true; linearPosition = 1.0; this.min = min; @@ -187,11 +205,12 @@ public class DoubleModel implements StateChangeListener, ChangeSource, Invalidat } - + /** * Generate a linear model from min to max. */ public ValueSliderModel(double min, double max) { + this.islinear = true; linearPosition = 1.0; this.min = new DoubleModel(min); @@ -205,6 +224,10 @@ public class DoubleModel implements StateChangeListener, ChangeSource, Invalidat this(min, 0.5, mid, max); } + public ValueSliderModel(double min, double mid, DoubleModel max) { + this(min, 0.5, mid, max); + } + /* * v(x) = mul * x^exp + add * @@ -213,32 +236,46 @@ public class DoubleModel implements StateChangeListener, ChangeSource, Invalidat * v'(pos) = mul*exp * pos^(exp-1) = linearMul */ public ValueSliderModel(double min, double pos, double mid, double max) { + this(min, pos, mid, new DoubleModel(max)); + } + + public ValueSliderModel(double min, double pos, double mid, DoubleModel max) { this.min = new DoubleModel(min); this.mid = new DoubleModel(mid); - this.max = new DoubleModel(max); + this.max = max; + + this.islinear = false; + + max.addChangeListener(this); - linearPosition = pos; //linear0 = min; //linear1 = (mid-min)/pos; - if (!(min < mid && mid <= max && 0 < pos && pos < 1)) { + if (!(min < mid && mid <= max.getValue() && 0 < pos && pos < 1)) { throw new IllegalArgumentException("Bad arguments for ValueSliderModel " + "min=" + min + " mid=" + mid + " max=" + max + " pos=" + pos); } + updateExponentialParameters(); + + } + + private void updateExponentialParameters() { + double pos = this.linearPosition; + double minValue = this.min.getValue(); + double midValue = this.mid.getValue(); + double maxValue = this.max.getValue(); /* * quad2..0 are calculated such that * f(pos) = mid - continuity * f(1) = max - end point * f'(pos) = linear1 - continuity of derivative */ - - double delta = (mid - min) / pos; - quad2 = (max - mid - delta + delta * pos) / pow2(pos - 1); - quad1 = (delta + 2 * (mid - max) * pos - delta * pos * pos) / pow2(pos - 1); - quad0 = (mid - (2 * mid + delta) * pos + (max + delta) * pos * pos) / pow2(pos - 1); - + double delta = (midValue - minValue) / pos; + quad2 = (maxValue - midValue - delta + delta * pos) / pow2(pos - 1); + quad1 = (delta + 2 * (midValue - maxValue) * pos - delta * pos * pos) / pow2(pos - 1); + quad0 = (midValue - (2 * midValue + delta) * pos + (maxValue + delta) * pos * pos) / pow2(pos - 1); } private double pow2(double x) { @@ -366,6 +403,11 @@ public class DoubleModel implements StateChangeListener, ChangeSource, Invalidat @Override public void stateChanged(EventObject e) { // Min or max range has changed. + if (!islinear) { + double midValue = (max.getValue() - min.getValue()) / 3.0; + mid.setValue(midValue); + updateExponentialParameters(); + } // Fire if not already firing if (firing == 0) fireStateChanged(); @@ -385,14 +427,18 @@ public class DoubleModel implements StateChangeListener, ChangeSource, Invalidat return new ValueSliderModel(min, mid, max); } + public BoundedRangeModel getSliderModel(double min, double mid, DoubleModel max) { + return new ValueSliderModel(min, mid, max); + } + public BoundedRangeModel getSliderModel(double min, double pos, double mid, double max) { return new ValueSliderModel(min, pos, mid, max); } - - - + + + //////////// Action model //////////// private class AutomaticActionModel extends AbstractAction implements StateChangeListener, Invalidatable { @@ -491,15 +537,15 @@ public class DoubleModel implements StateChangeListener, ChangeSource, Invalidat } - - - + + + //////////// Main model ///////////// /* * The main model handles all values in SI units, i.e. no conversion is made within the model. */ - + private final ChangeSource source; private final String valueName; private final double multiplier; @@ -516,14 +562,14 @@ public class DoubleModel implements StateChangeListener, ChangeSource, Invalidat private Unit currentUnit; private final double minValue; - private final double maxValue; + private double maxValue; private String toString = null; - + private int firing = 0; // >0 when model itself is sending events - + // Used to differentiate changes in valueName and other changes in the component: private double lastValue = 0; private boolean lastAutomatic = false; @@ -677,7 +723,7 @@ public class DoubleModel implements StateChangeListener, ChangeSource, Invalidat } - + /** * Returns the value of the variable (in SI units). */ @@ -725,7 +771,6 @@ public class DoubleModel implements StateChangeListener, ChangeSource, Invalidat } } - /** * Returns whether setting the value automatically is available. */ @@ -811,7 +856,7 @@ public class DoubleModel implements StateChangeListener, ChangeSource, Invalidat } - + /** * Add a listener to the model. Adds the model as a listener to the value source if this * is the first listener. @@ -897,10 +942,10 @@ public class DoubleModel implements StateChangeListener, ChangeSource, Invalidat // Copy the list before iterating to prevent concurrent modification exceptions. EventListener[] ls = listeners.toArray(new EventListener[0]); for (EventListener l : ls) { - if ( l instanceof StateChangeListener ) { - ((StateChangeListener)l).stateChanged(event); - } else if ( l instanceof ChangeListener ) { - ((ChangeListener)l).stateChanged(cevent); + if (l instanceof StateChangeListener) { + ((StateChangeListener) l).stateChanged(event); + } else if (l instanceof ChangeListener) { + ((ChangeListener) l).stateChanged(cevent); } } firing--;