/* Copyright 2005-2006 Tim Fennell * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package net.sourceforge.stripes.tag; import net.sourceforge.stripes.validation.BooleanTypeConverter; import javax.servlet.jsp.JspException; import javax.servlet.jsp.tagext.BodyTag; /** * <p>Coordinates with one or more other tags to produce a well formed HTML select tag with state * repopulation. The select tag itself really only writes out the basic * {@literal <select name="foo"> ... </select>} piece of the structure, and provides mechanisms * for child options to determine whether or not they should render themselves as selected.</p> * * @author Tim Fennell * * @see InputOptionTag * @see InputOptionsCollectionTag * @see InputOptionsEnumerationTag */ public class InputSelectTag extends InputTagSupport implements BodyTag { private Object value; private Object selectedValueOrValues; /** * If the text value passed in matches the empty string or (ignoring case) "multiple", * or if the value can be converted to true by the {@link BooleanTypeConverter} then the * attribute will be set to "multiple", otherwise the attribute will not be output. */ public void setMultiple(String multiple) { boolean isMultiple = "multiple".equalsIgnoreCase(multiple) || "".equals(multiple); if (!isMultiple) { BooleanTypeConverter converter = new BooleanTypeConverter(); isMultiple = converter.convert(multiple, Boolean.class, null); } if (isMultiple) { set("multiple", "multiple"); } else { getAttributes().remove("multiple"); } } /** Gets the HTML attribute "multiple". **/ public String getMultiple() { return get("multiple"); } /** * Stores the value attribute in an instance variable since it is used to determine which * options are checked. */ public void setValue(Object value) { this.value = value; this.selectedValueOrValues = value; } /** * Returns the String value set by the tag attribute on the JSP, or the override value set in * the HttpRequest, or the override value bound to the ActionBean object in scope. * * @return Object one of <em>String</em> if the value comes from the tag on the JSP, * <em>String[]</em> if the value(s) comes from the HttpServletRequest, or the type * of the field on the ActionBean which could be <em>Collection</em>, <em>Object[]</em> * or <em>Object</em>. */ public Object getValue() { return this.selectedValueOrValues; } /** * Returns the scalar value or Array or Collection of values that are to be selected in the * select tag. This will either be the value returned by the PopulationStrategy, or the value * supplied by the container to setValue(). * * @return an Object, Object[] or {@code Collection<Object>} of values that are selected */ public Object getSelectedValueOrValues() { return this.selectedValueOrValues; } /** * Checks to see if the option value should be rendered as selected or not. Consults with the * override values on the form submission or backing form, if there is one. If there is no * ActionBean object present, then return the values of <em>selectedOnPage</em> supplied by the * option. * * @param optionValue the value of the option under consideration * @param selectedOnPage true if the page contains selected=... and false otherwise */ public boolean isOptionSelected(Object optionValue, boolean selectedOnPage) { if (this.selectedValueOrValues != null) { return isItemSelected(optionValue, this.selectedValueOrValues); } else { return selectedOnPage; } } /** * Writes out the opening {@literal <select name="foo">} tag. Looks for values in the request * and in the ActionBean if one is present, and caches those values so it can efficiently * determine which child options should be selected or not. * * @return EVAL_BODY_INCLUDE in all cases * @throws JspException if the enclosing form tag cannot be found or output cannot be written */ @Override public int doStartInputTag() throws JspException { writeOpenTag(getPageContext().getOut(), "select"); Object override = getOverrideValueOrValues(); if (override != null) { this.selectedValueOrValues = override; } return EVAL_BODY_INCLUDE; } /** Does nothing. */ public void doInitBody() throws JspException { } /** * Does nothing. * @return SKIP_BODY in all cases. */ public int doAfterBody() throws JspException { return SKIP_BODY; } /** * Writes out the close select tag ({@literal </select>}). * @return EVAL_PAGE in all cases * @throws JspException if output cannot be written. */ @Override public int doEndInputTag() throws JspException { writeCloseTag(getPageContext().getOut(), "select"); this.selectedValueOrValues = this.value; // reset in case the tag is reused return EVAL_PAGE; } /** Releases the discovered selected values and then calls super-release(). */ @Override public void release() { this.selectedValueOrValues = null; super.release(); } }