1 package net.sf.openrocket.gui.adaptors;
3 import java.lang.reflect.InvocationTargetException;
4 import java.lang.reflect.Method;
5 import java.util.ArrayList;
7 import javax.swing.SpinnerModel;
8 import javax.swing.SpinnerNumberModel;
9 import javax.swing.event.ChangeEvent;
10 import javax.swing.event.ChangeListener;
12 import net.sf.openrocket.util.BugException;
13 import net.sf.openrocket.util.ChangeSource;
14 import net.sf.openrocket.util.Reflection;
17 public class IntegerModel implements ChangeListener {
20 //////////// JSpinner Model ////////////
22 private class IntegerSpinnerModel extends SpinnerNumberModel {
24 public Object getValue() {
25 return IntegerModel.this.getValue();
29 public void setValue(Object value) {
30 if (firing > 0) // Ignore, if called when model is sending events
32 Number num = (Number)value;
33 int newValue = num.intValue();
34 IntegerModel.this.setValue(newValue);
37 // int newValue = Integer.parseInt((String)value);
38 // IntegerModel.this.setValue(newValue);
39 // } catch (NumberFormatException e) {
40 // IntegerModel.this.fireStateChanged();
45 public Object getNextValue() {
46 int d = IntegerModel.this.getValue();
53 public Object getPreviousValue() {
54 int d = IntegerModel.this.getValue();
61 public void addChangeListener(ChangeListener l) {
62 IntegerModel.this.addChangeListener(l);
66 public void removeChangeListener(ChangeListener l) {
67 IntegerModel.this.removeChangeListener(l);
72 * Returns a new SpinnerModel with the same base as the DoubleModel.
73 * The values given to the JSpinner are in the currently selected units.
75 * @return A compatibility layer for a SpinnerModel.
77 public SpinnerModel getSpinnerModel() {
78 return new IntegerSpinnerModel();
84 //////////// Main model /////////////
87 * The main model handles all values in SI units, i.e. no conversion is made within the model.
90 private final ChangeSource source;
91 private final String valueName;
93 private final Method getMethod;
94 private final Method setMethod;
96 private final ArrayList<ChangeListener> listeners = new ArrayList<ChangeListener>();
98 private final int minValue;
99 private final int maxValue;
102 private int firing = 0; // >0 when model itself is sending events
105 // Used to differentiate changes in valueName and other changes in the source:
106 private int lastValue = 0;
111 * Generates a new DoubleModel that changes the values of the specified source.
112 * The double value is read and written using the methods "get"/"set" + valueName.
114 * @param source Component whose parameter to use.
115 * @param valueName Name of metods used to get/set the parameter.
116 * @param multiplier Value shown by the model is the value from source.getXXX * multiplier
117 * @param min Minimum value allowed (in SI units)
118 * @param max Maximum value allowed (in SI units)
120 public IntegerModel(ChangeSource source, String valueName, int min, int max) {
121 this.source = source;
122 this.valueName = valueName;
128 getMethod = source.getClass().getMethod("get" + valueName);
129 setMethod = source.getClass().getMethod("set" + valueName,int.class);
130 } catch (NoSuchMethodException e) {
131 throw new IllegalArgumentException("get/set methods for value '"+valueName+
132 "' not present in class "+source.getClass().getCanonicalName());
136 public IntegerModel(ChangeSource source, String valueName, int min) {
137 this(source,valueName,min,Integer.MAX_VALUE);
140 public IntegerModel(ChangeSource source, String valueName) {
141 this(source,valueName,Integer.MIN_VALUE,Integer.MAX_VALUE);
148 * Returns the value of the variable.
150 public int getValue() {
152 return (Integer)getMethod.invoke(source);
153 } catch (IllegalArgumentException e) {
154 throw new BugException(e);
155 } catch (IllegalAccessException e) {
156 throw new BugException(e);
157 } catch (InvocationTargetException e) {
158 throw Reflection.handleWrappedException(e);
163 * Sets the value of the variable.
165 public void setValue(int v) {
167 setMethod.invoke(source, v);
168 } catch (IllegalArgumentException e) {
169 throw new BugException(e);
170 } catch (IllegalAccessException e) {
171 throw new BugException(e);
172 } catch (InvocationTargetException e) {
173 throw Reflection.handleWrappedException(e);
179 * Add a listener to the model. Adds the model as a listener to the Component if this
180 * is the first listener.
181 * @param l Listener to add.
183 public void addChangeListener(ChangeListener l) {
184 if (listeners.isEmpty()) {
185 source.addChangeListener(this);
186 lastValue = getValue();
193 * Remove a listener from the model. Removes the model from being a listener to the Component
194 * if this was the last listener of the model.
195 * @param l Listener to remove.
197 public void removeChangeListener(ChangeListener l) {
199 if (listeners.isEmpty()) {
200 source.removeChangeListener(this);
204 public void fireStateChanged() {
205 Object[] l = listeners.toArray();
206 ChangeEvent event = new ChangeEvent(this);
208 for (int i=0; i<l.length; i++)
209 ((ChangeListener)l[i]).stateChanged(event);
214 * Called when the source changes. Checks whether the modeled value has changed, and if
215 * it has, updates lastValue and generates ChangeEvents for all listeners of the model.
217 public void stateChanged(ChangeEvent e) {
226 * Explain the DoubleModel as a String.
229 public String toString() {
230 return "IntegerModel["+source.getClass().getCanonicalName()+":"+valueName+"]";