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.ChangeSource;
15 public class IntegerModel implements ChangeListener {
18 //////////// JSpinner Model ////////////
20 private class IntegerSpinnerModel extends SpinnerNumberModel {
22 public Object getValue() {
23 return IntegerModel.this.getValue();
27 public void setValue(Object value) {
28 if (firing > 0) // Ignore, if called when model is sending events
30 Number num = (Number)value;
31 int newValue = num.intValue();
32 IntegerModel.this.setValue(newValue);
35 // int newValue = Integer.parseInt((String)value);
36 // IntegerModel.this.setValue(newValue);
37 // } catch (NumberFormatException e) {
38 // IntegerModel.this.fireStateChanged();
43 public Object getNextValue() {
44 int d = IntegerModel.this.getValue();
51 public Object getPreviousValue() {
52 int d = IntegerModel.this.getValue();
59 public void addChangeListener(ChangeListener l) {
60 IntegerModel.this.addChangeListener(l);
64 public void removeChangeListener(ChangeListener l) {
65 IntegerModel.this.removeChangeListener(l);
70 * Returns a new SpinnerModel with the same base as the DoubleModel.
71 * The values given to the JSpinner are in the currently selected units.
73 * @return A compatibility layer for a SpinnerModel.
75 public SpinnerModel getSpinnerModel() {
76 return new IntegerSpinnerModel();
82 //////////// Main model /////////////
85 * The main model handles all values in SI units, i.e. no conversion is made within the model.
88 private final ChangeSource source;
89 private final String valueName;
91 private final Method getMethod;
92 private final Method setMethod;
94 private final ArrayList<ChangeListener> listeners = new ArrayList<ChangeListener>();
96 private final int minValue;
97 private final int maxValue;
100 private int firing = 0; // >0 when model itself is sending events
103 // Used to differentiate changes in valueName and other changes in the source:
104 private int lastValue = 0;
109 * Generates a new DoubleModel that changes the values of the specified source.
110 * The double value is read and written using the methods "get"/"set" + valueName.
112 * @param source Component whose parameter to use.
113 * @param valueName Name of metods used to get/set the parameter.
114 * @param multiplier Value shown by the model is the value from source.getXXX * multiplier
115 * @param min Minimum value allowed (in SI units)
116 * @param max Maximum value allowed (in SI units)
118 public IntegerModel(ChangeSource source, String valueName, int min, int max) {
119 this.source = source;
120 this.valueName = valueName;
126 getMethod = source.getClass().getMethod("get" + valueName);
127 setMethod = source.getClass().getMethod("set" + valueName,int.class);
128 } catch (NoSuchMethodException e) {
129 throw new IllegalArgumentException("get/set methods for value '"+valueName+
130 "' not present in class "+source.getClass().getCanonicalName());
134 public IntegerModel(ChangeSource source, String valueName, int min) {
135 this(source,valueName,min,Integer.MAX_VALUE);
138 public IntegerModel(ChangeSource source, String valueName) {
139 this(source,valueName,Integer.MIN_VALUE,Integer.MAX_VALUE);
146 * Returns the value of the variable.
148 public int getValue() {
150 return (Integer)getMethod.invoke(source);
151 } catch (IllegalArgumentException e) {
153 } catch (IllegalAccessException e) {
155 } catch (InvocationTargetException e) {
158 return lastValue; // Should not occur
162 * Sets the value of the variable.
164 public void setValue(int v) {
166 setMethod.invoke(source, v);
168 } catch (IllegalArgumentException e) {
170 } catch (IllegalAccessException e) {
172 } catch (InvocationTargetException e) {
175 fireStateChanged(); // Should not occur
180 * Add a listener to the model. Adds the model as a listener to the Component if this
181 * is the first listener.
182 * @param l Listener to add.
184 public void addChangeListener(ChangeListener l) {
185 if (listeners.isEmpty()) {
186 source.addChangeListener(this);
187 lastValue = getValue();
194 * Remove a listener from the model. Removes the model from being a listener to the Component
195 * if this was the last listener of the model.
196 * @param l Listener to remove.
198 public void removeChangeListener(ChangeListener l) {
200 if (listeners.isEmpty()) {
201 source.removeChangeListener(this);
205 public void fireStateChanged() {
206 Object[] l = listeners.toArray();
207 ChangeEvent event = new ChangeEvent(this);
209 for (int i=0; i<l.length; i++)
210 ((ChangeListener)l[i]).stateChanged(event);
215 * Called when the source changes. Checks whether the modeled value has changed, and if
216 * it has, updates lastValue and generates ChangeEvents for all listeners of the model.
218 public void stateChanged(ChangeEvent e) {
227 * Explain the DoubleModel as a String.
230 public String toString() {
231 return "IntegerModel["+source.getClass().getCanonicalName()+":"+valueName+"]";