001: /* XmlMacroComponent.java
002:
003: {{IS_NOTE
004: Purpose:
005:
006: Description:
007:
008: History:
009: Thu Aug 23 17:05:31 2007, Created by tomyeh
010: }}IS_NOTE
011:
012: Copyright (C) 2007 Potix Corporation. All Rights Reserved.
013:
014: {{IS_RIGHT
015: This program is distributed under GPL Version 2.0 in the hope that
016: it will be useful, but WITHOUT ANY WARRANTY.
017: }}IS_RIGHT
018: */
019: package org.zkoss.zml;
020:
021: import java.util.Map;
022: import java.util.LinkedHashMap;
023:
024: import org.zkoss.lang.Objects;
025: import org.zkoss.io.Serializables;
026:
027: import org.zkoss.zk.ui.Executions;
028: import org.zkoss.zk.ui.Execution;
029: import org.zkoss.zk.ui.Page;
030: import org.zkoss.zk.ui.Component;
031: import org.zkoss.zk.ui.AbstractComponent;
032: import org.zkoss.zk.ui.WrongValueException;
033: import org.zkoss.zk.ui.ext.Macro;
034:
035: /**
036: * The implemetation of a macro component for XML output.
037: *
038: * @author tomyeh
039: * @since 3.0.0
040: */
041: public class XmlMacroComponent extends AbstractComponent implements
042: Macro {
043: private transient Map _props;
044: private String _uri;
045: /** An array of components created by this inline macro.
046: * It is used only if {@link #isInline}
047: */
048: private Component[] _inlines;
049:
050: public XmlMacroComponent() {
051: init();
052: }
053:
054: private void init() {
055: _props = new LinkedHashMap();
056: _props.put("includer", this );
057: }
058:
059: //-- Macro --//
060: /** Creates the child components after apply dynamic properties
061: * {@link #setDynamicProperty}.
062: *
063: * <p>The second invocation is ignored. If you want to recreate
064: * child components, use {@link #recreate} instead.
065: *
066: * <p>If a macro component is created by ZK loader, this method is invoked
067: * automatically. Developers need to invoke this method only if they create
068: * a macro component manually.
069: *
070: * <p>If this is an line macro, this method is invoked automatically
071: * if {@link #setParent} or {@link #setPage} called
072: */
073: public void afterCompose() {
074: final Execution exec = Executions.getCurrent();
075: if (exec == null)
076: throw new IllegalStateException("No execution available.");
077:
078: if (isInline()) {
079: if (_inlines != null)
080: return; //don't do twice
081:
082: _inlines = exec.createComponents(_uri != null ? _uri
083: : getDefinition().getMacroURI(), _props);
084: //Note: it doesn't belong to any page/component
085: } else {
086: if (!getChildren().isEmpty())
087: return; //don't do twice (silently)
088:
089: exec.createComponents(_uri != null ? _uri : getDefinition()
090: .getMacroURI(), this , _props);
091: }
092: }
093:
094: public void setMacroURI(String uri) {
095: if (!Objects.equals(_uri, uri)) {
096: if (uri != null && uri.length() == 0)
097: throw new IllegalArgumentException("empty uri");
098: _uri = uri;
099: recreate();
100: }
101: }
102:
103: public void recreate() {
104: if (_inlines != null) {
105: for (int j = 0; j < _inlines.length; ++j)
106: _inlines[j].detach();
107: _inlines = null;
108: } else {
109: getChildren().clear();
110: }
111: afterCompose();
112: }
113:
114: public boolean isInline() {
115: return getDefinition().isInlineMacro();
116: }
117:
118: //Component//
119: /** Changes the parent.
120: *
121: * <p>Note: if this is an inline macro ({@link #isInline}),
122: * this method actually changes the parent of all components created
123: * from the macro URI.
124: * In other word, an inline macro behaves like a controller of
125: * the components it created. It doesn't belong to any page or parent.
126: * Moreover, {@link #afterCompose} is called automatically if
127: * it is not called (and this is an inline macro).
128: */
129: public void setParent(Component parent) {
130: if (isInline()) {
131: if (_inlines == null)
132: afterCompose(); //autocreate
133:
134: for (int j = 0; j < _inlines.length; ++j)
135: _inlines[j].setParent(parent);
136: } else {
137: super .setParent(parent);
138: }
139: }
140:
141: /** Changes the page.
142: *
143: * <p>Note: if this is an inline macro ({@link #isInline}),
144: * this method actually changes the page of all components created
145: * from the macro URI.
146: * In other word, an inline macro behaves like a controller of
147: * the components it created. It doesn't belong to any page or parent.
148: * Moreover, {@link #afterCompose} is called automatically if
149: * it is not called (and this is an inline macro).
150: */
151: public void setPage(Page page) {
152: if (isInline()) {
153: if (_inlines == null)
154: afterCompose(); //autocreate
155:
156: for (int j = 0; j < _inlines.length; ++j)
157: _inlines[j].setPage(page);
158: } else {
159: super .setPage(page);
160: }
161: }
162:
163: public boolean isChildable() {
164: return !isInline();
165: }
166:
167: //Serializable//
168: //NOTE: they must be declared as private
169: private synchronized void writeObject(java.io.ObjectOutputStream s)
170: throws java.io.IOException {
171: s.defaultWriteObject();
172:
173: _props.remove("includer");
174: Serializables.smartWrite(s, _props);
175: _props.put("includer", this );
176: }
177:
178: private synchronized void readObject(java.io.ObjectInputStream s)
179: throws java.io.IOException, ClassNotFoundException {
180: s.defaultReadObject();
181: init();
182: Serializables.smartRead(s, _props);
183: }
184:
185: //Cloneable//
186: public Object clone() {
187: final XmlMacroComponent clone = (XmlMacroComponent) super
188: .clone();
189: clone.init();
190: clone._props.putAll(_props);
191: clone._props.put("includer", this );
192:
193: if (_inlines != null) { //deep clone
194: clone._inlines = new Component[_inlines.length];
195: for (int j = 0; j < _inlines.length; ++j)
196: clone._inlines[j] = (Component) _inlines[j].clone();
197: }
198: return clone;
199: }
200:
201: //-- DynamicPropertied --//
202: public boolean hasDynamicProperty(String name) {
203: return _props.containsKey(name);
204: }
205:
206: public Object getDynamicProperty(String name) {
207: return _props.get(name);
208: }
209:
210: public void setDynamicProperty(String name, Object value)
211: throws WrongValueException {
212: _props.put(name, value);
213: }
214: }
|