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: * $Header:$
018: */
019: package org.apache.beehive.netui.tags.html;
020:
021: import org.apache.beehive.netui.util.internal.InternalStringBuilder;
022:
023: import org.apache.beehive.netui.tags.rendering.AbstractHtmlState;
024: import org.apache.beehive.netui.tags.rendering.OptionTag;
025: import org.apache.beehive.netui.tags.rendering.TagRenderingBase;
026: import org.apache.beehive.netui.tags.rendering.WriteRenderAppender;
027: import org.apache.beehive.netui.util.Bundle;
028:
029: import javax.servlet.ServletRequest;
030: import javax.servlet.http.HttpServletRequest;
031: import javax.servlet.jsp.JspException;
032: import javax.servlet.jsp.tagext.Tag;
033:
034: /**
035: * An option whose state is determined by its enclosing SelectOption.
036: * @jsptagref.tagdescription Renders a single <option> tag.
037: *
038: * <p>The <netui:selectOption> must have a parent {@link Select} tag.
039: *
040: * <p>To dynamically generate a set of <option> tags, point the {@link Select}
041: * tag at a String[], {@link java.util.HashMap java.util.HashMap},
042: * or any object that implements {@link java.util.Map java.util.Map}.
043: * @example The following sample generates a set of <option> tags.
044: * <pre> <netui:form action="submit">
045: * <netui:select dataSource="actionForm.selections" size="5">
046: * <netui:selectOption value="red" />
047: * <netui:selectOption value="blue" />
048: * <netui:selectOption value="green" />
049: * <netui:selectOption value="yellow" />
050: * <netui:selectOption value="orange" />
051: * </netui:select>
052: * <netui:button type="submit" value="Submit"/>
053: * </netui:form></pre>
054: * @netui:tag name="selectOption" description="An option whose state is determined by its enclosing netui:selectOption."
055: */
056: public class SelectOption extends HtmlBaseTag {
057: private OptionTag.State _state = new OptionTag.State();
058:
059: // this has it's own version of disabled in it...
060: private String _text; // The message text to be displayed to the user for this tag (if any)
061: private boolean _disabled; // Is this option disabled?
062: private String _value; // The server value for this option
063: private Select.RepeatingStages _repeatingType; // The type of the repeater.
064: private boolean _hasError = false; // Hack to avoid registering the same error in the SelectOption AND the Select.
065:
066: /**
067: * Return the name of the Tag.
068: */
069: public String getTagName() {
070: return "SelectOption";
071: }
072:
073: /**
074: * Base support for the attribute tag. This is overridden to prevent setting the <code>value</code>
075: * attribute.
076: * @param name The name of the attribute
077: * @param value The value of the attribute
078: */
079: public void setAttribute(String name, String value, String facet)
080: throws JspException {
081: if (name != null) {
082: if (name.equals(VALUE)) {
083: String s = Bundle.getString(
084: "Tags_AttributeMayNotBeSet",
085: new Object[] { name });
086: registerTagError(s, null);
087: }
088: }
089: super .setAttribute(name, value, facet);
090: }
091:
092: /**
093: * This method will return the state associated with the tag. This is used by this
094: * base class to access the individual state objects created by the tags.
095: * @return a subclass of the <code>AbstractHtmlState</code> class.
096: */
097: protected AbstractHtmlState getState() {
098: return _state;
099: }
100:
101: /**
102: * Gets if this option is disabled or not.
103: * @return the disabled state ("true" or "false")
104: */
105: public boolean getDisabled() {
106: return _disabled;
107: }
108:
109: /**
110: * Set if this option is disabled or not.
111: * @param disabled "true" or "false"
112: * @jsptagref.attributedescription Boolean value that determines whether the <option> is disabled.
113: * @jsptagref.databindable false
114: * @jsptagref.attributesyntaxvalue <i>boolean_disabled</i>
115: * @netui:attribute required="false" rtexprvalue="true" type="boolean"
116: * description="Determines whether the <option> is disabled."
117: */
118: public void setDisabled(boolean disabled) {
119: _disabled = disabled;
120: }
121:
122: /**
123: * This method will a boolean indicating if the control is disabled or not. This will cause the
124: * disable attribute to be evaluated which may result in a runtime error or a JspException.
125: * @return <code>true</code> if the control is disabled.
126: * @throws JspException on an exception.
127: */
128: protected boolean isDisabled() throws JspException {
129: return _disabled;
130: }
131:
132: /**
133: * If the selectOption is being used inside a repeating {@link Select}, this defines the Select
134: * attribute used to generate the option elements.
135: * @param repeatingType Value of "option", "dataSource", "default", (for optionsDataSource, dataSource,
136: * and defaultValue attributes respectively) or "null"
137: * @jsptagref.attributedescription If the selectOption tag is being used inside a repeating Select, this
138: * defines the Select attribute used to generate the option elements. Values are "option", "dataSource", "default",
139: * (for optionsDataSource, dataSource, and defaultValue attributes respectively) and "null".
140: * @jsptagref.databindable false
141: * @jsptagref.attributesyntaxvalue <i>string_repeatingType</i>
142: * @netui:attribute required="false" rtexprvalue="true"
143: * description="If the selectOption is being used inside a repeating Select, this defines the Select attribute used to generate the option elements."
144: */
145: public void setRepeatingType(String repeatingType) {
146: _repeatingType = Select.RepeatingStages
147: .parseString(repeatingType);
148: }
149:
150: /**
151: * Set the value of this SelectOption.
152: * @param value the SelectOption value
153: * @jsptagref.attributedescription A literal or a data binding expression that determines the value submitted by the
154: * <option> tag.
155: * @jsptagref.databindable Read Only
156: * @jsptagref.attributesyntaxvalue <i>string_or_expression_value</i>
157: * @netui:attribute required="true" rtexprvalue="true"
158: * description="A literal or a data binding expression that determines the value submitted by the
159: * <option> tag."
160: */
161: public void setValue(String value) throws JspException {
162: _value = value;
163: }
164:
165: /**
166: * Process the start of this tag.
167: * @throws JspException if a JSP exception has occurred
168: */
169: public int doStartTag() throws JspException {
170:
171: Tag parentTag = getParent();
172: while (!(parentTag instanceof Select)) {
173: parentTag = parentTag.getParent();
174: }
175:
176: if (parentTag == null) {
177: //throw error
178: String s = Bundle.getString("Tags_SelectOptionNoSelect");
179: registerTagError(s, null);
180: return SKIP_BODY;
181: }
182:
183: Select parentSelect = (Select) parentTag;
184: boolean repeating = parentSelect.isRepeater();
185:
186: // if we find an option inside a select and it's not a repeating select report the error
187: if ((parentSelect.getOptionsDataSource() != null) && !repeating) {
188: String s = Bundle
189: .getString("Tags_SelectOptionParentHasOptionsDataSource");
190: _hasError = true;
191: parentSelect.registerTagError(s, null);
192: return SKIP_BODY;
193: }
194:
195: // if we are an option inside a repeating select, we must specify the type of repeater we are.
196: if (repeating && _repeatingType == null) {
197: String s = Bundle
198: .getString("Tags_SelectRepeatingOptionType");
199: _hasError = true;
200: parentSelect.registerTagError(s, null);
201: return SKIP_BODY;
202: }
203:
204: if (repeating && !isRenderable(parentSelect)) {
205: return SKIP_BODY;
206: }
207:
208: // Do nothing until doEndTag() is called
209: return EVAL_BODY_BUFFERED;
210: }
211:
212: /**
213: * Process the body text of this tag (if any).
214: * @throws JspException if a JSP exception has occurred
215: */
216: public int doAfterBody() throws JspException {
217: String text = bodyContent.getString();
218: if (text != null) {
219: bodyContent.clearBody();
220: text = text.trim();
221: if (text.length() > 0)
222: _text = text;
223: }
224: return SKIP_BODY;
225: }
226:
227: /**
228: * Process the end of this tag.
229: * @throws JspException if a JSP exception has occurred
230: */
231: public int doEndTag() throws JspException {
232: String scriptId = null;
233:
234: ServletRequest req = pageContext.getRequest();
235:
236: if ((hasErrors()) || _hasError) {
237: localRelease();
238: return EVAL_PAGE;
239: }
240:
241: // the parent was validated in the doStartTag call
242: Tag parentTag = getParent();
243: while (!(parentTag instanceof Select)) {
244: parentTag = parentTag.getParent();
245: }
246:
247: assert (parentTag instanceof Select);
248: Select parentSelect = (Select) parentTag;
249: if (parentSelect.isRepeater()) {
250: if (!isRenderable(parentSelect))
251: return EVAL_PAGE;
252: }
253:
254: // Generate an HTML <option> element
255: //InternalStringBuilder results = new InternalStringBuilder(128);
256: _state.value = _value;
257:
258: // we assume that tagId will over have override id if both
259: // are defined.
260: if (_state.id != null) {
261: scriptId = renderNameAndId((HttpServletRequest) req,
262: _state, null);
263: }
264:
265: _state.disabled = _disabled;
266:
267: if (parentSelect.isMatched(_value))
268: _state.selected = true;
269:
270: WriteRenderAppender writer = new WriteRenderAppender(
271: pageContext);
272: TagRenderingBase br = TagRenderingBase.Factory.getRendering(
273: TagRenderingBase.OPTION_TAG, req);
274: br.doStartTag(writer, _state);
275:
276: if (_text == null)
277: write(parentSelect.formatText(_value));
278: else {
279: //@TODO: How should we report errors
280: write(parentSelect.formatText(_text));
281: }
282: br.doEndTag(writer);
283:
284: parentSelect.addOptionToList(_value);
285:
286: if (scriptId != null)
287: write(scriptId);
288:
289: // Continue evaluating this page
290: localRelease();
291: return EVAL_PAGE;
292: }
293:
294: /**
295: * Release any acquired resources.
296: */
297: protected void localRelease() {
298: super .localRelease();
299:
300: _state.clear();
301:
302: _text = null;
303: _disabled = false;
304: _value = null;
305: _hasError = false;
306: }
307:
308: private boolean isRenderable(Select sel) {
309: assert (sel != null);
310:
311: if (_repeatingType == null)
312: return true;
313:
314: if (sel.isNullStage())
315: return _repeatingType == Select.RepeatingStages.NULL;
316: if (sel.isOptionStage()
317: && _repeatingType == Select.RepeatingStages.OPTION)
318: return true;
319: if (sel.isDataSourceStage()
320: && _repeatingType == Select.RepeatingStages.DATASOURCE)
321: return true;
322: if (sel.isDefaultStage()
323: && _repeatingType == Select.RepeatingStages.DEFAULT)
324: return true;
325: return false;
326: }
327: }
|