1 package net.sf.openrocket.gui.adaptors;
3 import java.awt.Component;
4 import java.awt.event.ActionEvent;
5 import java.lang.reflect.InvocationTargetException;
6 import java.lang.reflect.Method;
7 import java.util.ArrayList;
10 import javax.swing.AbstractAction;
11 import javax.swing.event.ChangeEvent;
12 import javax.swing.event.ChangeListener;
14 import net.sf.openrocket.util.ChangeSource;
18 * A class that adapts an isXXX/setXXX boolean variable. It functions as an Action suitable
19 * for usage in JCheckBox or JToggleButton. You can create a suitable button with
21 * check = new JCheckBox(new BooleanModel(component,"Value"))
22 * check.setText("Label");
24 * This will produce a button that uses isValue() and setValue(boolean) of the corresponding
27 * Additionally a number of component enabled states may be controlled by this class using
28 * the method {@link #addEnableComponent(Component, boolean)}.
30 * @author Sampo Niskanen <sampo.niskanen@iki.fi>
33 public class BooleanModel extends AbstractAction implements ChangeListener {
35 private final ChangeSource source;
36 private final String valueName;
38 private final Method getMethod;
39 private final Method setMethod;
40 private final Method getEnabled;
42 private final List<Component> components = new ArrayList<Component>();
43 private final List<Boolean> componentEnableState = new ArrayList<Boolean>();
45 private int firing = 0;
47 private boolean oldValue;
48 private boolean oldEnabled;
50 public BooleanModel(ChangeSource source, String valueName) {
52 this.valueName = valueName;
54 Method getter=null, setter=null;
59 getter = source.getClass().getMethod("is" + valueName);
60 } catch (NoSuchMethodException ignore) { }
63 getter = source.getClass().getMethod("get" + valueName);
64 } catch (NoSuchMethodException ignore) { }
67 setter = source.getClass().getMethod("set" + valueName,boolean.class);
68 } catch (NoSuchMethodException ignore) { }
70 if (getter==null || setter==null) {
71 throw new IllegalArgumentException("get/is methods for boolean '"+valueName+
72 "' not present in class "+source.getClass().getCanonicalName());
80 e = source.getClass().getMethod("is" + valueName + "Enabled");
81 } catch (NoSuchMethodException ignore) { }
84 oldValue = getValue();
85 oldEnabled = getIsEnabled();
87 this.setEnabled(oldEnabled);
88 this.putValue(SELECTED_KEY, oldValue);
90 source.addChangeListener(this);
93 public boolean getValue() {
95 return (Boolean)getMethod.invoke(source);
96 } catch (IllegalAccessException e) {
97 throw new RuntimeException("getMethod execution error for source "+source,e);
98 } catch (InvocationTargetException e) {
99 throw new RuntimeException("getMethod execution error for source "+source,e);
103 public void setValue(boolean b) {
105 setMethod.invoke(source, new Object[] { (Boolean)b });
106 } catch (IllegalAccessException e) {
107 throw new RuntimeException("setMethod execution error for source "+source,e);
108 } catch (InvocationTargetException e) {
109 throw new RuntimeException("setMethod execution error for source "+source,e);
115 * Add a component the enabled status of which will be controlled by the value
116 * of this boolean. The <code>component</code> will be enabled exactly when
117 * the state of this model is equal to that of <code>enableState</code>.
119 * @param component the component to control.
120 * @param enableState the state in which the component should be enabled.
122 public void addEnableComponent(Component component, boolean enableState) {
123 components.add(component);
124 componentEnableState.add(enableState);
125 updateEnableStatus();
129 * Add a component which will be enabled when this boolean is <code>true</code>.
130 * This is equivalent to <code>booleanModel.addEnableComponent(component, true)</code>.
132 * @param component the component to control.
133 * @see #addEnableComponent(Component, boolean)
135 public void addEnableComponent(Component component) {
136 addEnableComponent(component, true);
139 private void updateEnableStatus() {
140 boolean state = getValue();
142 for (int i=0; i < components.size(); i++) {
143 Component c = components.get(i);
144 boolean b = componentEnableState.get(i);
145 c.setEnabled(state == b);
151 // public boolean isEnabled() {
152 // if (getEnabled == null)
155 // return (Boolean)getEnabled.invoke(source);
156 // } catch (IllegalAccessException e) {
157 // throw new RuntimeException("getEnabled execution error for source "+source,e);
158 // } catch (InvocationTargetException e) {
159 // throw new RuntimeException("getEnabled execution error for source "+source,e);
164 private boolean getIsEnabled() {
165 if (getEnabled == null)
168 return (Boolean)getEnabled.invoke(source);
169 } catch (IllegalAccessException e) {
170 throw new RuntimeException("getEnabled execution error for source "+source,e);
171 } catch (InvocationTargetException e) {
172 throw new RuntimeException("getEnabled execution error for source "+source,e);
177 // public Object getValue(String key) {
178 // if (key.equals(SELECTED_KEY)) {
179 // return getValue();
181 // return super.getValue(key);
185 // public void putValue(String key, Object value) {
186 // if (firing > 0) // Ignore if currently firing event
188 // if (key.equals(SELECTED_KEY) && (value instanceof Boolean)) {
189 // setValue((Boolean)value);
191 // super.putValue(key, value);
193 // updateEnableStatus();
198 public void stateChanged(ChangeEvent event) {
202 boolean v = getValue();
203 boolean e = getIsEnabled();
207 this.putValue(SELECTED_KEY, getValue());
208 // this.firePropertyChange(SELECTED_KEY, !v, v);
209 updateEnableStatus();
212 if (oldEnabled != e) {
220 public void actionPerformed(ActionEvent e) {
224 boolean v = (Boolean)this.getValue(SELECTED_KEY);
228 oldValue = getValue();
230 this.putValue(SELECTED_KEY, oldValue);
231 this.setEnabled(getIsEnabled());
232 updateEnableStatus();
238 public String toString() {
239 return "BooleanModel["+source.getClass().getCanonicalName()+":"+valueName+"]";