001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: */
017: package org.apache.cocoon.forms.formmodel;
018:
019: import org.apache.cocoon.forms.FormContext;
020: import org.apache.cocoon.forms.FormsRuntimeException;
021: import org.apache.cocoon.forms.event.ValueChangedEvent;
022: import org.apache.cocoon.forms.event.ValueChangedListener;
023: import org.apache.cocoon.forms.event.ValueChangedListenerEnabled;
024:
025: import org.apache.commons.lang.ObjectUtils;
026:
027: /**
028: * A discriminated union that references a discriminant value in another
029: * widget and contains one of several cases (widgets). To have a case
030: * hold more than one widget or to use a different id for the case than
031: * for the widget id, just wrap the widget(s) in a container widget named
032: * with the desired case id.
033: *
034: * @version $Id: Union.java 462520 2006-10-10 19:39:14Z vgritsenko $
035: */
036: public class Union extends AbstractContainerWidget {
037:
038: //Note: union instances behave like simple "field" instance with respect to
039: // XSLT post-processing, the choice of element-name reflects this.
040: private static final String UNION_EL = "field";
041:
042: private Widget caseWidget;
043: protected String caseValue;
044:
045: private final UnionDefinition definition;
046:
047: public Union(UnionDefinition definition) {
048: super (definition);
049: this .definition = definition;
050: // TODO: Remove after moving logic to Field.
051: //item.enteredValue = (String)definition.getDefaultValue();
052: }
053:
054: public WidgetDefinition getDefinition() {
055: return definition;
056: }
057:
058: /**
059: * Called after widget's environment has been setup,
060: * to allow for any contextual initalization such as
061: * looking up case widgets for union widgets.
062: */
063: public void initialize() {
064: String caseWidgetId = definition.getCaseWidgetId();
065: this .caseWidget = getParent().lookupWidget(caseWidgetId);
066: if (this .caseWidget == null) {
067: throw new FormsRuntimeException(
068: "Could not find case widget '" + caseWidgetId
069: + "' for union '" + getId() + "'.",
070: getLocation());
071: }
072:
073: ((ValueChangedListenerEnabled) caseWidget)
074: .addValueChangedListener(new ValueChangedListener() {
075: public void valueChanged(ValueChangedEvent event) {
076: String newValue = (String) event.getNewValue();
077: if (!ObjectUtils.equals(Union.this .caseValue,
078: newValue)) {
079: Union.this .caseValue = newValue;
080: getForm().addWidgetUpdate(Union.this );
081: }
082: }
083: });
084: }
085:
086: /**
087: * @return "field"
088: */
089: public String getXMLElementName() {
090: return UNION_EL;
091: }
092:
093: public Object getValue() {
094: return this .caseWidget.getValue();
095: }
096:
097: public void readFromRequest(FormContext formContext) {
098: // Ensure the case widget has read its value
099: this .caseWidget.readFromRequest(formContext);
100:
101: Widget widget;
102: // Read current case from request
103: String newValue = (String) getValue();
104: if (newValue != null && !newValue.equals("")) {
105: // We need to know if the case widget is the submit widget,
106: // and since the submit widget is only determined after the readFromRequest,
107: // we need to do it here prematurely (as happens in Action & Upload)
108: String fullId = caseWidget.getRequestParameterName();
109: if (fullId.equals(formContext.getRequest().getParameter(
110: Form.SUBMIT_ID_PARAMETER))) {
111: getForm().setSubmitWidget(this .caseWidget);
112: }
113:
114: if (getForm().getSubmitWidget() == this .caseWidget
115: && !newValue.equals(this .caseValue)) {
116: // If submitted by the case widget and its value has changed, read the values
117: // for the previous case value. This allows to keep any already entered values
118: // despite the case change.
119: widget = getChild(this .caseValue);
120: } else {
121: // Get the corresponding widget (will create it if needed)
122: widget = getChild(newValue);
123: }
124:
125: if (widget != null
126: && getCombinedState().isAcceptingInputs()) {
127: widget.readFromRequest(formContext);
128: }
129: }
130:
131: if (!ObjectUtils.equals(this .caseValue, newValue)) {
132: this .caseValue = newValue;
133: getForm().addWidgetUpdate(this );
134: }
135: }
136:
137: // TODO: Simplify this logic.
138: public boolean validate() {
139: if (!getCombinedState().isValidatingValues()) {
140: this .wasValid = true;
141: return true;
142: }
143:
144: Widget widget;
145: boolean valid = true;
146: // Read current case from request
147: String value = (String) getValue();
148: if (value != null && !value.equals("")) {
149: if ((widget = getChild(value)) != null) {
150: valid = valid & widget.validate();
151: }
152: }
153: this .wasValid = valid;
154: return valid;
155: }
156:
157: public Widget getChild(String id) {
158: if (!widgets.hasWidget(id) && definition.hasWidget(id)) {
159: definition.createWidget(this , id);
160: Widget child = super .getChild(id);
161: child.initialize();
162: return child;
163: }
164: return super .getChild(id);
165: }
166:
167: //TODO: check further: cause the claim in the accompanied comment doesn't seem
168: // to be completely correct
169:
170: // This method is overridden to suppress output of sub-widget sax fragments.
171: // public void generateItemsSaxFragment(ContentHandler contentHandler, Locale locale) throws SAXException {
172: // // Do nothing
173: // }
174:
175: }
|