001: /* ***** BEGIN LICENSE BLOCK *****
002: * Version: MPL 1.1
003: * The contents of this file are subject to the Mozilla Public License Version
004: * 1.1 (the "License"); you may not use this file except in compliance with
005: * the License. You may obtain a copy of the License at
006: * http://www.mozilla.org/MPL/
007: *
008: * Software distributed under the License is distributed on an "AS IS" basis,
009: * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
010: * for the specific language governing rights and limitations under the
011: * License.
012: *
013: * The Original Code is Riot.
014: *
015: * The Initial Developer of the Original Code is
016: * Neteye GmbH.
017: * Portions created by the Initial Developer are Copyright (C) 2006
018: * the Initial Developer. All Rights Reserved.
019: *
020: * Contributor(s):
021: * Felix Gnass [fgnass at neteye dot de]
022: *
023: * ***** END LICENSE BLOCK ***** */
024: package org.riotfamily.forms;
025:
026: import java.io.PrintWriter;
027: import java.util.ArrayList;
028: import java.util.Iterator;
029: import java.util.List;
030:
031: import org.riotfamily.common.markup.Html;
032: import org.riotfamily.common.markup.TagWriter;
033: import org.riotfamily.forms.request.FormRequest;
034:
035: /**
036: * Abstract superclass for elements that consist of several child elements.
037: * Calls to <code>processRequest()</code> and <code>render()</code> are
038: * automatically delegated to the components. Addionally the components are
039: * initialized, i.e. <code>setParent()</code>, <code>setForm()</code> and
040: * <code>Form.registerElement()</code> are called.
041: */
042: public abstract class CompositeElement extends AbstractEditorBase {
043:
044: private List components = new ArrayList();
045:
046: private boolean surroundBySpan;
047:
048: /**
049: * Empty default constructor.
050: */
051: public CompositeElement() {
052: }
053:
054: protected List getComponents() {
055: return components;
056: }
057:
058: /**
059: * Adds the given element to the list of components. If a form as already
060: * been set {@link #initComponent(Element)} is
061: * invoked, otherwise initialization is deferred until
062: * {@link #setForm(Form)} is called.
063: *
064: * @param element the element to add
065: */
066: protected void addComponent(Element element) {
067: components.add(element);
068: element.setParent(this );
069: if (getForm() != null) {
070: initComponent(element);
071: }
072: }
073:
074: /**
075: * Removes the given component. Note that the element is
076: * not unregistered from the form.
077: */
078: protected void removeComponent(Element element) {
079: components.remove(element);
080: }
081:
082: public boolean isEmpty() {
083: return components.isEmpty();
084: }
085:
086: /**
087: * Invokes <code>initComponent(Element)</code> on all components and
088: * finally calls <code>initCompositeElement()</code>.
089: */
090: protected final void afterFormSet() {
091: Iterator it = components.iterator();
092: while (it.hasNext()) {
093: Element element = (Element) it.next();
094: initComponent(element);
095: }
096: initCompositeElement();
097: }
098:
099: /**
100: * Subclasses may override this method to perform initialization tasks.
101: * A reference to the form will be set at this point and all components
102: * will be initialized.
103: *
104: *The default implementation does nothing.
105: */
106: protected void initCompositeElement() {
107: }
108:
109: /**
110: * Calls <code>processRequestInternal()</code> and afterwards
111: * <code>processRequestComponents()</code> to process the components.
112: */
113: public void processRequest(FormRequest request) {
114: processRequestInternal(request);
115: processRequestCompontents(request);
116: }
117:
118: /**
119: * Processes the request for all the components
120: */
121: protected void processRequestCompontents(FormRequest request) {
122: // Temporary list to allow concurrent modification
123: List tempList = new ArrayList(components);
124: Iterator it = tempList.iterator();
125: while (it.hasNext()) {
126: Element element = (Element) it.next();
127: log.debug("Processing component: " + element);
128: element.processRequest(request);
129: }
130: }
131:
132: /**
133: * Sets a reference to the form and registers the element by calling
134: * {@link Form#registerElement(Element)}.
135: *
136: * @throws IllegalStateException if form is null
137: */
138: protected void initComponent(Element element) {
139: if (getForm() == null) {
140: throw new IllegalStateException("Form not set");
141: }
142: getForm().registerElement(element);
143: }
144:
145: /**
146: * Called before processRequest() is invoked on the contained elements.
147: * Subclasses can override this method to perform custom processing. The
148: * default implementation does nothing.
149: */
150: protected void processRequestInternal(FormRequest request) {
151: }
152:
153: protected boolean isSurroundBySpan() {
154: return this .surroundBySpan;
155: }
156:
157: protected void setSurroundBySpan(boolean surroundBySpan) {
158: this .surroundBySpan = surroundBySpan;
159: }
160:
161: protected void renderInternal(PrintWriter writer) {
162: if (surroundBySpan) {
163: TagWriter spanTag = new TagWriter(writer);
164: spanTag.start(Html.SPAN).attribute(Html.COMMON_ID, getId())
165: .body();
166: renderComponents(writer);
167: spanTag.end();
168: } else {
169: renderComponents(writer);
170: }
171: }
172:
173: protected void renderComponents(PrintWriter writer) {
174: Iterator it = components.iterator();
175: while (it.hasNext()) {
176: Element element = (Element) it.next();
177: log.debug("Rendering component " + element);
178: element.render(writer);
179: }
180: }
181:
182: /**
183: * Delegates the call to the first component.
184: */
185: public void focus() {
186: if (!components.isEmpty()) {
187: ((Element) components.get(0)).focus();
188: }
189: }
190:
191: /**
192: * Helper method to check for composite elements in templates.
193: * Always returns <code>true</code>
194: */
195: public boolean isCompositeElement() {
196: return true;
197: }
198: }
|