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.logging.LogHelper;
15 import net.sf.openrocket.startup.Application;
16 import net.sf.openrocket.util.BugException;
17 import net.sf.openrocket.util.ChangeSource;
18 import net.sf.openrocket.util.Reflection;
22 * A class that adapts an isXXX/setXXX boolean variable. It functions as an Action suitable
23 * for usage in JCheckBox or JToggleButton. You can create a suitable button with
25 * check = new JCheckBox(new BooleanModel(component,"Value"))
26 * check.setText("Label");
28 * This will produce a button that uses isValue() and setValue(boolean) of the corresponding
31 * Additionally a number of component enabled states may be controlled by this class using
32 * the method {@link #addEnableComponent(Component, boolean)}.
34 * @author Sampo Niskanen <sampo.niskanen@iki.fi>
37 public class BooleanModel extends AbstractAction implements ChangeListener {
38 private static final LogHelper log = Application.getLogger();
40 private final ChangeSource source;
41 private final String valueName;
43 private final Method getMethod;
44 private final Method setMethod;
45 private final Method getEnabled;
47 private final List<Component> components = new ArrayList<Component>();
48 private final List<Boolean> componentEnableState = new ArrayList<Boolean>();
50 private String toString = null;
52 private int firing = 0;
54 private boolean oldValue;
55 private boolean oldEnabled;
57 public BooleanModel(ChangeSource source, String valueName) {
59 this.valueName = valueName;
61 Method getter = null, setter = null;
66 getter = source.getClass().getMethod("is" + valueName);
67 } catch (NoSuchMethodException ignore) {
71 getter = source.getClass().getMethod("get" + valueName);
72 } catch (NoSuchMethodException ignore) {
76 setter = source.getClass().getMethod("set" + valueName, boolean.class);
77 } catch (NoSuchMethodException ignore) {
80 if (getter == null || setter == null) {
81 throw new IllegalArgumentException("get/is methods for boolean '" + valueName +
82 "' not present in class " + source.getClass().getCanonicalName());
90 e = source.getClass().getMethod("is" + valueName + "Enabled");
91 } catch (NoSuchMethodException ignore) {
95 oldValue = getValue();
96 oldEnabled = getIsEnabled();
98 this.setEnabled(oldEnabled);
99 this.putValue(SELECTED_KEY, oldValue);
101 source.addChangeListener(this);
104 public boolean getValue() {
106 return (Boolean) getMethod.invoke(source);
107 } catch (IllegalAccessException e) {
108 throw new BugException("getMethod execution error for source " + source, e);
109 } catch (InvocationTargetException e) {
110 throw Reflection.handleWrappedException(e);
114 public void setValue(boolean b) {
115 log.debug("Setting value of " + this + " to " + b);
117 setMethod.invoke(source, new Object[] { (Boolean) b });
118 } catch (IllegalAccessException e) {
119 throw new BugException("setMethod execution error for source " + source, e);
120 } catch (InvocationTargetException e) {
121 throw Reflection.handleWrappedException(e);
127 * Add a component the enabled status of which will be controlled by the value
128 * of this boolean. The <code>component</code> will be enabled exactly when
129 * the state of this model is equal to that of <code>enableState</code>.
131 * @param component the component to control.
132 * @param enableState the state in which the component should be enabled.
134 public void addEnableComponent(Component component, boolean enableState) {
135 components.add(component);
136 componentEnableState.add(enableState);
137 updateEnableStatus();
141 * Add a component which will be enabled when this boolean is <code>true</code>.
142 * This is equivalent to <code>booleanModel.addEnableComponent(component, true)</code>.
144 * @param component the component to control.
145 * @see #addEnableComponent(Component, boolean)
147 public void addEnableComponent(Component component) {
148 addEnableComponent(component, true);
151 private void updateEnableStatus() {
152 boolean state = getValue();
154 for (int i = 0; i < components.size(); i++) {
155 Component c = components.get(i);
156 boolean b = componentEnableState.get(i);
157 c.setEnabled(state == b);
163 private boolean getIsEnabled() {
164 if (getEnabled == null)
167 return (Boolean) getEnabled.invoke(source);
168 } catch (IllegalAccessException e) {
169 throw new BugException("getEnabled execution error for source " + source, e);
170 } catch (InvocationTargetException e) {
171 throw Reflection.handleWrappedException(e);
176 public void stateChanged(ChangeEvent event) {
178 log.debug("Ignoring stateChanged of " + this + ", currently firing events");
182 boolean v = getValue();
183 boolean e = getIsEnabled();
185 log.debug("Value of " + this + " has changed to " + v + " oldValue=" + oldValue);
188 this.putValue(SELECTED_KEY, getValue());
189 // this.firePropertyChange(SELECTED_KEY, !v, v);
190 updateEnableStatus();
193 if (oldEnabled != e) {
194 log.debug("Enabled status of " + this + " has changed to " + e + " oldEnabled=" + oldEnabled);
202 public void actionPerformed(ActionEvent e) {
204 log.debug("Ignoring actionPerformed of " + this + ", currently firing events");
208 boolean v = (Boolean) this.getValue(SELECTED_KEY);
209 log.user("Value of " + this + " changed to " + v + " oldValue=" + oldValue);
213 oldValue = getValue();
215 this.putValue(SELECTED_KEY, oldValue);
216 this.setEnabled(getIsEnabled());
217 updateEnableStatus();
223 public String toString() {
224 if (toString == null) {
225 toString = "BooleanModel[" + source.getClass().getSimpleName() + ":" + valueName + "]";