001: /*
002: * Jacareto Copyright (c) 2002-2005
003: * Applied Computer Science Research Group, Darmstadt University of
004: * Technology, Institute of Mathematics & Computer Science,
005: * Ludwigsburg University of Education, and Computer Based
006: * Learning Research Group, Aachen University. All rights reserved.
007: *
008: * Jacareto is free software; you can redistribute it and/or
009: * modify it under the terms of the GNU General Public
010: * License as published by the Free Software Foundation; either
011: * version 2 of the License, or (at your option) any later version.
012: *
013: * Jacareto is distributed in the hope that it will be useful,
014: * but WITHOUT ANY WARRANTY; without even the implied warranty of
015: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
016: * General Public License for more details.
017: *
018: * You should have received a copy of the GNU General Public
019: * License along with Jacareto; if not, write to the Free
020: * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
021: *
022: */
023:
024: package jacareto.comp;
025:
026: import jacareto.record.ComponentPropertiesRecordable;
027: import jacareto.system.Environment;
028: import jacareto.system.EnvironmentMember;
029: import jacareto.toolkit.StringToolkit;
030:
031: import java.awt.Component;
032: import java.awt.event.ComponentEvent;
033:
034: import java.beans.PropertyChangeEvent;
035: import java.beans.PropertyChangeListener;
036:
037: import java.util.Enumeration;
038: import java.util.Hashtable;
039: import java.util.Vector;
040:
041: /**
042: * Class which watches components for changes and corrects wrong states.
043: *
044: * @author <a href="mailto:cspannagel@web.de">Christian Spannagel</a>
045: * @version 1.01
046: */
047: public class ComponentWatcher extends EnvironmentMember implements
048: PropertyChangeListener, java.awt.event.ComponentListener {
049: /** The hashtable which maps components to component properties recordables. */
050: private Hashtable componentToProperties;
051:
052: /** The components instance. */
053: private Components components;
054:
055: /** The thread which changes component states. */
056: private Thread t;
057:
058: /**
059: * Creates a new component listener.
060: *
061: * @param env the environment
062: * @param components the components instance
063: */
064: public ComponentWatcher(Environment env, Components components) {
065: super (env);
066: this .components = components;
067: componentToProperties = new Hashtable();
068: }
069:
070: /**
071: * Adds a component with a given enabled state to be watched.
072: *
073: * @param component the component
074: * @param properties the properties of the recordable (will be cloned)
075: */
076: public void addComponent(Component component,
077: ComponentPropertiesRecordable properties) {
078: boolean isAlreadyContained = componentToProperties
079: .containsKey(component);
080:
081: componentToProperties.put(component, properties.clone());
082:
083: if (!isAlreadyContained) {
084: component.addPropertyChangeListener(this );
085: component.addComponentListener(this );
086: }
087: }
088:
089: /**
090: * Removes a component.
091: *
092: * @param component the component to be removed.
093: */
094: public void removeComponent(Component component) {
095: if (componentToProperties.containsKey(component)) {
096: component.removePropertyChangeListener(this );
097: component.removeComponentListener(this );
098: componentToProperties.remove(component);
099: }
100: }
101:
102: /**
103: * Clears the component watcher.
104: */
105: public void clear() {
106: Enumeration keys = componentToProperties.keys();
107:
108: while (keys.hasMoreElements()) {
109: Component component = (Component) keys.nextElement();
110: component.removePropertyChangeListener(this );
111: component.removeComponentListener(this );
112: }
113:
114: componentToProperties.clear();
115: }
116:
117: /**
118: * Updates the watcher. If this instance watches a component which is not known by the
119: * components instance anymore, it will be removed.
120: */
121: public void update() {
122: Vector componentsToBeRemoved = new Vector(5, 5);
123:
124: // Get the components to be removed
125: Enumeration keys = componentToProperties.keys();
126:
127: while (keys.hasMoreElements()) {
128: Component component = (Component) keys.nextElement();
129:
130: if (!components.isKnown(component)) {
131: componentsToBeRemoved.add(component);
132: }
133: }
134:
135: for (int i = 0; i < componentsToBeRemoved.size(); i++) {
136: removeComponent((Component) componentsToBeRemoved.get(i));
137: }
138: }
139:
140: /**
141: * Called when a property of a component which is watched has been changed.
142: *
143: * @param evt the event
144: */
145: public void propertyChange(PropertyChangeEvent evt) {
146: String propertyName = evt.getPropertyName().toString();
147: Object source = evt.getSource();
148:
149: if (StringToolkit.areEqual(propertyName, "enabled")
150: && (source instanceof Component)) {
151: Component component = (Component) source;
152: ComponentPropertiesRecordable properties = (ComponentPropertiesRecordable) componentToProperties
153: .get(component);
154: boolean isEnabled = ((Boolean) evt.getNewValue())
155: .booleanValue();
156: boolean shouldBeEnabled = properties.getIsEnabled();
157:
158: if (properties.getApplyIsEnabled()
159: && (isEnabled != shouldBeEnabled)) {
160: t = new Thread(new ComponentStateChanger(component,
161: ComponentStateChanger.ENABLED, shouldBeEnabled));
162: t.start();
163: }
164: }
165:
166: if (StringToolkit.areEqual(propertyName, "visible")
167: && (source instanceof Component)) {
168: Component component = (Component) source;
169: ComponentPropertiesRecordable properties = (ComponentPropertiesRecordable) componentToProperties
170: .get(component);
171: boolean isVisible = ((Boolean) evt.getNewValue())
172: .booleanValue();
173: boolean shouldBeVisible = properties.getIsVisible();
174:
175: if (properties.getApplyIsVisible()
176: && (isVisible != shouldBeVisible)) {
177: t = new Thread(new ComponentStateChanger(component,
178: ComponentStateChanger.VISIBLE, shouldBeVisible));
179: t.start();
180: }
181: }
182: }
183:
184: /**
185: * Called when a component is hidden.
186: *
187: * @param event the event
188: */
189: public void componentHidden(ComponentEvent event) {
190: Component component = (Component) event.getSource();
191: ComponentPropertiesRecordable properties = (ComponentPropertiesRecordable) componentToProperties
192: .get(component);
193:
194: if (properties.getApplyIsVisible() && properties.getIsVisible()) {
195: t = new Thread(new ComponentStateChanger(component,
196: ComponentStateChanger.VISIBLE, true));
197: t.start();
198: }
199: }
200:
201: /**
202: * Called when a component is shown.
203: *
204: * @param event the event
205: */
206: public void componentShown(ComponentEvent event) {
207: Component component = (Component) event.getSource();
208: ComponentPropertiesRecordable properties = (ComponentPropertiesRecordable) componentToProperties
209: .get(component);
210:
211: if (properties.getApplyIsVisible()
212: && !properties.getIsVisible()) {
213: t = new Thread(new ComponentStateChanger(component,
214: ComponentStateChanger.VISIBLE, false));
215: t.start();
216: }
217: }
218:
219: public void componentMoved(ComponentEvent event) {
220: // do nothing
221: }
222:
223: public void componentResized(ComponentEvent event) {
224: // do nothing
225: }
226:
227: /**
228: * Class which corrects the state of the component
229: */
230: class ComponentStateChanger implements Runnable {
231: //~ Static fields/initializers -------------------------------------------------------------
232:
233: public static final int ENABLED = 0;
234: public static final int VISIBLE = 1;
235:
236: //~ Instance fields ------------------------------------------------------------------------
237:
238: private Component component;
239: private int type;
240: private boolean value;
241:
242: //~ Constructors ---------------------------------------------------------------------------
243:
244: public ComponentStateChanger(Component component, int type,
245: boolean value) {
246: this .component = component;
247: this .type = type;
248: this .value = value;
249: }
250:
251: //~ Methods --------------------------------------------------------------------------------
252:
253: public void run() {
254: // Thread should sleep a little while, because the property change must be performed before.
255: // Then the property change will be cancelled.
256: try {
257: Thread.sleep(50);
258: } catch (InterruptedException ioex) {
259: ;
260: }
261:
262: switch (type) {
263: case ENABLED:
264: component.setEnabled(value);
265:
266: break;
267:
268: case VISIBLE:
269: component.setVisible(value);
270:
271: break;
272: }
273: }
274: }
275: }
|