001: /*
002: * Copyright 2000,2005 wingS development team.
003: *
004: * This file is part of wingS (http://wingsframework.org).
005: *
006: * wingS is free software; you can redistribute it and/or modify
007: * it under the terms of the GNU Lesser General Public License
008: * as published by the Free Software Foundation; either version 2.1
009: * of the License, or (at your option) any later version.
010: *
011: * Please see COPYING for the complete licence.
012: */
013: package org.wings;
014:
015: import org.wings.template.*;
016: import org.wings.template.propertymanagers.SAbstractButtonPropertyManager;
017: import org.wings.template.propertymanagers.SAbstractIconTextCompoundPropertyManager;
018: import org.wings.template.propertymanagers.SComponentPropertyManager;
019: import org.wings.template.propertymanagers.SListPropertyManager;
020: import org.wings.template.propertymanagers.SLabelPropertyManager;
021: import org.wings.template.propertymanagers.STextFieldPropertyManager;
022: import org.wings.template.propertymanagers.STablePropertyManager;
023: import org.wings.template.propertymanagers.SFileChooserPropertyManager;
024: import org.wings.template.propertymanagers.STextAreaPropertyManager;
025: import org.wings.template.parser.PageParser;
026:
027: import java.io.File;
028: import java.net.URL;
029: import java.util.HashMap;
030: import java.util.Iterator;
031: import java.util.Map;
032:
033: /**
034: * Static layout manager that uses template files to arrange components.
035: * <p/>
036: * Like any other layout manager it allows to place arbitrary elements, but you can
037: * write a simple HTML-page being the template for your container component.
038: * Though we encourage the use of the dynamic layout managers, this layout manager can be
039: * very useful in realising the main page layout of your web application.
040: * <p/>
041: * To use this layout manager you have to define a template file required by the STemplateLayout
042: * instance. Inside this template file you can insert inside your custom HTML code desired
043: * wingS objects using tags like
044: * <p/>
045: * <code><input name="compname"></code>
046: * <p/> or
047: * <p/><code><object name="compname"></object></code>
048: * <p/>
049: * The name attribute of these <code>input</code> or <code>object</code> tag is the name
050: * you have to use as layout <em>constraint</em> when you add the desired component to the
051: * template layout managed {@link SContainer}:
052: * <p/><code>panel.add(new SLabel("a test label), "compname"));</code>
053: * <p/>
054: * Besides this simple inlining mechanism the STemplateLayout manager has also another
055: * very powerful feature: <b>Specific components bean attributes can be overwritten</b> by
056: * specific optional inline attributes attached to your <code>object</code> html tags i.e. like
057: * <p/><code><object name="compname" background="#ff0000" text="new text"></object></code><p/>
058: * Please refer to javadoc of {@link PropertyManager} for more information on this feature.
059: * <p/>
060: * <b>Sample template file:</b><br/>
061: * <CODE>
062: * <HTML><BODY>
063: * Name der Person: <COMPONENT NAME=NAME><BR>
064: * Vorname der Person: <COMPONENT NAME=VORNAME ICON="vorname.gif"><BR>
065: * Wohnort der Person: <COMPONENT NAME=WOHNORT><BR>
066: * </BODY></HTML>
067: * </CODE>
068: * <BR>
069: * <b>According java sample code:</b>:<BR>
070: * <CODE>
071: * templateContainer.setLayout(new STemplateLayout("templatefile"));
072: * templateContainer.addComponent(new SLabel("Haaf"), "NAME");
073: * templateContainer.addComponent(new SButton("Armin"), "VORNAME");
074: * templateContainer.addComponent(new SLabel("Neu-Ulm"), "WOHNORT");
075: * </CODE>
076: *
077: * @see PropertyManager
078: * @author <a href="mailto:haaf@mercatis.de">Armin Haaf</a>
079: * @author Jochen Woehrle
080: * @author <a href="mailto:H.Zeller@acm.org">Henner Zeller</a>
081: */
082: public class STemplateLayout extends SAbstractLayoutManager {
083: /*
084: * Dieser PropertyManager behandelt alle Properties, zu denen kein eigener
085: * PropertyManager gefunden wurde.
086: */
087: private static final PropertyManager defaultPropertyManager = new PropertyManager() {
088: final Class[] empty = new Class[0];
089:
090: public void setProperty(SComponent c, String name, String value) {
091: }
092:
093: public Class[] getSupportedClasses() {
094: return empty;
095: }
096: };
097:
098: /*
099: * Alle Property Manager
100: */
101: private static final HashMap propertyManager = new HashMap();
102:
103: /*
104: * some default property Managers. Sets properties of components
105: * from parameters given in the template page.
106: */
107: static {
108: addPropertyManager(new SComponentPropertyManager());
109: addPropertyManager(new SAbstractIconTextCompoundPropertyManager());
110: addPropertyManager(new SAbstractButtonPropertyManager());
111: addPropertyManager(new SLabelPropertyManager());
112: addPropertyManager(new STextFieldPropertyManager());
113: addPropertyManager(new STextAreaPropertyManager());
114: addPropertyManager(new STablePropertyManager());
115: addPropertyManager(new SFileChooserPropertyManager());
116: addPropertyManager(new SListPropertyManager());
117: }
118:
119: /**
120: * Abstraction of the template source (file, resource, ..)
121: */
122: protected HashMap components = new HashMap();
123:
124: private TemplateSource templateSource = null;
125:
126: /**
127: * PageParser to use
128: */
129: protected transient PageParser pageParser;
130:
131: public STemplateLayout() {
132: }
133:
134: /**
135: * Create a TemplateLayout that reads its content from the generic
136: * {@link TemplateSource}. The template source can be implemented
137: * to be read from any source you want to, e.g. database BLOBs. Whenever
138: * the source changes (i.e. lastModified() returns a different
139: * modification time the last time this source has been parsed), the
140: * template is reparsed.
141: *
142: * @param source the TemplateSource this template is to be read from.
143: */
144: public STemplateLayout(TemplateSource source) {
145: setTemplate(source);
146: }
147:
148: /**
149: * Open a template from a file with the given name.
150: * Whenever the file changes, the Template is reloaded.
151: *
152: * @param tmplFileName the filename to read the file from.
153: * @throws java.io.IOException
154: */
155: public STemplateLayout(String tmplFileName)
156: throws java.io.IOException {
157: setTemplate(new File(tmplFileName));
158: }
159:
160: /**
161: * Read the template from a file.
162: * Open a template from a file.
163: * Whenever the file changes, the Template is reloaded.
164: *
165: * @param tmplFile the File to read the template from.
166: * @throws java.io.IOException
167: */
168: public STemplateLayout(File tmplFile) throws java.io.IOException {
169: setTemplate(tmplFile);
170: }
171:
172: /**
173: * Read the template from an URL.
174: * The content is cached.
175: *
176: * @param url the URL to read the template from.
177: * @throws java.io.IOException
178: */
179: public STemplateLayout(URL url) throws java.io.IOException {
180: setTemplate(url);
181: }
182:
183: /**
184: * Determines appropriate property manager for the given SComponent or
185: * derived class. Goes up the hierarchy.
186: */
187: public static final PropertyManager getPropertyManager(Class c) {
188: if (c == null)
189: return defaultPropertyManager;
190:
191: PropertyManager p = (PropertyManager) propertyManager.get(c);
192:
193: if (p == null)
194: return getPropertyManager(c.getSuperclass());
195:
196: return p;
197: }
198:
199: /**
200: * Adds a PropertyManager.
201: * A Property Manager provides a mapping from properties given in
202: * template tags to properties of components.
203: * PropertyManager are responsible for a number of component classes; if
204: * there is already a mapping for a certain class, then this mapping
205: * is <em>not</em> added.
206: */
207: public static final void addPropertyManager(PropertyManager p) {
208: if (p == null)
209: return;
210:
211: Class[] cl = p.getSupportedClasses();
212: if (cl == null)
213: return;
214:
215: for (int i = 0; i < cl.length; i++) {
216: if (!propertyManager.containsKey(cl[i]))
217: propertyManager.put(cl[i], p);
218: }
219: }
220:
221: /**
222: * Deregisters a property manager for a given component class to be able to replace it.
223: * @param supportedComponentClass Target class as in {@link org.wings.template.PropertyManager#getSupportedClasses()}
224: */
225: public static final PropertyManager removePropertyManager(
226: Class supportedComponentClass) {
227: if (supportedComponentClass == null)
228: return null;
229: return (PropertyManager) propertyManager
230: .remove(supportedComponentClass);
231: }
232:
233: /**
234: * Set the template to the template given as file name.
235: *
236: * @throws java.io.IOException
237: */
238: public void setTemplate(String templateFileName)
239: throws java.io.IOException {
240: setTemplate(new File(templateFileName));
241: }
242:
243: /**
244: * Set the template to the template stored in the given file.
245: *
246: * @throws java.io.IOException
247: */
248: public void setTemplate(File templateFile)
249: throws java.io.IOException {
250: setTemplate(new CachedFileTemplateSource(templateFile));
251: }
252:
253: /**
254: * Set the template to the template which can be retrieved from the
255: * given URL.
256: *
257: * @throws java.io.IOException
258: */
259: public void setTemplate(URL templateURL) throws java.io.IOException {
260: if ("file".equals(templateURL.getProtocol())) {
261: setTemplate(new File(templateURL.getFile()));
262: } else {
263: setTemplate(new CachedFileTemplateSource(templateURL));
264: }
265: }
266:
267: /**
268: * Sets the template from the DataSource. Use this, if you hold your
269: * templates in databases etc. and write your own DataSource.
270: *
271: * @param source the source this template is to be read.
272: * @see org.wings.template.TemplateSource
273: */
274: public void setTemplate(TemplateSource source) {
275: templateSource = source;
276: }
277:
278: /**
279: * add a component with the given constraint. The contstraint in the
280: * TemplateLayout is the value of the name attribute of the object in
281: * the HTML-template.
282: *
283: * @param c the component to be added
284: * @param constraint the string describing the
285: */
286: public void addComponent(SComponent c, Object constraint, int index) {
287: if (constraint == null)
288: throw new IllegalArgumentException(
289: "null constraint not allowed here");
290: components.put(constraint.toString(), c);
291: }
292:
293: /**
294: * removes the given component.
295: *
296: * @param comp the component to be removed.
297: */
298: public void removeComponent(SComponent comp) {
299: Iterator it = components.entrySet().iterator();
300: while (it.hasNext()) {
301: Map.Entry e = (Map.Entry) it.next();
302: if (e.getValue() == comp)
303: it.remove();
304: }
305: }
306:
307: /**
308: * returns a map of the constraint/component.
309: */
310: public SComponent getComponent(String name) {
311: return (SComponent) components.get(name);
312: }
313:
314: /**
315: * Returns the source of the template layout.
316: * @see #setTemplate(TemplateSource)
317: * @return the template source
318: */
319: public TemplateSource getTemplateSource() {
320: return templateSource;
321: }
322:
323: /**
324: * Retrieve the PageParser of this instance
325: *
326: * @return the current PageParser
327: */
328: public PageParser getPageParser() {
329: return pageParser != null ? pageParser : PageParser
330: .getInstance();
331: }
332:
333: /**
334: * Set the PageParser for this instance
335: *
336: * @param pageParser the new PageParser
337: */
338: public void setPageParser(PageParser pageParser) {
339: this.pageParser = pageParser;
340: }
341: }
|