001: /*
002: Launch4j (http://launch4j.sourceforge.net/)
003: Cross-platform Java application wrapper for creating Windows native executables.
004:
005: Copyright (c) 2004, 2007 Grzegorz Kowal
006:
007: All rights reserved.
008:
009: Redistribution and use in source and binary forms, with or without modification,
010: are permitted provided that the following conditions are met:
011:
012: * Redistributions of source code must retain the above copyright notice,
013: this list of conditions and the following disclaimer.
014: * Redistributions in binary form must reproduce the above copyright notice,
015: this list of conditions and the following disclaimer in the documentation
016: and/or other materials provided with the distribution.
017: * Neither the name of the Launch4j nor the names of its contributors
018: may be used to endorse or promote products derived from this software without
019: specific prior written permission.
020:
021: THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
022: "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
023: LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
024: A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
025: CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
026: EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
027: PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
028: PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
029: LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
030: NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
031: SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
032: */
033:
034: /*
035: * Created on Apr 30, 2005
036: */
037: package net.sf.launch4j.binding;
038:
039: import java.beans.PropertyChangeEvent;
040: import java.beans.PropertyChangeListener;
041: import java.util.HashMap;
042: import java.util.Iterator;
043: import java.util.Map;
044:
045: import javax.swing.JComboBox;
046: import javax.swing.JComponent;
047: import javax.swing.JList;
048: import javax.swing.JRadioButton;
049: import javax.swing.JTextArea;
050: import javax.swing.JToggleButton;
051: import javax.swing.text.JTextComponent;
052:
053: import org.apache.commons.beanutils.PropertyUtils;
054:
055: /**
056: * Creates and handles bindings.
057: *
058: * @author Copyright (C) 2005 Grzegorz Kowal
059: */
060: public class Bindings implements PropertyChangeListener {
061: private final Map _bindings = new HashMap();
062: private final Map _optComponents = new HashMap();
063: private boolean _modified = false;
064:
065: /**
066: * Used to track component modifications.
067: */
068: public void propertyChange(PropertyChangeEvent evt) {
069: String prop = evt.getPropertyName();
070: if ("AccessibleValue".equals(prop)
071: || "AccessibleText".equals(prop)
072: || "AccessibleVisibleData".equals(prop)) {
073: _modified = true;
074: }
075: }
076:
077: /**
078: * Any of the components modified?
079: */
080: public boolean isModified() {
081: return _modified;
082: }
083:
084: public Binding getBinding(String property) {
085: return (Binding) _bindings.get(property);
086: }
087:
088: private void registerPropertyChangeListener(JComponent c) {
089: c.getAccessibleContext().addPropertyChangeListener(this );
090: }
091:
092: private void registerPropertyChangeListener(JComponent[] cs) {
093: for (int i = 0; i < cs.length; i++) {
094: cs[i].getAccessibleContext()
095: .addPropertyChangeListener(this );
096: }
097: }
098:
099: private boolean isPropertyNull(IValidatable bean, Binding b) {
100: try {
101: for (Iterator iter = _optComponents.keySet().iterator(); iter
102: .hasNext();) {
103: String property = (String) iter.next();
104: if (b.getProperty().startsWith(property)) {
105: return PropertyUtils.getProperty(bean, property) == null;
106: }
107: }
108: return false;
109: } catch (Exception e) {
110: throw new BindingException(e);
111: }
112: }
113:
114: /**
115: * Enables or disables all components bound to properties that begin with given prefix.
116: */
117: public void setComponentsEnabled(String prefix, boolean enabled) {
118: for (Iterator iter = _bindings.values().iterator(); iter
119: .hasNext();) {
120: Binding b = (Binding) iter.next();
121: if (b.getProperty().startsWith(prefix)) {
122: b.setEnabled(enabled);
123: }
124: }
125: }
126:
127: /**
128: * Clear all components, set them to their default values.
129: * Clears the _modified flag.
130: */
131: public void clear(IValidatable bean) {
132: for (Iterator iter = _optComponents.values().iterator(); iter
133: .hasNext();) {
134: ((Binding) iter.next()).clear(bean);
135: }
136: for (Iterator iter = _bindings.values().iterator(); iter
137: .hasNext();) {
138: ((Binding) iter.next()).clear(bean);
139: }
140: _modified = false;
141: }
142:
143: /**
144: * Copies data from the Java Bean to the UI components.
145: * Clears the _modified flag.
146: */
147: public void put(IValidatable bean) {
148: for (Iterator iter = _optComponents.values().iterator(); iter
149: .hasNext();) {
150: ((Binding) iter.next()).put(bean);
151: }
152: for (Iterator iter = _bindings.values().iterator(); iter
153: .hasNext();) {
154: Binding b = (Binding) iter.next();
155: if (isPropertyNull(bean, b)) {
156: b.clear(null);
157: } else {
158: b.put(bean);
159: }
160: }
161: _modified = false;
162: }
163:
164: /**
165: * Copies data from UI components to the Java Bean and checks it's class invariants.
166: * Clears the _modified flag.
167: * @throws InvariantViolationException
168: * @throws BindingException
169: */
170: public void get(IValidatable bean) {
171: try {
172: for (Iterator iter = _optComponents.values().iterator(); iter
173: .hasNext();) {
174: ((Binding) iter.next()).get(bean);
175: }
176: for (Iterator iter = _bindings.values().iterator(); iter
177: .hasNext();) {
178: Binding b = (Binding) iter.next();
179: if (!isPropertyNull(bean, b)) {
180: b.get(bean);
181: }
182: }
183: bean.checkInvariants();
184: for (Iterator iter = _optComponents.keySet().iterator(); iter
185: .hasNext();) {
186: String property = (String) iter.next();
187: IValidatable component = (IValidatable) PropertyUtils
188: .getProperty(bean, property);
189: if (component != null) {
190: component.checkInvariants();
191: }
192: }
193: _modified = false; // XXX
194: } catch (InvariantViolationException e) {
195: e.setBinding(getBinding(e.getProperty()));
196: throw e;
197: } catch (Exception e) {
198: throw new BindingException(e);
199: }
200: }
201:
202: private Bindings add(Binding b) {
203: if (_bindings.containsKey(b.getProperty())) {
204: throw new BindingException(Messages
205: .getString("Bindings.duplicate.binding"));
206: }
207: _bindings.put(b.getProperty(), b);
208: return this ;
209: }
210:
211: /**
212: * Add an optional (nullable) Java Bean component of type clazz.
213: */
214: public Bindings addOptComponent(String property, Class clazz,
215: JToggleButton c, boolean enabledByDefault) {
216: Binding b = new OptComponentBinding(this , property, clazz, c,
217: enabledByDefault);
218: if (_optComponents.containsKey(property)) {
219: throw new BindingException(Messages
220: .getString("Bindings.duplicate.binding"));
221: }
222: _optComponents.put(property, b);
223: return this ;
224: }
225:
226: /**
227: * Add an optional (nullable) Java Bean component of type clazz.
228: */
229: public Bindings addOptComponent(String property, Class clazz,
230: JToggleButton c) {
231: return addOptComponent(property, clazz, c, false);
232: }
233:
234: /**
235: * Handles JEditorPane, JTextArea, JTextField
236: */
237: public Bindings add(String property, JTextComponent c,
238: String defaultValue) {
239: registerPropertyChangeListener(c);
240: return add(new JTextComponentBinding(property, c, defaultValue));
241: }
242:
243: /**
244: * Handles JEditorPane, JTextArea, JTextField
245: */
246: public Bindings add(String property, JTextComponent c) {
247: registerPropertyChangeListener(c);
248: return add(new JTextComponentBinding(property, c, ""));
249: }
250:
251: /**
252: * Handles JToggleButton, JCheckBox
253: */
254: public Bindings add(String property, JToggleButton c,
255: boolean defaultValue) {
256: registerPropertyChangeListener(c);
257: return add(new JToggleButtonBinding(property, c, defaultValue));
258: }
259:
260: /**
261: * Handles JToggleButton, JCheckBox
262: */
263: public Bindings add(String property, JToggleButton c) {
264: registerPropertyChangeListener(c);
265: return add(new JToggleButtonBinding(property, c, false));
266: }
267:
268: /**
269: * Handles JRadioButton
270: */
271: public Bindings add(String property, JRadioButton[] cs,
272: int defaultValue) {
273: registerPropertyChangeListener(cs);
274: return add(new JRadioButtonBinding(property, cs, defaultValue));
275: }
276:
277: /**
278: * Handles JRadioButton
279: */
280: public Bindings add(String property, JRadioButton[] cs) {
281: registerPropertyChangeListener(cs);
282: return add(new JRadioButtonBinding(property, cs, 0));
283: }
284:
285: /**
286: * Handles JTextArea
287: */
288: public Bindings add(String property, JTextArea textArea,
289: String defaultValue) {
290: registerPropertyChangeListener(textArea);
291: return add(new JTextComponentBinding(property, textArea,
292: defaultValue));
293: }
294:
295: /**
296: * Handles JTextArea lists
297: */
298: public Bindings add(String property, JTextArea textArea) {
299: registerPropertyChangeListener(textArea);
300: return add(new JTextAreaBinding(property, textArea));
301: }
302:
303: /**
304: * Handles Optional JTextArea lists
305: */
306: public Bindings add(String property, String stateProperty,
307: JToggleButton button, JTextArea textArea) {
308: registerPropertyChangeListener(button);
309: registerPropertyChangeListener(textArea);
310: return add(new OptJTextAreaBinding(property, stateProperty,
311: button, textArea));
312: }
313:
314: /**
315: * Handles JList
316: */
317: public Bindings add(String property, JList list) {
318: registerPropertyChangeListener(list);
319: return add(new JListBinding(property, list));
320: }
321:
322: /**
323: * Handles JComboBox
324: */
325: public Bindings add(String property, JComboBox combo,
326: int defaultValue) {
327: registerPropertyChangeListener(combo);
328: return add(new JComboBoxBinding(property, combo, defaultValue));
329: }
330:
331: /**
332: * Handles JComboBox
333: */
334: public Bindings add(String property, JComboBox combo) {
335: registerPropertyChangeListener(combo);
336: return add(new JComboBoxBinding(property, combo, 0));
337: }
338: }
|