KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > swixml > Parser


1 /*--
2  $Id: Parser.java,v 1.4 2005/06/04 22:17:02 wolfpaulus Exp $
3
4  Copyright (C) 2003-2004 Wolf Paulus.
5  All rights reserved.
6
7  Redistribution and use in source and binary forms, with or without
8  modification, are permitted provided that the following conditions
9  are met:
10
11  1. Redistributions of source code must retain the above copyright
12  notice, this list of conditions, and the following disclaimer.
13
14  2. Redistributions in binary form must reproduce the above copyright
15  notice, this list of conditions, and the disclaimer that follows
16  these conditions in the documentation and/or other materials provided
17  with the distribution.
18
19  3. The end-user documentation included with the redistribution,
20  if any, must include the following acknowledgment:
21         "This product includes software developed by the
22          SWIXML Project (http://www.swixml.org/)."
23  Alternately, this acknowledgment may appear in the software itself,
24  if and wherever such third-party acknowledgments normally appear.
25
26  4. The name "Swixml" must not be used to endorse or promote products
27  derived from this software without prior written permission. For
28  written permission, please contact <info_AT_swixml_DOT_org>
29
30  5. Products derived from this software may not be called "Swixml",
31  nor may "Swixml" appear in their name, without prior written
32  permission from the Swixml Project Management.
33
34  THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
35  WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
36  OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
37  DISCLAIMED. IN NO EVENT SHALL THE SWIXML PROJECT OR ITS
38  CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
39  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
40  LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
41  USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
42  ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
43  OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
44  OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
45  SUCH DAMAGE.
46  ====================================================================
47
48  This software consists of voluntary contributions made by many
49  individuals on behalf of the Swixml Project and was originally
50  created by Wolf Paulus <wolf_AT_swixml_DOT_org>. For more information
51  on the Swixml Project, please see <http://www.swixml.org/>.
52 */

53
54 package org.swixml;
55
56 import org.jdom.Attribute;
57 import org.jdom.Document;
58 import org.jdom.Element;
59 import org.swixml.converters.ConstraintsConverter;
60 import org.swixml.converters.LocaleConverter;
61 import org.swixml.converters.PrimitiveConverter;
62
63 import javax.swing.*;
64 import java.awt.*;
65 import java.lang.reflect.*;
66 import java.util.*;
67 import java.util.List JavaDoc;
68
69 /**
70  * Singleton Parser to render XML for Swing Documents
71  * <p/>
72  * <img SRC="doc-files/swixml_1_0.png" ALIGN="center">
73  * </p>
74  *
75  * @author <a HREF="mailto:wolf@paulus.com">Wolf Paulus</a>
76  * @author <a HREF="mailto:fm@authentidate.de">Frank Meissner</a>
77  * @version $Revision: 1.4 $
78  * @see org.swixml.SwingTagLibrary
79  * @see org.swixml.ConverterLibrary
80  */

