001: /*
002: * Copyright (c) 2004 JETA Software, Inc. All rights reserved.
003: *
004: * Redistribution and use in source and binary forms, with or without modification,
005: * are permitted provided that the following conditions are met:
006: *
007: * o Redistributions of source code must retain the above copyright notice,
008: * this list of conditions and the following disclaimer.
009: *
010: * o Redistributions in binary form must reproduce the above copyright notice,
011: * this list of conditions and the following disclaimer in the documentation
012: * and/or other materials provided with the distribution.
013: *
014: * o Neither the name of JETA Software nor the names of its contributors may
015: * be used to endorse or promote products derived from this software without
016: * specific prior written permission.
017: *
018: * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
019: * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
020: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
021: * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
022: * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
023: * INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
024: * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
025: * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
026: * INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
027: * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
028: */
029:
030: package com.jeta.forms.gui.beans;
031:
032: import java.util.HashMap;
033: import java.util.Iterator;
034: import java.util.LinkedHashMap;
035:
036: import javax.swing.JComponent;
037: import javax.swing.JLabel;
038:
039: import com.jeta.forms.components.border.TitledBorderBottom;
040: import com.jeta.forms.components.border.TitledBorderLabel;
041: import com.jeta.forms.components.border.TitledBorderSide;
042: import com.jeta.forms.components.image.ImageComponent;
043: import com.jeta.forms.components.label.JETALabel;
044: import com.jeta.forms.components.line.HorizontalLineComponent;
045: import com.jeta.forms.components.line.VerticalLineComponent;
046: import com.jeta.forms.components.separator.TitledSeparator;
047: import com.jeta.forms.gui.beans.factories.BeanFactory;
048: import com.jeta.forms.gui.beans.factories.ButtonBeanFactory;
049: import com.jeta.forms.gui.beans.factories.CheckBoxBeanFactory;
050: import com.jeta.forms.gui.beans.factories.ComboBoxBeanFactory;
051: import com.jeta.forms.gui.beans.factories.EditorPaneFactory;
052: import com.jeta.forms.gui.beans.factories.FormattedTextFieldFactory;
053: import com.jeta.forms.gui.beans.factories.GridViewBeanFactory;
054: import com.jeta.forms.gui.beans.factories.HorizontalLineComponentFactory;
055: import com.jeta.forms.gui.beans.factories.ImageBeanFactory;
056: import com.jeta.forms.gui.beans.factories.JComponentBeanFactory;
057: import com.jeta.forms.gui.beans.factories.LabelBeanFactory;
058: import com.jeta.forms.gui.beans.factories.ListBeanFactory;
059: import com.jeta.forms.gui.beans.factories.PasswordFieldBeanFactory;
060: import com.jeta.forms.gui.beans.factories.ProgressBarFactory;
061: import com.jeta.forms.gui.beans.factories.RadioButtonBeanFactory;
062: import com.jeta.forms.gui.beans.factories.SliderFactory;
063: import com.jeta.forms.gui.beans.factories.TabbedPaneFactory;
064: import com.jeta.forms.gui.beans.factories.TableBeanFactory;
065: import com.jeta.forms.gui.beans.factories.TextAreaBeanFactory;
066: import com.jeta.forms.gui.beans.factories.TextFieldBeanFactory;
067: import com.jeta.forms.gui.beans.factories.TitledBorderBottomFactory;
068: import com.jeta.forms.gui.beans.factories.TitledBorderLabelFactory;
069: import com.jeta.forms.gui.beans.factories.TitledBorderSideFactory;
070: import com.jeta.forms.gui.beans.factories.TitledSeparatorFactory;
071: import com.jeta.forms.gui.beans.factories.ToggleButtonFactory;
072: import com.jeta.forms.gui.beans.factories.TreeFactory;
073: import com.jeta.forms.gui.beans.factories.VerticalLineComponentFactory;
074: import com.jeta.forms.gui.common.FormException;
075: import com.jeta.forms.gui.form.GridView;
076: import com.jeta.forms.logger.FormsLogger;
077:
078: /**
079: * This is a factory for creating a JETABean wrapper for a given Swing component
080: * and its associated custom properties. We need this because we want to support
081: * dynamic properties for Swing components. For example, we would like to have a
082: * buttonGroup property for JRadioButtons. This is easier for the user than
083: * having to programmatically manage ButtonGroups. The buttonGroup property will
084: * handle this for the design and runtime systems. Each Swing component can have
085: * different dynamic properties. For example, tabbed panes have tabs while JList
086: * and JTables have scrollBar properties. So, we use this factory to properly
087: * initialize a JETABean for a given Swing component.
088: *
089: * @author Jeff Tassin
090: */
091: public class JETABeanFactory {
092: /**
093: * m_factories<String,BeanFactory> A map of component class names and their
094: * associated BeanFactories This is for standard Swing Components such as
095: * JList, JButton, JLabel, etc.
096: */
097: private static LinkedHashMap m_factories = new LinkedHashMap();
098:
099: /**
100: * m_custom_factories<String,BeanFactory> A map of component class names
101: * and their associated BeanFactories. This is for custom, imported Java
102: * Beans. If those beans extend one of the standard swing components, then
103: * we want to use that factory when creating the JETABean and its custom
104: * properties.
105: */
106: private static HashMap m_custom_factories = new HashMap();
107:
108: static {
109: /** standard swing components */
110: registerFactory("javax.swing.JButton", new ButtonBeanFactory());
111: registerFactory("javax.swing.JToggleButton",
112: new ToggleButtonFactory());
113: registerFactory("javax.swing.JCheckBox",
114: new CheckBoxBeanFactory());
115: registerFactory("javax.swing.JComboBox",
116: new ComboBoxBeanFactory());
117: registerFactory("javax.swing.JList", new ListBeanFactory());
118: registerFactory("javax.swing.JRadioButton",
119: new RadioButtonBeanFactory());
120: registerFactory("javax.swing.JTextField",
121: new TextFieldBeanFactory());
122: registerFactory("javax.swing.JPasswordField",
123: new PasswordFieldBeanFactory());
124: registerFactory("javax.swing.JTextArea",
125: new TextAreaBeanFactory());
126: registerFactory("javax.swing.JTable", new TableBeanFactory());
127: registerFactory("javax.swing.JProgressBar",
128: new ProgressBarFactory());
129: registerFactory("javax.swing.JSlider", new SliderFactory());
130: registerFactory("javax.swing.JTree", new TreeFactory());
131: registerFactory("javax.swing.JEditorPane",
132: new EditorPaneFactory());
133: registerFactory("javax.swing.JTabbedPane",
134: new TabbedPaneFactory());
135: registerFactory("javax.swing.JFormattedTextField",
136: new FormattedTextFieldFactory());
137:
138: /* special case for JLabel since we have a custom JETALabel */
139: LabelBeanFactory lbf = new LabelBeanFactory();
140: lbf.setBeanClass(JLabel.class);
141: registerFactory("javax.swing.JLabel", lbf);
142:
143: /** custom jetaware components */
144: registerFactory(HorizontalLineComponent.class.getName(),
145: new HorizontalLineComponentFactory());
146: registerFactory(VerticalLineComponent.class.getName(),
147: new VerticalLineComponentFactory());
148: registerFactory(GridView.class.getName(),
149: new GridViewBeanFactory());
150: registerFactory(ImageComponent.class.getName(),
151: new ImageBeanFactory());
152: registerFactory(JETALabel.class.getName(),
153: new LabelBeanFactory());
154: registerFactory(TitledBorderLabel.class.getName(),
155: new TitledBorderLabelFactory());
156: registerFactory(TitledBorderSide.class.getName(),
157: new TitledBorderSideFactory());
158: registerFactory(TitledBorderBottom.class.getName(),
159: new TitledBorderBottomFactory());
160: registerFactory(TitledSeparator.class.getName(),
161: new TitledSeparatorFactory());
162: }
163:
164: /**
165: * Registers a factory for the given component class
166: */
167: public static void registerFactory(String compClass,
168: BeanFactory factory) {
169: m_factories.put(compClass, factory);
170: }
171:
172: /**
173: * Removes all custom factories from the cache
174: */
175: public static void clearCustomFactories() {
176: m_custom_factories.clear();
177: }
178:
179: /**
180: * Creates a JETABean wrapper for managing a JavaBean.
181: *
182: * @param compClass
183: * the class name of the Java Bean to create (e.g.
184: * javax.swing.JButton, javax.swing.JRadioButton, etc.)
185: * @param compName
186: * the name to assign to this component by calling
187: * Component.setName
188: * @param instantiateBean
189: * set to true if the underlying Java Bean should be instantiated
190: * as well. During deserialization we don't want to do this
191: * because the XMLDecoder will create the JavaBean for us.
192: * @param setDefaults
193: * sets default properties for the bean. If false, no properties
194: * will be set (e.g. the text for a JButton)
195: */
196: public static JETABean createBean(String compClass,
197: String compName, boolean instantiateBean,
198: boolean setDefaults) throws FormException {
199: if (compClass != null) {
200: compClass = compClass.replace('/', '.');
201: compClass = compClass.replace('\\', '.');
202: }
203:
204: BeanFactory factory = (BeanFactory) lookupFactory(compClass);
205: if (factory != null) {
206: return factory.createBean(compName, instantiateBean,
207: setDefaults);
208: } else {
209: return null;
210: }
211: }
212:
213: /**
214: * Creates a bean info object for the given class.
215: */
216: public static DynamicBeanInfo getBeanInfo(Class compClass)
217: throws FormException {
218: DynamicBeanInfo beaninfo = JComponentBeanFactory
219: .createBeanInfo(compClass);
220: BeanFactory bf = lookupFactory(compClass.getName());
221: /** todo fix this to eliminate instance check */
222: if (bf instanceof JComponentBeanFactory) {
223: BeanProperties default_props = new BeanProperties(beaninfo);
224: ((JComponentBeanFactory) bf)
225: .defineProperties(default_props);
226: } else if (bf instanceof GridViewBeanFactory) {
227: BeanProperties default_props = new BeanProperties(beaninfo);
228: ((GridViewBeanFactory) bf).defineProperties(default_props);
229: }
230: return beaninfo;
231: }
232:
233: /**
234: * Looks up a BeanFactory from either the standard factories or one of the
235: * custom component factories. Null is returned if a factory is not found.
236: */
237: private static BeanFactory lookupFactory(String compClass) {
238: BeanFactory factory = (BeanFactory) m_factories.get(compClass);
239: if (factory == null)
240: factory = (BeanFactory) m_custom_factories.get(compClass);
241:
242: return factory;
243: }
244:
245: /**
246: * Locates a factory that is for a superclass of the given component class.
247: * Iterates over all registered factories. Almost all factories will have
248: * the same superclass as a superclass of the given component class. For
249: * example, we automatically register a factory for both JRadioButton and
250: * JToggleButton. If a user wants to register a custom component based on
251: * JRadioButton, then either factory would work. However, since the factory
252: * associated with JRadioButton is a closer relationship, we need to choose
253: * that one.
254: *
255: * @param compClass
256: * the class of the Java Bean whose factory we wish to locate.
257: * @return a JComponentBeanFactory associated with the given bean.
258: */
259: private static JComponentBeanFactory lookupAssignableFactory(
260: Class compClass) {
261: /**
262: * count for keeping track of the factory with the closest relationship
263: * to the given compClass
264: */
265: int min_count = 0;
266: JComponentBeanFactory result_factory = null;
267:
268: if (JComponent.class.isAssignableFrom(compClass)) {
269: Iterator iter = m_factories.values().iterator();
270: while (iter.hasNext()) {
271: BeanFactory factory = (BeanFactory) iter.next();
272: if (factory instanceof JComponentBeanFactory) {
273: JComponentBeanFactory jfactory = (JComponentBeanFactory) factory;
274: Class super class = compClass;
275: int derive_count = 1;
276: while (super class != JComponent.class
277: && super class != Object.class) {
278: if (super class == jfactory.getBeanClass()) {
279: if ((min_count > derive_count)
280: || (min_count == 0)) {
281: result_factory = jfactory;
282: min_count = derive_count;
283: }
284: break;
285: }
286: super class = super class.getSuperclass();
287: derive_count++;
288: }
289: }
290: }
291: }
292: return result_factory;
293: }
294:
295: /**
296: * This is for custom, imported Java Beans. If those beans extend one of the
297: * standard swing components, then we want to register a factory based on
298: * the standard factory so we can still use any custom properties.
299: */
300: public static void tryRegisterCustomFactory(String compClass,
301: boolean scrollable) throws FormException {
302: try {
303: if (compClass == null)
304: return;
305:
306: if (compClass != null) {
307: compClass = compClass.replace('/', '.');
308: compClass = compClass.replace('\\', '.');
309: }
310:
311: Class c = Class.forName(compClass);
312: tryRegisterCustomFactory(c, scrollable);
313: } catch (Exception e) {
314: FormsLogger.debug(e);
315: if (e instanceof FormException)
316: throw (FormException) e;
317: else
318: throw new FormException(e);
319: }
320: }
321:
322: /**
323: * This is for custom, imported Java Beans. If those beans extend one of the
324: * standard swing components, then we want to register a factory based on
325: * the standard factory so we can still use any custom properties.
326: */
327: public static void tryRegisterCustomFactory(Class compClass,
328: boolean scrollable) throws FormException {
329: try {
330: if (compClass == null)
331: return;
332:
333: /**
334: * This is needed to support custom swing components that are
335: * scrollable.
336: */
337: BeanFactory bf = lookupFactory(compClass.getName());
338: if (bf instanceof JComponentBeanFactory) {
339: JComponentBeanFactory jf = (JComponentBeanFactory) bf;
340: jf.setScrollable(scrollable);
341: return;
342: }
343:
344: JComponentBeanFactory jfactory = lookupAssignableFactory(compClass);
345: if (jfactory != null) {
346: JComponentBeanFactory customfactory = (JComponentBeanFactory) jfactory
347: .getClass().newInstance();
348: customfactory.setBeanClass(compClass);
349: customfactory.setScrollable(scrollable);
350: m_custom_factories.put(compClass.getName(),
351: customfactory);
352: return;
353: }
354:
355: /**
356: * If we can't find a registered class, then just use the JComponent
357: * class
358: */
359: JComponentBeanFactory customfactory = new JComponentBeanFactory(
360: compClass);
361: customfactory.setScrollable(scrollable);
362: m_custom_factories.put(compClass.getName(), customfactory);
363: } catch (Exception e) {
364: FormsLogger.debug(e);
365: if (e instanceof FormException)
366: throw (FormException) e;
367: else
368: throw new FormException(e);
369: }
370: }
371:
372: /** @link dependency */
373: /* # JETABean lnkJETABean; */
374: }
|