001: /**
002: * Copyright 2006 Webmedia Group Ltd.
003: *
004: * Licensed under the Apache License, Version 2.0 (the "License");
005: * you may not use this file except in compliance with the License.
006: * You may obtain a copy of the License at
007: *
008: * http://www.apache.org/licenses/LICENSE-2.0
009: *
010: * Unless required by applicable law or agreed to in writing, software
011: * distributed under the License is distributed on an "AS IS" BASIS,
012: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013: * See the License for the specific language governing permissions and
014: * limitations under the License.
015: **/package org.araneaframework.uilib.form;
016:
017: import java.util.Iterator;
018: import java.util.Map;
019: import org.apache.commons.collections.map.LinkedMap;
020: import org.araneaframework.Environment;
021: import org.araneaframework.Widget;
022: import org.araneaframework.core.AraneaRuntimeException;
023: import org.araneaframework.core.Assert;
024: import org.araneaframework.core.StandardEnvironment;
025: import org.araneaframework.framework.MessageContext;
026: import org.araneaframework.uilib.InvalidFormElementNameException;
027: import org.araneaframework.uilib.form.visitor.FormElementVisitor;
028: import org.araneaframework.uilib.list.util.NestedFormUtil;
029: import org.araneaframework.uilib.util.NameUtil;
030:
031: /**
032: * This class represents a form element that can contain other form elements.
033: *
034: * @author Jevgeni Kabanov (ekabanov <i>at</i> araneaframework <i>dot</i> org)
035: */
036: public class FormWidget extends GenericFormElement implements
037: FormContext {
038: //*******************************************************************
039: // FIELDS
040: //*******************************************************************
041: protected LinkedMap elements = new LinkedMap();
042:
043: //*********************************************************************
044: //* INTERNAL METHODS
045: //*********************************************************************
046:
047: protected void init() throws Exception {
048: super .init();
049:
050: for (Iterator i = getElements().entrySet().iterator(); i
051: .hasNext();) {
052: Map.Entry element = (Map.Entry) i.next();
053: addWidget(element.getKey(), (Widget) element.getValue());
054: }
055: }
056:
057: //*********************************************************************
058: //* PUBLIC METHODS
059: //*********************************************************************
060:
061: protected Environment getChildWidgetEnvironment() throws Exception {
062: return new StandardEnvironment(super
063: .getChildWidgetEnvironment(), FormContext.class, this );
064: }
065:
066: public void clearErrors() {
067: getMessageCtx().hideMessages(MessageContext.ERROR_TYPE,
068: getErrors());
069: super .clearErrors();
070: for (Iterator i = getElements().values().iterator(); i
071: .hasNext();) {
072: ((GenericFormElement) i.next()).clearErrors();
073: }
074: }
075:
076: public boolean isValid() {
077: boolean result = super .isValid();
078:
079: for (Iterator i = getElements().values().iterator(); i
080: .hasNext();) {
081: if (!result)
082: break;
083: result &= ((GenericFormElement) i.next()).isValid();
084: }
085:
086: return result;
087: }
088:
089: /**
090: * Returns a contained element by its name.
091: *
092: * @param elementName contained element name
093: * @return a contained element by its name.
094: */
095: public GenericFormElement getElement(String elementName) {
096: if (elementName.indexOf('.') == -1)
097: return (GenericFormElement) elements.get(elementName);
098: return getGenericElementByFullName(elementName);
099: }
100:
101: /**
102: * Adds a contained element with given id after the element with specified id.
103: *
104: * @param id added element id
105: * @param element added element
106: * @param afterId element id after which contained element should be added
107: */
108: public void addElementAfter(String id, GenericFormElement element,
109: String afterId) {
110: Assert.notEmptyParam(id, "id");
111: Assert.notEmptyParam(afterId, "afterId");
112: Assert.notNullParam(element, "element");
113: Assert
114: .isTrue(id.indexOf(".") == -1,
115: "addElementAfter() does not accept nested 'id' parameter..");
116:
117: FormWidget form = NestedFormUtil.getDeepestForm(afterId, this );
118:
119: // form is now the actual form to add element into
120: form.addFlatElementAfter(id, element, NameUtil
121: .getShortestSuffix(afterId));
122: }
123:
124: /**
125: * Adds a contained element with given id before the element with specified id.
126: * Should be only used in RARE cases where internal order of elements matters for some reason.
127: *
128: * @param id added element id
129: * @param element added element
130: * @param beforeId element id before which contained element should be added
131: */
132: public void addElementBefore(String id, GenericFormElement element,
133: String beforeId) {
134: Assert.notEmptyParam(id, "id");
135: Assert.notEmptyParam(beforeId, "beforeId");
136: Assert.notNullParam(element, "element");
137: Assert
138: .isTrue(id.indexOf(".") == -1,
139: "addElementBefore() does not accept nested 'id' parameter.");
140:
141: FormWidget form = NestedFormUtil.getDeepestForm(beforeId, this );
142:
143: // form is now the actual form to add element into
144: form.addFlatElementBefore(id, element, NameUtil
145: .getShortestSuffix(beforeId));
146: }
147:
148: private void addFlatElementAfter(String id,
149: GenericFormElement element, String afterId) {
150: Assert
151: .isTrue(afterId.indexOf(".") == -1,
152: "addFlatElementAfter() method does not accept nested 'afterId'");
153: LinkedMap newElements = new LinkedMap();
154:
155: if (!getElements().containsKey(afterId))
156: throw new AraneaRuntimeException("The element '" + afterId
157: + "' does not exist!");
158:
159: for (Iterator i = elements.entrySet().iterator(); i.hasNext();) {
160: Map.Entry entry = (Map.Entry) i.next();
161:
162: newElements.put(entry.getKey(), entry.getValue());
163: if (entry.getKey().equals(afterId)) {
164: newElements.put(id, element);
165: }
166: }
167:
168: if (isInitialized())
169: addWidget(id, element);
170:
171: elements = newElements;
172: }
173:
174: private void addFlatElementBefore(String id,
175: GenericFormElement element, String beforeId) {
176: Assert
177: .isTrue(beforeId.indexOf(".") == -1,
178: "addFlatElementBefore() method does not accept nested 'afterId'");
179: LinkedMap newElements = new LinkedMap();
180:
181: if (!elements.containsKey(beforeId))
182: throw new AraneaRuntimeException("The element '" + beforeId
183: + "' does not exist!");
184:
185: for (Iterator i = elements.entrySet().iterator(); i.hasNext();) {
186: Map.Entry entry = (Map.Entry) i.next();
187:
188: if (entry.getKey().equals(beforeId))
189: newElements.put(id, element);
190: newElements.put(entry.getKey(), entry.getValue());
191: }
192:
193: if (isInitialized())
194: addWidget(id, element);
195:
196: elements = newElements;
197: }
198:
199: /**
200: * Adds a contained element.
201: *
202: * @param element contained element.
203: * @param id element id
204: */
205: public void addElement(String id, GenericFormElement element) {
206: Assert.notEmptyParam(id, "id");
207: Assert.notNullParam(element, "element");
208:
209: if (id.indexOf(".") != -1) {
210: NestedFormUtil.addElement(this , id, element);
211: } else {
212: elements.put(id, element);
213:
214: if (isInitialized())
215: addWidget(id, element);
216: }
217: }
218:
219: /**
220: * Removes a contained element by its name.
221: */
222: public void removeElement(String id) {
223: Assert.notEmptyParam(id, "id");
224:
225: elements.remove(id);
226:
227: if (isInitialized())
228: removeWidget(id);
229: }
230:
231: /**
232: * Returns elements.
233: * @return elements.
234: */
235: public Map getElements() {
236: return new LinkedMap(elements);
237: }
238:
239: /**
240: * Calls {@link GenericFormElement#convert()} for all contained elements.
241: */
242: protected void convertInternal() throws Exception {
243: for (Iterator i = elements.values().iterator(); i.hasNext();) {
244: ((GenericFormElement) i.next()).convert();
245: }
246: }
247:
248: /**
249: * Controls that the constraints and all subcontrols are valid.
250: */
251: protected boolean validateInternal() throws Exception {
252: for (Iterator i = elements.values().iterator(); i.hasNext();)
253: ((GenericFormElement) i.next()).validate();
254:
255: return super .validateInternal();
256: }
257:
258: public void markBaseState() {
259: for (Iterator i = elements.values().iterator(); i.hasNext();)
260: ((GenericFormElement) i.next()).markBaseState();
261: }
262:
263: public void restoreBaseState() {
264: for (Iterator i = elements.values().iterator(); i.hasNext();)
265: ((GenericFormElement) i.next()).restoreBaseState();
266: }
267:
268: public boolean isStateChanged() {
269: boolean result = false;
270: for (Iterator i = elements.values().iterator(); i.hasNext();)
271: result |= ((GenericFormElement) i.next()).isStateChanged();
272: return result;
273: }
274:
275: public void setDisabled(boolean disabled) {
276: for (Iterator i = elements.values().iterator(); i.hasNext();)
277: ((GenericFormElement) i.next()).setDisabled(disabled);
278: }
279:
280: public boolean isDisabled() {
281: boolean result = false;
282: for (Iterator i = elements.values().iterator(); i.hasNext();)
283: result &= ((GenericFormElement) i.next()).isDisabled();
284: return result;
285: }
286:
287: public void accept(String id, FormElementVisitor visitor) {
288: visitor.visit(id, this );
289:
290: visitor.pushContext(id, this );
291:
292: for (Iterator i = elements.entrySet().iterator(); i.hasNext();) {
293: Map.Entry entry = (Map.Entry) i.next();
294:
295: String elementId = (String) entry.getKey();
296: GenericFormElement element = (GenericFormElement) entry
297: .getValue();
298:
299: element.accept(elementId, visitor);
300: }
301:
302: visitor.popContext();
303: }
304:
305: //*********************************************************************
306: //* ELEMENT CREATION AND ADDITION
307: //*********************************************************************
308:
309: /**
310: * Adds a new subform to this {@link FormWidget}.
311: * @param id subform id.
312: *
313: * @return created subform
314: */
315: public FormWidget addSubForm(String id) {
316: Assert.notEmptyParam(id, "id");
317:
318: FormWidget result = new FormWidget();
319: addElement(id, result);
320: return result;
321: }
322:
323: /**
324: * This method makes a {@link FormElement} with given {@link Control} and {@link Data}.
325: *
326: * @param labelId localized label id
327: * @param control the type of control
328: * @param data the type of data
329: * @param initialValue initial value for data
330: * @param mandatory whether the element must be filled in
331: * @return {@link FormElement} with given configuration
332: */
333: public FormElement createElement(String labelId, Control control,
334: Data data, Object initialValue, boolean mandatory) {
335: if (data != null)
336: data.setValue(initialValue);
337: return createElement(labelId, control, data, mandatory);
338: }
339:
340: /**
341: * This method makes a {@link FormElement} with given {@link Control} and {@link Data}.
342: *
343: * @param labelId id of the localized label.
344: * @param control the type of control data.
345: * @param data the type of data.
346: * @param mandatory whether the element must be present in request.
347: * @return {@link FormElement} with given configuration
348: */
349: public FormElement createElement(String labelId, Control control,
350: Data data, boolean mandatory) {
351: Assert.notNullParam(control, "control");
352:
353: FormElement result = new FormElement();
354:
355: result.setLabel(labelId);
356: result.setMandatory(mandatory);
357: result.setLabel(labelId);
358: result.setControl(control);
359: if (data != null) {
360: result.setData(data);
361: }
362: return result;
363: }
364:
365: /**
366: * This method adds a {@link FormElement} to this {@link FormWidget}.
367: *
368: * @param elementName the name of the form element.
369: * @param labelId id of the localized label.
370: * @param control the type of control data.
371: * @param data the type of data.
372: * @param mandatory whether the element must be present in request.
373: */
374: public FormElement addElement(String elementName, String labelId,
375: Control control, Data data, boolean mandatory) {
376: FormElement result = createElement(labelId, control, data,
377: mandatory);
378: addElement(elementName, result);
379: return result;
380: }
381:
382: /**
383: * This method adds a {@link FormElement} to this {@link FormWidget}.
384: *
385: * @param elementName the name of the form element.
386: * @param labelId id of the localized label.
387: * @param control the type of control data.
388: * @param data the type of data.
389: * @param mandatory whether the element must be present in request.
390: */
391: public FormElement addElement(String elementName, String labelId,
392: Control control, Data data, Object initialValue,
393: boolean mandatory) {
394: FormElement result = createElement(labelId, control, data,
395: initialValue, mandatory);
396: addElement(elementName, result);
397: return result;
398: }
399:
400: //*********************************************************************
401: //* TRAVERSAL METHODS
402: //*********************************************************************
403:
404: /**
405: * Returns form element specified by full name.
406: * @param fullName The full dot-separated name of the form element.
407: * @return form element specified by full name.
408: */
409: public GenericFormElement getGenericElementByFullName(
410: String fullName) {
411: Assert.notEmptyParam(fullName, "fullName");
412:
413: GenericFormElement result = null;
414:
415: String currentElementName = NameUtil.getNamePrefix(fullName);
416: String nextElementNames = NameUtil.getNameSuffix(fullName);
417:
418: if ("".equals(nextElementNames)) {
419: result = getElement(currentElementName);
420: } else {
421: FormWidget nextElement = (FormWidget) getElement(currentElementName);
422:
423: if (nextElement == null)
424: return null;
425:
426: result = nextElement
427: .getGenericElementByFullName(nextElementNames);
428: }
429:
430: return result;
431: }
432:
433: /**
434: * Returns simple form element specified by full name.
435: * @param fullName The full dot-separated name of the form element.
436: * @return simple form element specified by full name.
437: */
438: public FormElement getElementByFullName(String fullName) {
439: return (FormElement) getGenericElementByFullName(fullName);
440: }
441:
442: /**
443: * Returns simple form element specified by full name.
444: * @param fullName The full dot-separated name of the form element.
445: * @return simple form element specified by full name.
446: */
447: public FormWidget getSubFormByFullName(String fullName) {
448: return (FormWidget) getGenericElementByFullName(fullName);
449: }
450:
451: /**
452: * Returns composite form element specified by full name.
453: * @param fullName The full dot-separated name of the form element.
454: * @return composite form element specified by full name.
455: */
456: public Control getControlByFullName(String fullName) {
457: FormElement el = getElementByFullName(fullName);
458: return (el == null) ? null : el.getControl();
459: }
460:
461: /**
462: * Returns form element value specified by full name.
463: * @param fullName The full dot-separated name of the form element.
464: * @return form element value specified by full name.
465: */
466: public Object getValueByFullName(String fullName) {
467: FormElement el = getElementByFullName(fullName);
468: return (el == null) ? null : el.getValue();
469: }
470:
471: /**
472: * Sets form element value specified by full name.
473: * @param fullName The full dot-separated name of the form element.
474: * @param value form element value specified by full name.
475: */
476: public void setValueByFullName(String fullName, Object value) {
477: FormElement el = getElementByFullName(fullName);
478:
479: if (el == null)
480: throw new InvalidFormElementNameException(fullName);
481:
482: el.getData().setValue(value);
483: }
484:
485: public void addError(String error) {
486: super .addError(error);
487: getMessageCtx().showErrorMessage(error);
488: }
489:
490: /**
491: * Returns {@link ViewModel}.
492: * @return {@link ViewModel}.
493: */
494: public Object getViewModel() {
495: return new ViewModel();
496: }
497:
498: //*********************************************************************
499: //* VIEW MODEL
500: //*********************************************************************
501:
502: /**
503: * Represents a composite form element view model.
504: *
505: * @author Jevgeni Kabanov (ekabanov <i>at</i> araneaframework <i>dot</i> org)
506: *
507: */
508: public class ViewModel extends GenericFormElement.ViewModel {
509: /**
510: * Returns the <code>Map</code> with element views.
511: * @return the <code>Map</code> with element views.
512: */
513: public Map getElements() {
514: return getChildren();
515: }
516: }
517: }
|