81 public class Parser {
82
83   //
84
// Custom Attributes
85
//
86

87   /**
88    * Additional attribute to collect layout constrain information
89    */

90   public static final String JavaDoc ATTR_CONSTRAINTS = "constraints";
91
92   /**
93    * Additional attribute to collect information about the PLAF implementation
94    */

95   public static final String JavaDoc ATTR_PLAF = "plaf";
96
97   /**
98    * Additional attribute to collect layout constrain information
99    */

100   public static final String JavaDoc ATTR_BUNDLE = "bundle";
101
102   /**
103    * Additional attribute to collect layout constrain information
104    */

105   public static final String JavaDoc ATTR_LOCALE = "locale";
106
107   /**
108    * Allows to provides swixml tags with an unique id
109    */

110   public static final String JavaDoc ATTR_ID = "id";
111
112   /**
113    * Allows to provides swixml tags with an unique id
114    */

115   public static final String JavaDoc ATTR_REFID = "refid";
116
117   /**
118    * Allows to provides swixml tags with an unique id
119    *
120    * @see #ATTR_REFID
121    * @deprecated use refid instead
122    */

123   public static final String JavaDoc ATTR_USE = "use";
124
125   /**
126    * Allows to provides swixml tags with an unique id
127    */

128   public static final String JavaDoc ATTR_INCLUDE = "include";
129
130   /**
131    * Allows to provides swixml tags with a dynamic update class
132    */

133   public static final String JavaDoc ATTR_INITCLASS = "initclass";
134
135   /**
136    * Allows to provides swixml tags with a dynamic update class
137    */

138   public static final String JavaDoc ATTR_ACTION = "action";
139
140   /**
141    * Prefix for all MAC OS X related attributes
142    */

143   public static final String JavaDoc ATTR_MACOS_PREFIX = "macos_";
144
145   /**
146    * Attribute name that flags an Action as the default Preferences handler on a Mac
147    */

148   public static final String JavaDoc ATTR_MACOS_PREF = ATTR_MACOS_PREFIX + "preferences";
149
150   /**
151    * Attribute name that flags an Action as the default Aboutbox handler on a Mac
152    */

153   public static final String JavaDoc ATTR_MACOS_ABOUT = ATTR_MACOS_PREFIX + "about";
154
155   /**
156    * Attribute name that flags an Action as the default Quit handler on a Mac
157    */

158   public static final String JavaDoc ATTR_MACOS_QUIT = ATTR_MACOS_PREFIX + "quit";
159
160   /**
161    * Attribute name that flags an Action as the default Open Application handler on a Mac
162    */

163   public static final String JavaDoc ATTR_MACOS_OPENAPP = ATTR_MACOS_PREFIX + "openapp";
164
165   /**
166    * Attribute name that flags an Action as the default Open File handler on a Mac
167    */

168   public static final String JavaDoc ATTR_MACOS_OPENFILE = ATTR_MACOS_PREFIX + "openfile";
169
170   /**
171    * Attribute name that flags an Action as the default Print handler on a Mac
172    */

173   public static final String JavaDoc ATTR_MACOS_PRINT = ATTR_MACOS_PREFIX + "print";
174
175   /**
176    * Attribute name that flags an Action as the default Re-Open Applicaiton handler on a Mac
177    */

178   public static final String JavaDoc ATTR_MACOS_REOPEN = ATTR_MACOS_PREFIX + "reopen";
179
180
181   /**
182    * Method name used with initclass - if this exit, the update class will no be instanced but getInstance is called
183    */

184   public static final String JavaDoc GETINSTANCE = "getInstance";
185
186   /**
187    * Localiced Attributes
188    */

189   public static final Vector LOCALIZED_ATTRIBUTES = new Vector();
190
191   //
192
// Private Members
193
//
194

195   /**
196    * the calling engine
197    */

198   private SwingEngine engine;
199
200   /**
201    * ConverterLib, to access COnverters, converting String in all kinds of things
202    */

203   private ConverterLibrary cvtlib = ConverterLibrary.getInstance();
204
205   /**
206    * map to store id-id components, needed to support labelFor attributes
207    */

208   private Map lbl_map = new HashMap();
209
210   /**
211    * map to store specific Mac OS actions mapping
212    */

213   private Map mac_map = new HashMap();
214
215   /**
216    * docoument, to be parsed
217    */

218   private Document jdoc;
219
220   /**
221    * Static Initializer adds Attribute Names into the LOCALIZED_ATTRIBUTES Vector
222    * Needs to be inserted all lowercase.
223    */

224   static {
225     LOCALIZED_ATTRIBUTES.add("accelerator");
226     LOCALIZED_ATTRIBUTES.add("icon");
227     LOCALIZED_ATTRIBUTES.add("iconimage");
228     LOCALIZED_ATTRIBUTES.add("label");
229     LOCALIZED_ATTRIBUTES.add("mnemonic");
230     LOCALIZED_ATTRIBUTES.add("name");
231     LOCALIZED_ATTRIBUTES.add("text");
232     LOCALIZED_ATTRIBUTES.add("title");
233     LOCALIZED_ATTRIBUTES.add("titleat");
234     LOCALIZED_ATTRIBUTES.add("titles");
235     LOCALIZED_ATTRIBUTES.add("tooltiptext");
236   }
237
238   /**
239    * Constructs a new SwixMl Parser for the provided engine.
240    *
241    * @param engine <code>SwingEngine</code>
242    */

243   public Parser(SwingEngine engine) {
244     this.engine = engine;
245   }
246
247   /**
248    * Converts XML into a javax.swing object tree.
249    * <pre>
250    * Note: This parse method does not return a swing object but converts all <b>sub</b> nodes
251    * of the xml documents root into seing objects and adds those into the provided container.
252    * This is useful when a JApplet for instance already exists and need to get some gui inserted.
253    * </pre>
254    *
255    * @param jdoc <code>Document</code> providing the XML document
256    * @param container <code>Container</code> container for the XML root's children
257    * @throws Exception
258    */

259   public void parse(Document jdoc, Container container) throws Exception JavaDoc {
260     this.jdoc = jdoc;
261     this.lbl_map.clear();
262     this.mac_map.clear();
263     getSwing(processCustomAttributes(jdoc.getRootElement()), container);
264
265     linkLabels();
266     supportMacOS();
267
268     this.lbl_map.clear();
269     this.mac_map.clear();
270   }
271
272   /**
273    * Converts XML into a javax.swing object tree.
274    * <pre>
275    * Reads XML from the provied <code>Reader</code> and builds an intermediate jdom document.
276    * Tags and their attributes are getting converted into swing objects.
277    * </pre>
278    *
279    * @param jdoc <code>Document</code> providing the XML document
280    * @return <code>java.awt.Container</code> root object for the swing object tree
281    * @throws Exception
282    */

283   public Object JavaDoc parse(Document jdoc) throws Exception JavaDoc {
284     this.jdoc = jdoc;
285     this.lbl_map.clear();
286     Object JavaDoc obj = getSwing(processCustomAttributes(jdoc.getRootElement()), null);
287
288     linkLabels();
289     supportMacOS();
290
291     this.lbl_map.clear();
292     this.mac_map.clear();
293     return obj;
294   }
295
296   /**
297    * Looks for custom attributes to be proccessed.
298    *
299    * @param element <code>Element</code> custom attr. tag are looked for in this jdoc element
300    * @return <code>Element</code> - passed in (and maybe modified) element
301    * <pre>
302    * <b>Note:</b>
303    * <br>Successfully proccessed custom attributes will be removed from the jdoc element.
304    * </pre>
305    */

306   private Element processCustomAttributes(Element element) throws Exception JavaDoc {
307     //
308
// set Locale
309
//
310
Attribute locale = element.getAttribute(Parser.ATTR_LOCALE);
311     if (locale != null && locale.getValue() != null) {
312       engine.setLocale(LocaleConverter.conv(locale));
313       element.removeAttribute(Parser.ATTR_LOCALE);
314     }
315     //
316
// set ResourceBundle
317
//
318
Attribute bundle = element.getAttribute(Parser.ATTR_BUNDLE);
319     if (bundle != null && bundle.getValue() != null) {
320       engine.getLocalizer().setResourceBundle(bundle.getValue());
321       element.removeAttribute(Parser.ATTR_BUNDLE);
322     }
323     //
324
// Set Look and Feel based on ATTR_PLAF
325
//
326
Attribute plaf = element.getAttribute(Parser.ATTR_PLAF);
327     if (plaf != null && plaf.getValue() != null && 0 < plaf.getValue().length()) {
328       try {
329         if (!(SwingEngine.isMacOSXSupported() && SwingEngine.isMacOSX())) {
330           UIManager.setLookAndFeel(plaf.getValue());
331         }
332       } catch (Exception JavaDoc e) {
333         if (SwingEngine.DEBUG_MODE) {
334           System.err.println(e);
335         }
336       }
337       element.removeAttribute(Parser.ATTR_PLAF);
338     }
339
340     return element;
341   }
342
343   /**
344    * Helper Method to Link Labels to InputFields etc.
345    */

346   private void linkLabels() {
347     Iterator it = lbl_map.keySet().iterator();
348     while (it != null && it.hasNext()) {
349       JLabel lbl = (JLabel) it.next();
350       String JavaDoc id = lbl_map.get(lbl).toString();
351       try {
352         lbl.setLabelFor((Component) engine.getIdMap().get(id));
353       } catch (ClassCastException JavaDoc e) {
354         // intent. empty.
355
}
356     }
357   };
358
359   /**
360    * Link actions with the MacOS' system menu bar
361    */

362   private void supportMacOS() {
363     if (SwingEngine.isMacOSXSupported() && SwingEngine.isMacOSX()) {
364       try {
365         MacApp.getInstance().update(mac_map);
366       } catch (Throwable JavaDoc t) {
367         // intentionally empty
368
}
369     }
370   }
371
372   /**
373    * Recursively converts <code>org.jdom.Element</code>s into <code>javax.swing</code> or <code>java.awt</code> objects
374    *
375    * @param element <code>org.jdom.Element</code> XML tag
376    * @param obj <code>Object</code> if not null, only this elements children will be processed, not the element itself
377    * @return <code>java.awt.Container</code> representing the GUI impementation of the XML tag.
378    * @throws Exception
379    */

380   Object JavaDoc getSwing(Element element, Object JavaDoc obj) throws Exception JavaDoc {
381
382     Factory factory = engine.getTaglib().getFactory(element.getName());
383     // look for <id> attribute value
384
String JavaDoc id = element.getAttribute(Parser.ATTR_ID) != null ? element.getAttribute(Parser.ATTR_ID).getValue().trim() : null;
385     // either there is no id or the id is not user so far
386
boolean unique = !engine.getIdMap().containsKey(id);
387     boolean constructed = false;
388
389     if (!unique) {
390       throw new IllegalStateException JavaDoc("id already in use: " + id + " : " + engine.getIdMap().get(id).getClass().getName());
391     }
392     if (factory == null) {
393       throw new Exception JavaDoc("Unknown TAG, implementation class not defined: " + element.getName());
394     }
395
396     //
397
// XInclude
398
//
399

400     if (element.getAttribute(Parser.ATTR_INCLUDE) != null) {
401       StringTokenizer st = new StringTokenizer(element.getAttribute(Parser.ATTR_INCLUDE).getValue(), "#");
402       element.removeAttribute(Parser.ATTR_INCLUDE);
403       Document doc = new org.jdom.input.SAXBuilder().build(this.engine.getClassLoader().getResourceAsStream(st.nextToken()));
404       Element xelem = find(doc.getRootElement(), st.nextToken());
405       if (xelem != null) {
406         moveContent(xelem, element);
407       }
408     }
409
410     //
411
// clone attribute if <em>use</em> attribute is available
412
//
413

414
415     if (element.getAttribute(Parser.ATTR_REFID) != null) {
416       element = (Element) element.clone();
417       cloneAttributes(element);
418       element.removeAttribute(Parser.ATTR_REFID);
419     } else if (element.getAttribute(Parser.ATTR_USE) != null) {
420       element = (Element) element.clone();
421       cloneAttributes(element);
422       element.removeAttribute(Parser.ATTR_USE);
423     }
424     //
425
// let the factory instance a new object
426
//
427

428     List JavaDoc attributes = element.getAttributes();
429     if (obj == null) {
430       Object JavaDoc initParameter = null;
431
432       if (element.getAttribute(Parser.ATTR_INITCLASS) != null) {
433         StringTokenizer st = new StringTokenizer(element.getAttributeValue(Parser.ATTR_INITCLASS), "( )");
434         element.removeAttribute(Parser.ATTR_INITCLASS);
435         //try {
436
try {
437           if (st.hasMoreTokens()) {
438             Class JavaDoc initClass = Class.forName(st.nextToken()); // load update type
439
try { // look for a getInstance() methode
440
Method factoryMethod = initClass.getMethod(Parser.GETINSTANCE, null);
441               if (Modifier.isStatic(factoryMethod.getModifiers())) {
442                 initParameter = factoryMethod.invoke(null, null);
443               }
444             } catch (NoSuchMethodException JavaDoc nsme) {
445               // really nothing to do here
446
}
447             if (initParameter == null && st.hasMoreTokens()) { // now try to instantiate with String taking ctor
448
try {
449                 Constructor ctor = initClass.getConstructor(new Class JavaDoc[]{String JavaDoc.class});
450                 String JavaDoc pattern = st.nextToken();
451                 initParameter = ctor.newInstance(new Object JavaDoc[]{pattern});
452               } catch (NoSuchMethodException JavaDoc e) {
453               } catch (SecurityException JavaDoc e) {
454               } catch (InstantiationException JavaDoc e) {
455               } catch (IllegalAccessException JavaDoc e) {
456               } catch (IllegalArgumentException JavaDoc e) {
457               } catch (InvocationTargetException e) {
458               }
459             }
460             if (initParameter == null) { // now try to instantiate with default ctor
461
initParameter = initClass.newInstance();
462             }
463             if (Action.class.isInstance(initParameter)) {
464               for (int i = 0, n = attributes.size(); i < n; i++) {
465                 Attribute attrib = (Attribute) attributes.get(i);
466                 String JavaDoc attribName = attrib.getName();
467                 if (attribName != null && attribName.startsWith(ATTR_MACOS_PREFIX)) {
468                   mac_map.put(attribName, initParameter);
469                 }
470               }
471             }
472           }
473         } catch (ClassNotFoundException JavaDoc e) {
474           System.err.println(Parser.ATTR_INITCLASS + " not instantiated : " + e.getLocalizedMessage() + e);
475         } catch (SecurityException JavaDoc e) {
476           System.err.println(Parser.ATTR_INITCLASS + " not instantiated : " + e.getLocalizedMessage() + e);
477         } catch (IllegalAccessException JavaDoc e) {
478           System.err.println(Parser.ATTR_INITCLASS + " not instantiated : " + e.getLocalizedMessage() + e);
479         } catch (IllegalArgumentException JavaDoc e) {
480           System.err.println(Parser.ATTR_INITCLASS + " not instantiated : " + e.getLocalizedMessage() + e);
481         } catch (InvocationTargetException e) {
482           System.err.println(Parser.ATTR_INITCLASS + " not instantiated : " + e.getLocalizedMessage() + e);
483         } catch (InstantiationException JavaDoc e) {
484           System.err.println(Parser.ATTR_INITCLASS + " not instantiated : " + e.getLocalizedMessage() + e);
485         } catch (RuntimeException JavaDoc re) {
486           throw re;
487         } catch (Exception JavaDoc e) {
488           throw new Exception JavaDoc(Parser.ATTR_INITCLASS + " not instantiated : " + e.getLocalizedMessage(), e);
489         }
490       }
491
492       obj = initParameter != null ? factory.newInstance(new Object JavaDoc[]{initParameter}) : factory.newInstance();
493       constructed = true;
494       //
495
// put newly created object in the map if it has an <id> attribute (uniqueness is given att this point)
496
//
497
if (id != null) {
498         engine.getIdMap().put(id, obj);
499       }
500     }
501     //
502
// 1st attempt to apply attributes (call setters on the objects)
503
// put an action attribute at the beginning of the attribute list
504
//
505
Attribute actionAttr = element.getAttribute("Action");
506     if (actionAttr != null) {
507       element.removeAttribute(actionAttr);
508       attributes.add(0, actionAttr);
509     }
510     //
511
// put Tag's Text content into Text Attribute
512
//
513
if (element.getAttribute("Text") == null && 0 < element.getTextTrim().length()) {
514       attributes.add(new Attribute("Text", element.getTextTrim()));
515     }
516     List JavaDoc remainingAttrs = applyAttributes(obj, factory, attributes);
517     //
518
// process child tags
519
//
520

521     LayoutManager layoutMgr = obj instanceof Container ? ((Container) obj).getLayout() : null;
522
523     Iterator it = element.getChildren().iterator();
524     while (it != null && it.hasNext()) {
525       Element child = (Element) it.next();
526       //
527
// Prepare for possible groupping through BottonGroup Tag
528
//
529
if ("buttongroup".equalsIgnoreCase(child.getName())) {
530
531         int k = JMenu.class.isAssignableFrom(obj.getClass()) ? ((JMenu) obj).getItemCount() : ((Container) obj).getComponentCount();
532         getSwing(child, obj);
533         int n = JMenu.class.isAssignableFrom(obj.getClass()) ? ((JMenu) obj).getItemCount() : ((Container) obj).getComponentCount();
534         //
535
// add the recently add container entries into the btngroup
536
//
537
ButtonGroup btnGroup = new ButtonGroup();
538         // incase the button group was given an id attr. it should also be put into the idmap.
539
if (null != child.getAttribute(Parser.ATTR_ID)) {
540           engine.getIdMap().put(child.getAttribute(Parser.ATTR_ID).getValue(), btnGroup);
541         }
542         while (k < n) {
543           putIntoBtnGrp(JMenu.class.isAssignableFrom(obj.getClass()) ? ((JMenu) obj).getItem(k++) : ((Container) obj).getComponent(k++), btnGroup);
544         }
545         continue;
546       }
547
548       //
549
// A CONSTRAINTS attribute is removed from the childtag but used to add the child into the currrent obj
550
//
551
Attribute constrnAttr = child.getAttribute(Parser.ATTR_CONSTRAINTS);
552       Object JavaDoc constrains = null;
553       if (constrnAttr != null && layoutMgr != null) {
554         child.removeAttribute(Parser.ATTR_CONSTRAINTS); // therefore it won't be used in getSwing(child)
555
constrains = ConstraintsConverter.convert(layoutMgr.getClass(), constrnAttr);
556       }
557
558       //
559
// A GridBagConstraints grand-childtag is not added at all ..
560
// .. but used to add the child into this container
561
//
562
Element grandchild = child.getChild("gridbagconstraints");
563       if (grandchild != null) {
564         addChild((Container) obj, (Component) getSwing(child, null), getSwing(grandchild, null));
565       } else if (!child.getName().equals("gridbagconstraints")) {
566         addChild((Container) obj, (Component) getSwing(child, null), constrains);
567       }
568     }
569
570     //
571
// 2nd attempt to apply attributes (call setters on the objects)
572
//
573
if (remainingAttrs != null && 0 < remainingAttrs.size()) {
574       remainingAttrs = applyAttributes(obj, factory, remainingAttrs);
575       if (remainingAttrs != null) {
576         it = remainingAttrs.iterator();
577         while (it != null && it.hasNext()) {
578           Attribute attr = (Attribute) it.next();
579           if (JComponent.class.isAssignableFrom(obj.getClass())) {
580             ((JComponent) obj).putClientProperty(attr.getName(), attr.getValue());
581             if (SwingEngine.DEBUG_MODE) {
582               System.out.println("ClientProperty put: " + obj.getClass().getName() + "(" + id + "): " + attr.getName() + "=" + attr.getValue());
583             }
584           } else {
585             if (SwingEngine.DEBUG_MODE) {
586               System.err.println(attr.getName() + " not applied for tag: <" + element.getName() + ">");
587             }
588           }
589         }
590       }
591     }
592
593     return (constructed ? obj : null);
594   }
595
596   /**
597    * Creates an object and sets properties based on the XML tag's attributes
598    *
599    * @param obj <code>Object</code> object representing a tag found in the SWIXML descriptor document
600    * @param factory <code>Factory</code> factory to instantiate a new object
601    * @param attributes <code>List</code> attribute list
602    * @return <code>List</code> - list of attributes that could not be applied.
603    * @throws Exception <pre>
604    * <ol>
605    * <li>For every attribute, createContainer() 1st tries to find a setter in the given factory.<br>
606    * if a setter can be found and converter exists to convert the parameter string into a type that fits
607    * the setter method, the setter gets invoked.</li>
608    * <li>Otherwise, createContainer() looks for a public field with a matching name.</li>
609    * </ol>
610    * </pre><pre>
611    * <b>Example:</b><br>
612    * <br>1.) try to create a parameter obj using the ParameterFactory: i.e.
613    * <br>background="FFC9AA" = container.setBackground ( new Color(attr.value) )
614    * <br>2.) try to find a simple setter taking a primitive or String: i.e.
615    * <br>width="25" container.setWidth( new Interger( attr. getIntValue() ) )
616    * <br>3.) try to find a public field,
617    * <br>container.BOTTOM_ALIGNMENT
618    * </pre>
619    */

620   private List JavaDoc applyAttributes(Object JavaDoc obj, Factory factory, List JavaDoc attributes) throws Exception JavaDoc {
621     //
622
// pass 1: Make an 'action' the 1st attribute to be processed -
623
// otherwise the action would overwrtite already applied attributes like text etc.
624
//
625

626     for (int i = 0; i < attributes.size(); i++) {
627       Attribute attr = (Attribute) attributes.get(i);
628       if (Parser.ATTR_ACTION.equalsIgnoreCase(attr.getName())) {
629         attributes.remove(i);
630         attributes.add(0, attr);
631         break;
632       }
633     }
634
635     //
636
// pass 2: process the attributes
637
//
638

639     Iterator it = attributes.iterator();
640     List JavaDoc list = new ArrayList(); // remember not applied attributes
641
Action action = null; // used to insert an action into the macmap
642

643     while (it != null && it.hasNext()) { // loop through all available attributes
644
Attribute attr = (Attribute) it.next();
645
646       if (Parser.ATTR_ID.equals(attr.getName()))
647         continue;
648       if (Parser.ATTR_REFID.equals(attr.getName()))
649         continue;
650       if (Parser.ATTR_USE.equals(attr.getName()))
651         continue;
652
653       if (action != null && attr.getName().startsWith(Parser.ATTR_MACOS_PREFIX)) {
654         mac_map.put(attr.getName(), action);
655         continue;
656       }
657
658       if (JLabel.class.isAssignableFrom(obj.getClass()) && attr.getName().equalsIgnoreCase("LabelFor")) {
659         lbl_map.put(obj, attr.getValue());
660         continue;
661       }
662
663       // using guessSetter allow to not have to care about case when looking at the attribute name.
664
Method method = factory.guessSetter(attr.getName());
665       if (method != null) {
666         //
667
// A setter method has successfully been identified.
668
//
669
Class JavaDoc paraType = method.getParameterTypes()[0];
670         Converter converter = cvtlib.getConverter(paraType);
671
672         if (converter != null) { // call setter with a newly instanced parameter
673
Object JavaDoc para = null;
674           try {
675             //
676
// Actions are provided in the engine's member variables.
677
// a getClass().getFields lookup has to be done to find the correct fields.
678
//
679
if (Action.class.equals(paraType)) {
680               para = engine.getClient().getClass().getField(attr.getValue()).get(engine.getClient());
681               action = (Action) para;
682             } else {
683               para = converter.convert(paraType, attr, engine.getLocalizer());
684             }
685
686             method.invoke(obj, new Object JavaDoc[]{para}); // ATTR SET
687

688           } catch (NoSuchFieldException JavaDoc e) {
689             if (SwingEngine.DEBUG_MODE) {
690               System.err.println("Action '" + attr.getValue() + "' not set. Public Action '" + attr.getValue() + "' not found in " + engine.getClient().getClass().getName());
691             }
692           } catch (InvocationTargetException e) {
693             //
694
// The JFrame class is slightly incompatible with Frame.
695
// Like all other JFC/Swing top-level containers, a JFrame contains a JRootPane as its only child.
696
// The content pane provided by the root pane should, as a rule, contain all the non-menu components
697
// displayed by the JFrame. The JFrame class is slightly incompatible with Frame.
698
//
699
if (obj instanceof RootPaneContainer) {
700               Container rootpane = ((RootPaneContainer) obj).getContentPane();
701               Factory f = engine.getTaglib().getFactory(rootpane.getClass());
702               Method m = f.guessSetter(attr.getName());
703               try {
704                 m.invoke(rootpane, new Object JavaDoc[]{para}); // ATTR SET
705
} catch (Exception JavaDoc ex) {
706                 list.add(attr);
707               }
708             } else {
709               list.add(attr);
710             }
711           } catch (Exception JavaDoc e) {
712             throw new Exception JavaDoc(e + ":" + method.getName() + ":" + para, e);
713           }
714           continue;
715         }
716
717         //
718
// try this: call the setter with an Object.class Type
719
//
720
if (paraType.equals(Object JavaDoc.class)) {
721           try {
722             String JavaDoc s = attr.getValue();
723             if (Parser.LOCALIZED_ATTRIBUTES.contains(attr.getName().toLowerCase()) && attr.getAttributeType() == Attribute.CDATA_TYPE) {
724               s = engine.getLocalizer().getString(s);
725             }
726             method.invoke(obj, new Object JavaDoc[]{s}); // ATTR SET
727
} catch (Exception JavaDoc e) {
728             list.add(attr);
729           }
730           continue;
731         }
732
733         //
734
// try this: call the setter with a primitive
735
//
736
if (paraType.isPrimitive()) {
737           try {
738             method.invoke(obj, new Object JavaDoc[]{PrimitiveConverter.conv(paraType, attr, engine.getLocalizer())}); // ATTR SET
739
} catch (Exception JavaDoc e) {
740             list.add(attr);
741           }
742           continue;
743         }
744         //
745
// try again later
746
//
747
list.add(attr);
748         continue;
749       } else {
750         //
751
// Search for a public field in the obj.class that matches the attribute name
752
//
753
try {
754           Field field = obj.getClass().getField(attr.getName());
755           if (field != null) {
756             Converter converter = cvtlib.getConverter(field.getType());
757             if (converter != null) {
758               //
759
// Localize Strings
760
//
761
Object JavaDoc fieldValue = converter.convert(field.getType(), attr, null);
762               if (String JavaDoc.class.equals(converter.convertsTo())) {
763                 fieldValue = engine.getLocalizer().getString((String JavaDoc) fieldValue);
764               }
765               field.set(obj, fieldValue); // ATTR SET
766
} else {
767               list.add(attr);
768             }
769           } else {
770             list.add(attr);
771           }
772         } catch (Exception JavaDoc e) {
773           list.add(attr);
774         }
775       }
776     } // end_while
777
return list;
778   }
779
780
781   /**
782    * Copies attributes that element doesn't have yet form element[id]
783    *
784    * @param target <code>Element</code> target to receive more attributes
785    */

786   private void cloneAttributes(Element target) {
787     Element source = null;
788     if (target.getAttribute(Parser.ATTR_REFID) != null) {
789       source = find(jdoc.getRootElement(), target.getAttribute(Parser.ATTR_REFID).getValue().trim());
790     } else if (target.getAttribute(Parser.ATTR_USE) != null) {
791       source = find(jdoc.getRootElement(), target.getAttribute(Parser.ATTR_USE).getValue().trim());
792     }
793     if (source != null) {
794       Iterator it = source.getAttributes().iterator();
795       while (it != null && it.hasNext()) {
796         Attribute attr = (Attribute) it.next();
797         String JavaDoc name = attr.getName().trim();
798         //
799
// copy but don't overwrite an attr.
800
// also, don't copy the id attr.
801
//
802
if (!Parser.ATTR_ID.equals(name) && target.getAttribute(name) == null) {
803           Attribute attrcln = (Attribute) attr.clone();
804           attrcln.detach();
805           target.setAttribute(attrcln);
806         }
807       } // end while
808
}
809   }
810
811
812   /**
813    * Adds a child component to a parent component
814    * considering many differences between the Swing containers
815    *
816    * @param parent <code>Component</code>
817    * @param component <code>Component</code> child to be added to the parent
818    * @param constrains <code>Object</code> contraints
819    * @return <code>Component</code> - the passed in component
820    */

821   private static Component addChild(Container parent, Component component, Object JavaDoc constrains) {
822     if (component == null)
823       return null;
824     //
825
// Set a JMenuBar for JFrames, JDialogs, etc.
826
//
827
if (component instanceof JMenuBar) {
828
829       try {
830         Method m = parent.getClass().getMethod("setJMenuBar", new Class JavaDoc[]{JMenuBar.class});
831         m.invoke(parent, new Object JavaDoc[]{component});
832       } catch (NoSuchMethodException JavaDoc e) {
833         parent.add(component);
834       } catch (Exception JavaDoc e) {
835         // intentionally empty
836
}
837  
838     } else if (parent instanceof RootPaneContainer) {
839       //
840
// add component into RootContainr
841
// All Swing top-level containers contain a JRootPane as their only child.
842
// The content pane provided by the root pane should contain all the non-menu components.
843
//
844
RootPaneContainer rpc = (RootPaneContainer) parent;
845       if (component instanceof LayoutManager) {
846         rpc.getContentPane().setLayout((LayoutManager) component);
847       } else {
848         rpc.getContentPane().add(component, constrains);
849       }
850     } else if (parent instanceof JScrollPane) {
851       //
852
// add component into a ScrollPane
853
//
854
JScrollPane scrollPane = (JScrollPane) parent;
855       scrollPane.setViewportView(component);
856     } else if (parent instanceof JSplitPane) {
857       //
858
// add component into a SplitPane
859
//
860
JSplitPane splitPane = (JSplitPane) parent;
861       if (splitPane.getOrientation() == JSplitPane.HORIZONTAL_SPLIT) {
862         //
863
// Horizontal SplitPane
864
//
865
if (splitPane.getTopComponent() == null) {
866           splitPane.setTopComponent(component);
867         } else {
868           splitPane.setBottomComponent(component);
869         }
870       } else {
871         //
872
// Vertical SplitPane
873
//
874
if (splitPane.getLeftComponent() == null) {
875           splitPane.setLeftComponent(component);
876         } else {
877           splitPane.setRightComponent(component);
878         }
879       }
880     } else if (parent instanceof JMenuBar && component instanceof JMenu) {
881       //
882
// add Menu into a MenuBar
883
//
884
JMenuBar menuBar = (JMenuBar) parent;
885       menuBar.add(component, constrains);
886     } else if (JSeparator.class.isAssignableFrom(component.getClass())) {
887       //
888
// add Separator to a Menu, Toolbar or PopupMenu
889
//
890
if (JToolBar.class.isAssignableFrom(parent.getClass()))
891         ((JToolBar) parent).addSeparator();
892       else if (JPopupMenu.class.isAssignableFrom(parent.getClass()))
893         ((JPopupMenu) parent).addSeparator();
894       else if (JMenu.class.isAssignableFrom(parent.getClass()))
895         ((JMenu) parent).addSeparator();
896       else if (constrains != null)
897         parent.add(component, constrains);
898       else
899         parent.add(component);
900
901     } else if (parent instanceof Container) {
902       //
903
// add compontent into container
904
//
905
if (constrains == null) {
906         parent.add(component);
907       } else {
908         parent.add(component, constrains);
909       }
910     }
911     return component;
912   }
913
914
915   /**
916    * Moves the content from the source into the traget <code>Element</code>
917    *
918    * @param source <code>Element</code> Content provider
919    * @param target <code>Element</code> Content receiver
920    */

921   private static void moveContent(Element source, Element target) {
922     List JavaDoc list = source.getContent();
923     while (!list.isEmpty()) {
924       Object JavaDoc obj = list.remove(0);
925       target.getContent().add(obj);
926     }
927   }
928
929   /**
930    * Recursive element by id finder
931    *
932    * @param element <code>Element</code> start node
933    * @param id <code>String</code> id to look for
934    * @return <code>Element</code> - with the given id in the id attribute or null if not found
935    */

936   private static Element find(Element element, String JavaDoc id) {
937     Element elem = null;
938     Attribute attr = element.getAttribute(Parser.ATTR_ID);
939     if (attr != null && id.equals(attr.getValue().trim())) {
940       elem = element;
941     } else {
942       Iterator it = element.getChildren().iterator();
943       while (it != null && it.hasNext() && elem == null) {
944         elem = find((Element) it.next(), id.trim());
945       }
946     }
947     return elem;
948   }
949
950   /**
951    * Recursively adds AbstractButtons into the given
952    *
953    * @param obj <code>Object</code> should be an AbstractButton or JComponent containing AbstractButtons
954    * @param grp <code>ButtonGroup</code>
955    */

956   private static void putIntoBtnGrp(Object JavaDoc obj, ButtonGroup grp) throws Exception JavaDoc {
957     if (AbstractButton.class.isAssignableFrom(obj.getClass())) {
958       grp.add((AbstractButton) obj);
959     } else if (JComponent.class.isAssignableFrom(obj.getClass())) {
960       JComponent jp = (JComponent) obj;
961       for (int i = 0; i < jp.getComponentCount(); i++) {
962         putIntoBtnGrp(jp.getComponent(i), grp);
963       }
964     } // otherwise just do nothing ...
965
}
966 }
967
Popular Tags