001: package net.xoetrope.builder.editor;
002:
003: import java.io.File;
004: import java.io.Reader;
005: import java.net.MalformedURLException;
006: import java.net.URL;
007: import java.net.URLClassLoader;
008: import java.util.Vector;
009:
010: import java.awt.AWTEvent;
011: import java.awt.Component;
012: import java.awt.TextComponent;
013:
014: import net.xoetrope.builder.XuiBuilder;
015: import net.xoetrope.builder.editor.components.swing.XComponentProxy;
016: import net.xoetrope.debug.DebugLogger;
017: import net.xoetrope.xml.XmlElement;
018: import net.xoetrope.xui.XModelHolder;
019: import net.xoetrope.xui.XPage;
020: import net.xoetrope.xui.XProjectManager;
021: import net.xoetrope.xui.XResourceManager;
022: import net.xoetrope.xui.build.BuildProperties;
023: import net.xoetrope.xui.data.XDataBinding;
024: import net.xoetrope.xui.data.XListBinding;
025: import net.xoetrope.xui.data.XModel;
026: import net.xoetrope.xui.data.XModelAdapter;
027: import net.xoetrope.xui.data.XStateBinding;
028: import net.xoetrope.xui.data.XTextBinding;
029: import net.xoetrope.xui.style.XStyleFactory;
030: import net.xoetrope.xui.validation.XValidationHandler;
031: import net.xoetrope.xui.data.XRadioBinding;
032:
033: /**
034: * Subclasses the XuiBuilder primarily to listen for the events being registered
035: * for components
036: * <p>Copyright (c) Xoetrope Ltd., 1998-2004</p>
037: * $Revision: 1.19 $
038: * License: see license.txt
039: */
040: public class XEditorXuiBuilder extends XuiBuilder {
041: protected XPageHolder pageHolder;
042: protected XEditorProject currentProject;
043: protected XPageResource currentResource;
044: protected XAttributeEvaluator evaluator;
045:
046: /**
047: * Construct a new builder and set a custom XStyleFactory
048: * @param stylefact A custom XStyleFactory
049: */
050: public XEditorXuiBuilder(XEditorProject project,
051: XStyleFactory stylefact, XPageHolder ph) {
052: super (XPage.XUI_SWING_PACKAGE);
053:
054: currentProject = project;
055: componentFactory = stylefact;
056: pageHolder = ph;
057: evaluator = null;
058: }
059:
060: /**
061: * Adds data bindings to the page.
062: * @param page the page to which the component/data bindings are added
063: * @param model the data model
064: */
065: protected void addBindings(XPage page, XmlElement model) {
066: if (model == null)
067: return;
068:
069: String nameStr = null, srcStr, adapterStr, typeStr;
070: XModel rootNode = XProjectManager.getModel();
071:
072: Vector eventNodes = model.getChildren();
073: int numChildren = eventNodes.size();
074: for (int i = 0; i < numChildren; i++) {
075: XmlElement childNode = (XmlElement) eventNodes.elementAt(i);
076: try {
077: nameStr = childNode.getAttribute("target");
078: srcStr = childNode.getAttribute("source");
079: typeStr = childNode.getAttribute("type");
080: XModel dataModel = (XModel) rootNode.get(srcStr);
081:
082: Component targetComp = page.findComponent(nameStr);
083: XDataBinding factoryBinding = getFactoryBinding(
084: targetComp, dataModel, childNode);
085: if (factoryBinding != null)
086: page.addBinding(factoryBinding);
087: else {
088: Component proxyComp = targetComp;
089: if (targetComp instanceof XComponentProxy) {
090: targetComp = ((XComponentProxy) targetComp)
091: .getProxiedComponent();
092: }
093:
094: XModel srcModel = (XModel) rootNode.get(page
095: .evaluatePath(srcStr));
096: if (targetComp.getClass().getName().indexOf(
097: "XComboBox") >= 0) {
098: XListBinding binding;
099:
100: // Check for a specific binding
101: adapterStr = childNode.getAttribute("adapter");
102: if (adapterStr != null
103: && adapterStr.length() > 0) {
104: // Assume a table is bound to the node
105: XModelAdapter adapter = (XModelAdapter) Class
106: .forName(adapterStr).newInstance();
107: XModel tableModel = (XModel) rootNode
108: .get(srcStr);
109: adapter.setModel(tableModel);
110: binding = new XListBinding(proxyComp,
111: adapter);
112: } else { // Otherwise static data is being bound
113: String destStr = childNode
114: .getAttribute("output");
115: if (destStr == null)
116: destStr = srcStr;
117:
118: XModel dstModel = (XModel) rootNode
119: .get(page.evaluatePath(destStr));
120: binding = new XListBinding(proxyComp,
121: srcStr, destStr, srcModel, dstModel);
122: }
123:
124: // Check and set the unique rows property
125: String attrib = childNode
126: .getAttribute("unique");
127: if ((attrib != null)
128: && (attrib.compareTo("true") == 0))
129: binding.setUseUnique(true);
130: page.addBinding(binding);
131: } else if (targetComp.getClass().getName().indexOf(
132: "XEdit") >= 0)
133: page.addBinding(new XTextBinding(targetComp,
134: srcStr, srcModel));
135: else if (targetComp.getClass().getName().indexOf(
136: "XTextArea") >= 0)
137: page.addBinding(new XTextBinding(targetComp,
138: srcStr, srcModel));
139: else if (targetComp.getClass().getName().indexOf(
140: "XButton") >= 0)
141: page.addBinding(new XTextBinding(targetComp,
142: srcStr, srcModel));
143: else if (targetComp.getClass().getName().indexOf(
144: "XLabel") >= 0)
145: page.addBinding(new XTextBinding(targetComp,
146: srcStr, srcModel));
147: else if (targetComp.getClass().getName().indexOf(
148: "XRadioButton") >= 0) {
149: if (typeStr != null)
150: if (typeStr.equals("text"))
151: page.addBinding(new XTextBinding(
152: targetComp, srcStr, srcModel));
153: else if (typeStr.equals("state")) {
154: XStateBinding sb = new XStateBinding(
155: targetComp, srcStr, srcModel,
156: childNode.getAttribute("leaf"));
157: String destStr = childNode
158: .getAttribute("output");
159: if (destStr != null)
160: sb.setOutputPath(destStr);
161: page.addBinding(sb);
162: } else
163: page.addBinding(new XRadioBinding(
164: targetComp, srcStr, srcModel));
165: } else if (targetComp.getClass().getName().indexOf(
166: "XCheckbox") >= 0) {
167: if ((typeStr != null)
168: && (typeStr.equals("text")))
169: page.addBinding(new XTextBinding(
170: targetComp, srcStr, srcModel));
171: else {
172: XStateBinding sb = new XStateBinding(
173: targetComp, srcStr, srcModel,
174: childNode.getAttribute("leaf"));
175: String destStr = childNode
176: .getAttribute("output");
177: if (destStr != null)
178: sb.setOutputPath(destStr);
179: page.addBinding(sb);
180: }
181: } else if (targetComp.getClass().getName().indexOf(
182: "XTable") >= 0) {
183: XModel tableModel = (XModel) rootNode
184: .get(srcStr);
185: ((XModelHolder) targetComp)
186: .setModel(tableModel);
187: } else if (targetComp instanceof TextComponent)
188: page.addBinding(new XTextBinding(targetComp,
189: srcStr, srcModel));
190: }
191: } catch (Exception e) {
192: if (BuildProperties.DEBUG)
193: DebugLogger
194: .logError("While adding the data binding element: "
195: + nameStr);
196: e.printStackTrace();
197: }
198: }
199: }
200:
201: /**
202: * Adds an individual component element to the page (this method may be called
203: * recursively for nested elements). Several methods will be attempted until a
204: * component is successfully created. Firstly the built-in component types are
205: * checked, then any additional registered component constructors. The types
206: * can be specified by type ID, type name or class name.
207: * @param childNode the XML element containing the component specification.
208: */
209: protected Component addComponent(XmlElement childNode) {
210: Component comp = super .addComponent(childNode);
211: if (comp != null) {
212: String styleValue = (String) childNode
213: .getAttribute("style");
214: if (styleValue != null)
215: currentResource.setStyleName(comp, styleValue);
216: }
217: return comp;
218: }
219:
220: /**
221: * Overrides the super method. First call the super method and then register
222: * the event with the Project. This allows the editor to display the
223: * methods for components when they are selected and also to save them.
224: * @param xpage The page that contains the response methods
225: * @param targetComp the component to which the event handler is added
226: * @param typeStr the type of handler
227: * @param name the name of the response method
228: */
229: protected void addHandler(XPage xPage, Component targetComp,
230: String typeStr, String name) {
231: if (!(xPage.getEventHandler() instanceof XEditorEventHandler)) {
232: XEditorEventHandler eventHandler = new XEditorEventHandler(
233: pageHolder, xPage.getEventHandler(), xPage,
234: new XValidationHandler(xPage));
235: page.setEventHandler(eventHandler);
236: pageHolder.addListeners(xPage, eventHandler);
237: }
238: super .addHandler(xPage, targetComp, typeStr, name);
239:
240: long eventMask = 0;
241: if (typeStr.compareTo("MouseHandler") == 0)
242: eventMask = AWTEvent.MOUSE_EVENT_MASK;
243: else if (typeStr.compareTo("MouseMotionHandler") == 0)
244: eventMask = AWTEvent.MOUSE_MOTION_EVENT_MASK;
245: else if (typeStr.compareTo("ActionHandler") == 0)
246: eventMask = AWTEvent.ACTION_EVENT_MASK;
247: else if (typeStr.compareTo("FocusHandler") == 0)
248: eventMask = AWTEvent.FOCUS_EVENT_MASK;
249: else if (typeStr.compareTo("ItemHandler") == 0)
250: eventMask = AWTEvent.ITEM_EVENT_MASK;
251: else if (typeStr.compareTo("KeyHandler") == 0)
252: eventMask = AWTEvent.KEY_EVENT_MASK;
253: else if (typeStr.compareTo("TextHandler") == 0)
254: eventMask = AWTEvent.TEXT_EVENT_MASK;
255:
256: currentProject.getPageResource(xPage.getName()).addCtlEvent(
257: targetComp, eventMask, name);
258: }
259:
260: protected void setPageName(String pageName) {
261: currentResource = currentProject.getPageResource(pageName);
262:
263: super .setPageName(pageName);
264: }
265:
266: /**
267: * Loads a class as the basis for a page. Reloads the class each time so that
268: * the code can be recompiled and reloaded for preview mode.
269: * @param className the full class name
270: * @return an instance of the XPage class or a derivative
271: * @throws ClassNotFoundException
272: * @throws IllegalAccessException
273: * @throws InstantiationException
274: */
275: protected XPage loadClass(String className)
276: throws ClassNotFoundException, IllegalAccessException,
277: InstantiationException {
278: try {
279: // Create new class loader
280: // with current dir as CLASSPATH
281: File file = new File(currentProject.getClassPath());
282: ClassLoader loader = new URLClassLoader(new URL[] { file
283: .toURL() }, getClass().getClassLoader());
284: // load class through new loader
285: Class aClass = loader.loadClass(className);
286: return (XPage) aClass.newInstance();
287: } catch (MalformedURLException ex) {
288: }
289:
290: return (XPage) Class.forName(className).newInstance();
291: }
292:
293: /**
294: * Loads an XPage via a reader obtained from the XResourceManager (searches
295: * the classpath). The pageName is assumed to be the name of an XML file. For
296: * example if the pageName is 'welcome' then the 'welcome.xml' file is read as
297: * a UTF8 encoded XML file.
298: * @param defPackageName the package or path to the page
299: * @param pageName the page name or the name of the class implementing the page
300: * @param include true if the page to be loaded is being included in another
301: * page in which case any class attribute of the included page is ignored
302: * @param fullPathProvided the full path to the page name is provided
303: * @return the page
304: */
305: public XPage loadPage(String defPackageName, String pageName,
306: boolean include, boolean fullPathProvided) {
307: packageName = defPackageName;
308:
309: Reader r = null;
310: try {
311: r = XResourceManager.getBufferedReader(pageName, null);
312: } catch (Exception ex) {
313: if (BuildProperties.DEBUG)
314: DebugLogger.logError("File NOT found: " + pageName);
315: }
316: if (r == null)
317: return null;
318:
319: return readPage(r, pageName, include);
320: }
321:
322: public void setPageAttribute(Component c, String attributeName,
323: String attributeValue) {
324: if (attributeName.compareTo("style") == 0)
325: currentResource.setStyleName(c, attributeValue);
326: else
327: currentResource.setPageAttribute(attributeName,
328: attributeValue);
329: }
330:
331: /**
332: * Get the value of an attribute.
333: * @param page the page being loaded
334: * @param attributeValue the raw value of the attribute
335: * @return the evaluated value of the attribute
336: */
337: public Object evaluateAttribute(XPage page, String attributeValue) {
338: if (evaluator != null)
339: return evaluator.evaluateAttribute(page, attributeValue);
340: return page.evaluateAttribute(attributeValue);
341: }
342:
343: /**
344: * Set the attribute evaluator object.
345: * @param e the new evaluator
346: */
347: public void setAttributeEvaluator(XAttributeEvaluator e) {
348: evaluator = e;
349: }
350: }
|