001: package org.uispec4j.utils;
002:
003: import org.uispec4j.*;
004:
005: import java.awt.Component;
006: import java.awt.Container;
007: import java.lang.reflect.Constructor;
008: import java.util.*;
009:
010: /**
011: * Factory which creates UIComponent wrappers for Swing components.
012: */
013: public final class UIComponentFactory {
014:
015: private static final Class[] COMPONENT_CLASSES = { Button.class,
016: CheckBox.class, ComboBox.class, Desktop.class,
017: ListBox.class, MenuBar.class, MenuItem.class, Panel.class,
018: PasswordField.class, ProgressBar.class, RadioButton.class,
019: Spinner.class, TabGroup.class, Table.class, TextBox.class,
020: ToggleButton.class, Tree.class, Window.class, Slider.class };
021:
022: private static List ADDITIONAL_CLASSES;
023: private static Map SWING_TO_UISPEC_MAP;
024:
025: /* Warning : reflection call in the extension mechanism */
026: public static void addUIComponentClass(Class uiComponentClass) {
027: getAdditionalClassesList().add(uiComponentClass);
028: }
029:
030: public static UIComponent createUIComponent(Component component) {
031: Class swingClass = getSwingClass(component.getClass());
032: if (swingClass == null) {
033: return null;
034: }
035: Class uiSpecClass = (Class) getSwingToUISpecMap().get(
036: swingClass);
037: try {
038: Constructor constructor = getConstructor(uiSpecClass,
039: swingClass);
040: return (UIComponent) constructor
041: .newInstance(new Object[] { component });
042: } catch (Exception e) {
043: throw new RuntimeException(e);
044: }
045: }
046:
047: public static UIComponent[] createUIComponents(
048: Component[] swingComponents) {
049: UIComponent[] components = new UIComponent[swingComponents.length];
050: for (int i = 0; i < swingComponents.length; i++) {
051: components[i] = createUIComponent(swingComponents[i]);
052: }
053: return components;
054: }
055:
056: static void fillSwingToUISpecMap(Map map, Class[] uiSpecClasses) {
057: for (int i = 0; i < uiSpecClasses.length; i++) {
058: Class uiSpecClass = uiSpecClasses[i];
059: addUIComponentClass(uiSpecClass, map);
060: }
061: }
062:
063: static Map initUIComponentClasses(Class[] uiComponentClasses,
064: List classes) {
065: List allClasses = new ArrayList();
066: allClasses.addAll(Arrays.asList(uiComponentClasses));
067: allClasses.addAll(classes);
068: Class[] allClassesArray = (Class[]) allClasses
069: .toArray(new Class[allClasses.size()]);
070: checkClasses(allClassesArray);
071:
072: Map result = new HashMap();
073: fillSwingToUISpecMap(result, allClassesArray);
074: return result;
075: }
076:
077: private static Constructor getConstructor(Class uiSpecClass,
078: Class swingClass) throws NoSuchMethodException {
079: try {
080: return uiSpecClass
081: .getConstructor(new Class[] { swingClass });
082: } catch (NoSuchMethodException e) {
083: return getConstructor(uiSpecClass, swingClass
084: .getSuperclass());
085: }
086: }
087:
088: private static void addUIComponentClass(Class uiSpecClass, Map map) {
089: Class[] classes = UIComponentAnalyzer
090: .getSwingClasses(uiSpecClass);
091: for (int j = 0; j < classes.length; j++) {
092: checkSwingClass(classes[j], uiSpecClass);
093: map.put(classes[j], uiSpecClass);
094: }
095: }
096:
097: private static void checkSwingClass(Class aClass, Class uiSpecClass) {
098: if (!Container.class.isAssignableFrom(aClass)) {
099: throw new RuntimeException("Class '" + aClass
100: + "' in field 'SWING_CLASSES' of class '"
101: + uiSpecClass + "' should extend '"
102: + Container.class + "'");
103: }
104: }
105:
106: private static Class getSwingClass(Class swingClass) {
107: if (swingClass == null) {
108: return null;
109: }
110: if (getSwingToUISpecMap().containsKey(swingClass)) {
111: return swingClass;
112: }
113: return getSwingClass(swingClass.getSuperclass());
114: }
115:
116: private static void checkClasses(Class[] classes) {
117: for (int i = 0; i < classes.length; i++) {
118: checkClass(classes[i]);
119: checkTypeNameField(classes[i]);
120: }
121: }
122:
123: private static void checkClass(Class uiComponentClass) {
124: if (!UIComponent.class.isAssignableFrom(uiComponentClass)) {
125: throw new RuntimeException("Class '" + uiComponentClass
126: + "' should implement " + UIComponent.class);
127: }
128: }
129:
130: private static void checkTypeNameField(Class uiComponentClass) {
131: Object value;
132: try {
133: value = uiComponentClass.getDeclaredField("TYPE_NAME").get(
134: null);
135: } catch (IllegalAccessException e) {
136: throw new RuntimeException(
137: "Field 'static String TYPE_NAME' in class "
138: + uiComponentClass + " should be public");
139: } catch (NoSuchFieldException e) {
140: throw new RuntimeException(
141: "Class "
142: + uiComponentClass
143: + " should have a field 'public static String TYPE_NAME'");
144: }
145: if (value == null) {
146: throw new RuntimeException(
147: "Field 'static String TYPE_NAME' in class "
148: + uiComponentClass
149: + " should be initialized");
150: }
151: if (!String.class.isInstance(value)) {
152: throw new RuntimeException(
153: "Static field 'TYPE_NAME' in class "
154: + uiComponentClass
155: + " should be of type String");
156: }
157: }
158:
159: private static Map getSwingToUISpecMap() {
160: if (SWING_TO_UISPEC_MAP == null) {
161: SWING_TO_UISPEC_MAP = new HashMap();
162: SWING_TO_UISPEC_MAP = initUIComponentClasses(
163: COMPONENT_CLASSES, getAdditionalClassesList());
164: }
165: return SWING_TO_UISPEC_MAP;
166: }
167:
168: private static List getAdditionalClassesList() {
169: if (ADDITIONAL_CLASSES == null) {
170: ADDITIONAL_CLASSES = new ArrayList();
171: }
172: return ADDITIONAL_CLASSES;
173: }
174: }
|