001: package net.xoetrope.builder.editor;
002:
003: import java.io.IOException;
004: import java.io.StringWriter;
005: import java.io.Writer;
006: import java.lang.reflect.Method;
007: import java.util.Vector;
008:
009: import java.awt.AWTEvent;
010: import java.awt.Component;
011: import java.awt.Container;
012: import java.awt.Rectangle;
013:
014: import net.n3.nanoxml.IXMLElement;
015: import net.n3.nanoxml.XMLElement;
016: import net.n3.nanoxml.XMLWriter;
017:
018: import net.xoetrope.awt.XButton;
019: import net.xoetrope.awt.XCheckbox;
020: import net.xoetrope.awt.XComboBox;
021: import net.xoetrope.awt.XEdit;
022: import net.xoetrope.awt.XHotspotImage;
023: import net.xoetrope.awt.XImage;
024: import net.xoetrope.awt.XLabel;
025: import net.xoetrope.awt.XList;
026: import net.xoetrope.awt.XMetaContent;
027: import net.xoetrope.awt.XPanel;
028: import net.xoetrope.awt.XRadioButton;
029: import net.xoetrope.awt.XScrollPane;
030: import net.xoetrope.awt.XScrollableMetaContent;
031: import net.xoetrope.awt.XTable;
032: import net.xoetrope.xui.XEventHandler;
033: import net.xoetrope.xui.XPage;
034: import net.xoetrope.xui.data.XDataBinding;
035: import net.xoetrope.xui.data.XListBinding;
036: import net.xoetrope.xui.validation.XValidationHandler;
037: import net.xoetrope.xui.validation.XValidator;
038: import net.xoetrope.xui.wmf.XWmf;
039: import net.xoetrope.builder.editor.components.ComponentHelper;
040: import net.xoetrope.builder.editor.components.PropertyHelper;
041: import net.xoetrope.xui.data.XTextBinding;
042: import net.xoetrope.xui.XResourceManager;
043: import net.xoetrope.xml.nanoxml.NanoXmlWriter;
044: import net.xoetrope.builder.editor.plugin.XPluginManager;
045: import java.util.Hashtable;
046: import java.util.Enumeration;
047: import net.xoetrope.xui.XProjectManager;
048: import net.xoetrope.xui.data.XStateBinding;
049: import net.xoetrope.xui.XStateHolder;
050: import net.xoetrope.xui.data.XRadioBinding;
051:
052: /**
053: * Write out the XML description of an XUI page.
054: * <p>Copyright: Copyright (c) Xoetrope Ltd., 2002-2003</p>
055: * @version $Revision: 1.24 $
056: * @License: see license.txt
057: */
058: public class XuiWriter {
059: protected XPage targetPage;
060: protected XPageResource pageResources;
061: protected String implementingClassName;
062: protected XEditorProject currentProject;
063:
064: /**
065: * Create a new XML writer
066: * @param resources the page to write
067: */
068: public XuiWriter(XEditorProject project, XPageResource resources) {
069: currentProject = project;
070: pageResources = resources;
071: targetPage = pageResources.getPage();
072:
073: String javaSrc = pageResources.getJavaSource();
074: if ((javaSrc != null) && (javaSrc.length() > 0))
075: implementingClassName = pageResources.getPackageName()
076: + "." + pageResources.getName();
077: }
078:
079: /**
080: * Write the XML definition of the current XUI page
081: * @param writer the IO Writer
082: * @throws IOException
083: */
084: public void write(Writer writer) throws IOException {
085: NanoXmlWriter xmlWriter = new NanoXmlWriter(writer);
086: xmlWriter.write(generate(), true, 4);
087: }
088:
089: /**
090: * Get the XML for the styles as a String ready for writing to file
091: * @return the formatted output string
092: * @throws IOException
093: */
094: public String getXml() throws IOException {
095: StringWriter ssw = new StringWriter();
096: XMLWriter xmlWriter = new XMLWriter(ssw);
097: xmlWriter.write(generate(), true, 4);
098:
099: return ssw.toString();
100: }
101:
102: public XMLElement getBaseElement() {
103: try {
104: return generate();
105: } catch (IOException ex) {
106: return null;
107: }
108: }
109:
110: /**
111: * Get the XML definition of the current XUI page
112: * @throws IOException
113: */
114: private XMLElement generate() throws IOException {
115: XMLElement xml = new XMLElement("XPage");
116: if (implementingClassName == null) {
117: String className = targetPage.getClass().getName();
118: if (!className.equals("net.xoetrope.xui.XPage")) {
119: String defaultClassName = XProjectManager
120: .getCurrentProject().getStartupParam(
121: "DefaultClass");
122: if ((defaultClassName == null)
123: || !defaultClassName.equals(className))
124: xml.setAttribute("class", className);
125: }
126: } else {
127: if (implementingClassName.startsWith("."))
128: implementingClassName = implementingClassName
129: .substring(1);
130: xml.setAttribute("class", implementingClassName);
131: }
132:
133: PropertyHelper helper = new ComponentHelper()
134: .getPropertyHelper(targetPage);
135: String attributeValue = helper.getPropertyValue(pageResources,
136: targetPage, 6);
137: if ((attributeValue != null) && (attributeValue.length() > 0))
138: xml.setAttribute("style", attributeValue);
139:
140: int numProperties = helper.getNumProperties();
141: for (int i = helper.getNumBasicProperties(); i < numProperties; i++) {
142: attributeValue = helper.getPropertyValue(pageResources,
143: targetPage, i);
144: if ((attributeValue != null)
145: && (attributeValue.length() > 0))
146: xml.setAttribute(helper.getPropertyName(pageResources,
147: targetPage, i), attributeValue);
148: }
149:
150: XMLElement componentXml = new XMLElement("Components");
151: writeComponents(targetPage, componentXml);
152: xml.addChild(componentXml);
153:
154: XMLElement eventXml = new XMLElement("Events");
155: if (writeEvents(targetPage, eventXml) > 0)
156: xml.addChild(eventXml);
157:
158: XMLElement validationXml = new XMLElement("Validations");
159: if (writeValidations(targetPage, validationXml) > 0)
160: xml.addChild(validationXml);
161:
162: XMLElement dataXml = new XMLElement("Data");
163: if (writeBindings(targetPage, dataXml) > 0)
164: xml.addChild(dataXml);
165:
166: addPluginProperties(xml);
167: return xml;
168: }
169:
170: /**
171: * Write out the components and their attributes
172: * @param page
173: * @param element
174: */
175: protected void writeComponents(Container page, IXMLElement element) {
176: int numChildren = page.getComponentCount();
177: if (page instanceof net.xoetrope.swing.XScrollPane) {
178: writeComponents((Container) page.getComponent(0), element);
179: return;
180: }
181: for (int i = 0; i < numChildren; i++) {
182: Component comp = page.getComponent(i);
183: if (comp.getClass().getName().indexOf("javax.swing.plaf.") == 0)
184: continue;
185: PropertyHelper helper = new ComponentHelper()
186: .getPropertyHelper(comp);
187: if (helper != null) {
188: String typeStr = helper.getPropertyValue(pageResources,
189: comp, 0);
190: IXMLElement childXml = element.createElement(typeStr);
191: int numProperties = helper.getNumProperties();
192: for (int j = 1; j < numProperties; j++) {
193: int propertyType = helper.getPropertyType(j);
194: switch (propertyType) {
195: case PropertyHelper.VALIDATION_PROPERTY:
196: case PropertyHelper.DATA_PROPERTY:
197: case PropertyHelper.EVENT_HANDLER_PROPERTY:
198: break;
199:
200: case PropertyHelper.STYLE_PROPERTY: {
201: String attributeValue = helper
202: .getPropertyValue(pageResources, comp,
203: j);
204: String attributeName = helper.getPropertyName(
205: pageResources, comp, j);
206: if ((attributeValue != null)
207: && (attributeValue.length() > 0)
208: && !attributeValue.equals("[None]"))
209: childXml.setAttribute(attributeName
210: .toLowerCase(), attributeValue);
211: }
212: break;
213:
214: case PropertyHelper.PLAIN_PROPERTY:
215: default: {
216: String attributeValue = helper
217: .getPropertyValue(pageResources, comp,
218: j);
219: String attributeName = helper.getPropertyName(
220: pageResources, comp, j);
221: if ((attributeValue != null)
222: && (attributeValue.length() > 0))
223: childXml.setAttribute(attributeName
224: .toLowerCase(), attributeValue);
225: }
226: break;
227: }
228: }
229: addPluginProperties(comp, childXml);
230:
231: if ((comp instanceof Container)
232: && helper.allowsChildren())
233: writeComponents((Container) comp, childXml);
234:
235: element.addChild(childXml);
236: }
237: }
238: }
239:
240: /**
241: * Allow each plugin to add attributes to the pages
242: * @param element
243: */
244: protected void addPluginProperties( IXMLElement element )
245: {
246: XPluginManager pluginMgr = currentProject.getPluginManager();
247: int numPlugins = pluginMgr.getNumPlugins();
248: for ( int i = 0; i < numPlugins; i++ ) {
249: Hashtable attribTable = pluginMgr.getPlugin( i ).getPageAttributes( pageResources );
250: if ( attribTable != null ) {
251: Enumeration enum = attribTable.keys();
252: while ( enum.hasMoreElements()) {
253: String key = (String)enum.nextElement();
254: element.setAttribute( key, (String)attribTable.get( key ));
255: }
256: }
257: }
258: }
259:
260: /**
261: * Allow each plugin to add attributes to the pages
262: * @param element
263: */
264: protected void addPluginProperties( Component comp, IXMLElement childXml )
265: {
266: XPluginManager pluginMgr = currentProject.getPluginManager();
267: int numPlugins = pluginMgr.getNumPlugins();
268: for ( int i = 0; i < numPlugins; i++ ) {
269: Hashtable attribTable = pluginMgr.getPlugin( i ).getComponentAttributes( comp );
270: if ( attribTable != null ) {
271: Enumeration enum = attribTable.keys();
272: while ( enum.hasMoreElements()) {
273: String key = (String)enum.nextElement();
274: childXml.setAttribute( key, (String)attribTable.get( key ));
275: }
276: }
277: }
278: }
279:
280: /**
281: * Write out the component events and their attributes
282: * @param page the target page
283: * @param element the XML element to which the node is added
284: * @return the number of elements written
285: */
286: protected int writeEvents(Container page, IXMLElement element) {
287: int numElements = 0;
288: int numChildren = page.getComponentCount();
289: for (int i = 0; i < numChildren; i++) {
290: Component comp = page.getComponent(i);
291: String compName = comp.getName();
292: if (compName != null && compName.length() > 0) {
293: String method = pageResources.getCtlEvent(comp,
294: AWTEvent.TEXT_EVENT_MASK);
295: numElements += writeEvent(element, method, compName,
296: "TextHandler");
297:
298: method = pageResources.getCtlEvent(comp,
299: AWTEvent.KEY_EVENT_MASK);
300: numElements += writeEvent(element, method, compName,
301: "KeyHandler");
302:
303: method = pageResources.getCtlEvent(comp,
304: AWTEvent.MOUSE_EVENT_MASK);
305: numElements += writeEvent(element, method, compName,
306: "MouseHandler");
307:
308: method = pageResources.getCtlEvent(comp,
309: AWTEvent.MOUSE_MOTION_EVENT_MASK);
310: numElements += writeEvent(element, method, compName,
311: "MouseMotionHandler");
312:
313: method = pageResources.getCtlEvent(comp,
314: AWTEvent.ACTION_EVENT_MASK);
315: numElements += writeEvent(element, method, compName,
316: "ActionHandler");
317:
318: method = pageResources.getCtlEvent(comp,
319: AWTEvent.ITEM_EVENT_MASK);
320: numElements += writeEvent(element, method, compName,
321: "ItemHandler");
322:
323: method = pageResources.getCtlEvent(comp,
324: AWTEvent.FOCUS_EVENT_MASK);
325: numElements += writeEvent(element, method, compName,
326: "FocusHandler");
327: }
328: if (comp instanceof Container)
329: numElements += writeEvents((Container) comp, element);
330: }
331: return numElements;
332: }
333:
334: /**
335: * Append the XML for an event node
336: * @param element the parent element
337: * @param method the response method name
338: * @param target the componentto which the method responds
339: * @param handlerName the name/type of event handler to be used
340: * @return
341: */
342: public int writeEvent(IXMLElement element, String methodName,
343: String target, String handlerName) {
344: if (methodName == null)
345: return 0;
346:
347: IXMLElement childXml = element.createElement("Event");
348: childXml.setAttribute("method", methodName);
349: childXml.setAttribute("target", target);
350: childXml.setAttribute("type", handlerName);
351: element.addChild(childXml);
352: return 1;
353: }
354:
355: /**
356: * Append the XML for the validations
357: * @param element the parent element
358: * @param method the response method name
359: * @param target the componentto which the method responds
360: * @param handlerName the name/type of event handler to be used
361: * @return
362: */
363: protected int writeValidations(Container page, IXMLElement element) {
364:
365: XPage xpage = (XPage) page;
366: XValidationHandler handler = xpage.getValidationHandler();
367: int numValidations = iterateValidations(xpage, xpage, handler,
368: element);
369: // int numChildren = page.getComponentCount();
370: // for ( int i = 0; i < numChildren; i++ ) {
371: // Component comp = page.getComponent( i );
372: // Vector validations = handler.getValidations( comp );
373: // if ( validations != null ) {
374: // int size = validations.size();
375: // for ( int j = 0; j < size; j++ ) {
376: // IXMLElement childXml = element.createElement( "Validation" );
377: // childXml.setAttribute( "rule", ( ( XValidator )validations.elementAt( j ) ).getName() );
378: // childXml.setAttribute( "target", comp.getName() );
379: // element.addChild( childXml );
380: // numValidations++;
381: // }
382: // }
383: // if ( comp instanceof Container )
384: // numValidations += writeValidations( (Container)comp, element );
385: // }
386: return numValidations > 0 ? 1 : 0;
387: }
388:
389: private int iterateValidations(XPage page, Container cont,
390: XValidationHandler handler, IXMLElement element) {
391: int numValidations = 0;
392: int numChildren = cont.getComponentCount();
393: for (int i = 0; i < numChildren; i++) {
394: Component comp = cont.getComponent(i);
395: Vector validations = handler.getValidations(comp);
396: if (validations != null) {
397: int size = validations.size();
398: for (int j = 0; j < size; j++) {
399: if (validations.elementAt(j) instanceof XValidator) {
400: IXMLElement childXml = element
401: .createElement("Validation");
402: childXml.setAttribute("rule",
403: ((XValidator) validations.elementAt(j))
404: .getName());
405: childXml.setAttribute("target", comp.getName());
406: element.addChild(childXml);
407: numValidations++;
408: break;
409: }
410: }
411: }
412: if (comp instanceof Container) {
413: numValidations += iterateValidations(page,
414: (Container) comp, handler, element);
415: }
416: }
417: return numValidations;
418: }
419:
420: /**
421: * Write out the component data bindings and their attributes. Each 'bind'
422: * node must have the 'target' and 'source' attributes and may optionally have
423: * the 'output' and 'type' attributes. The 'target' attributes identifies the
424: * target component or the component whose content/state will be modified. The
425: * 'source' node identifies the data source in the data model while the
426: * 'output' node identifies the node where the component state or output is
427: * saved. The output node is optional and is used to distinguish initial data
428: * or content from the selection state or user input values. The 'type'
429: * attribute is used to distinguish the type of binding where a component may
430: * have multiple bindings, for example a radio button may have a text and a
431: * state binding.
432: * @param page the page being loaded
433: * @param element the bindings xml element
434: * @return the number of elements written
435: */
436: protected int writeBindings(XPage page, IXMLElement element) {
437: Vector bindings = page.getBindings();
438: int numElements = 0;
439: int numChildren = bindings.size();
440: for (int i = 0; i < numChildren; i++) {
441: IXMLElement childXml = element.createElement("Bind");
442: Component comp = null;
443: String source = null;
444: String output = null;
445: String type = null;
446: XDataBinding binding = (XDataBinding) bindings.elementAt(i);
447: if (binding instanceof XTextBinding) {
448: comp = ((XTextBinding) binding).getComponent();
449: source = ((XTextBinding) binding).getSourcePath();
450: output = ((XTextBinding) binding).getOutputPath();
451: if (comp instanceof XStateHolder)
452: type = "text";
453: } else if (binding instanceof XListBinding) {
454: comp = ((XListBinding) binding).getComponent();
455: source = ((XListBinding) binding).getSourcePath();
456: output = ((XListBinding) binding).getOutputPath();
457: } else if (binding instanceof XRadioBinding) {
458: comp = ((XRadioBinding) binding).getComponent();
459: source = ((XRadioBinding) binding).getSourcePath();
460: output = ((XRadioBinding) binding).getOutputPath();
461: } else if (binding instanceof XStateBinding) {
462: comp = ((XStateBinding) binding).getComponent();
463: source = ((XStateBinding) binding).getSourcePath();
464: output = ((XStateBinding) binding).getOutputPath();
465: if (comp instanceof XStateHolder)
466: type = "state";
467: }
468:
469: if (comp != null && comp.getName().length() > 0) {
470: childXml.setAttribute("target", comp.getName());
471: childXml.setAttribute("source", source);
472: if (output != null)
473: childXml.setAttribute("output", output);
474: if (type != null)
475: childXml.setAttribute("type", type);
476:
477: element.addChild(childXml);
478: numElements++;
479: }
480: }
481: return numElements;
482: }
483:
484: private void setAttribute(IXMLElement childXml, String attribName,
485: String attribValue) {
486: if (attribValue != null)
487: childXml.setAttribute(attribName, attribValue);
488: }
489: }
|