net.sf.clickclick.control.BooleanSelect.java Source code

Java tutorial

Introduction

Here is the source code for net.sf.clickclick.control.BooleanSelect.java

Source

/*
 * 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.sf.clickclick.control;

import java.util.List;
import org.apache.click.control.Select;
import org.apache.click.extras.control.DateField;
import org.apache.click.extras.control.IntegerField;
import org.apache.commons.lang.StringUtils;

/**
 * Provides a Select control that can be used as either a simple two-option
 * select (TRUE / FALSE) or as a tri-state select (UNSET / TRUE / FALSE).
 *
 * <table class='htmlHeader' cellspacing='6'>
 * <tr>
 * <td>BooleanSelect</td>
 * <td>
 * <select title='BooleanSelect Control'>
 * <option value=''></option>
 * <option value='true'>yes</option>
 * <option value='false'>no</option>
 * </select>
 * </td>
 * </tr>
 * </table>
 *
 * <h4>Use</h4>
 * Tri-state is handy when you want to confirm that the user made a conscious
 * decision and not just accepted the default value.
 * <p/>
 * Please note that tri-state can best be used in combination with
 * <i>required</i> and that the <i>required</i> property is useless when used
 * in combination with the two-state (as there will always be an option selected).
 * <p/>
 * The default value when creating a BooleanSelect field is:
 * <i>Required</i> == <i>Tristate</i>.
 * <p/>
 * Changing one of these properties after creation will not influence the other.
 * 
 * <h4>Values</h4>
 * <p/>
 * In holding with {@link IntegerField}, {@link DateField} and others the
 * <code>BooleanSelect</code> field provides <code>getBoolean()</code> and
 * <code>setBoolean()</code> methods.
 * <p/>
 * The <code>setValue()</code> and <code>setObjectValue()</code> only allow
 * Boolean objects or Strings(containing "true" or "false").
 * <p/>
 * <tt>null</tt> or empty strings are allowed in all these method and means:
 * value not set (unset). In keeping with the other Fields, <tt>null</tt>
 * values are stored and returned as "" (empty string). The
 * <tt>getValueObject()</tt> method does not return an empty string but
 * <code>null</code> instead.
 *
 * <h4>Makeup</h4>
 * <p/>
 * The labels used for the true and false options can be customized in two ways:
 * manually or with one of the built-in notations
 * <p/>
 * Use the <tt>setOptionLabels()</tt> convenience methods or the individual
 * properties to manually set.
 * <p/>
 * Or use the <tt>setNotation()</tt> method to use one of the built-in notations.
 * <p/>
 * Following notations are provided and backed by the resource-bundle (i18n).
 * <ul>
 * <li> <code>TRUE / FALSE</code> -- <i>default</i>
 * <li> <code>YES / NO</code>
 * <li> <code>ON / OFF</code>
 * <li> <code>ACTIVE / INACTIVE</code>
 * <li> <code>OPEN / CLOSED</code>
 * </ul>
 * <p/>
 * Remark: Options are created in <tt>control.onInit()</tt> all makeup needs to
 * be done in <code>page.onInit()</code> or earlier; changes made in
 * <tt>onRender()</tt>, <tt>onPost()</tt> or action listeners, will not be
 * reflected in the final result.
 *
 * @see Select
 */
public class BooleanSelect extends Select {

    // -------------------------------------------------------------- Constants

    private static final long serialVersionUID = 1L;

    /** Indicates the Select Option labels are custom set. */
    public static final String CUSTOM = "_custom_";

    /** Indicates the Select Option labels are set to TRUE / FALSE. */
    public static final String TRUEFALSE = "default";

    /** Indicates the Select Option labels are set to YES / NO. */
    public static final String YESNO = "yesno";

    /** Indicates the Select Option labels are set to ON / OFF. */
    public static final String ONOFF = "onoff";

    /** Indicates the Select Option labels are set to ACTIVE / INACTIVE. */
    public static final String ACTIVEINACTIVE = "activeinactive";

    /** Indicates the Select Option labels are set to OPEN / CLOSED. */
    public static final String OPENCLOSED = "openclosed";

    // -------------------------------------------------------------- Variables

    /** Indicates if tri-state is enabled or not, false by default. */
    private boolean tristate = false;

    /** The default notation, {@link #TRUEFALSE}. */
    private String notation = TRUEFALSE;

    /** The {@link #CUSTOM} <tt>true</tt> label. */
    private String customTrue = null;

    /** The {@link #CUSTOM} <tt>false</tt> label. */
    private String customFalse = null;

    /** The {@link #CUSTOM} <tt>unset</tt> label. */
    private String customUnset = null;

    /**
     * Create a Select field with no name defined.
     * <p/>
     * <b>Please note</b> the control's name must be defined before it is valid.
     */
    public BooleanSelect() {
        super();
    }

    /**
     * Create a Select field with the given name.
     *
     * @param name the name of the field
     */
    public BooleanSelect(String name) {
        super(name);
    }

    /**
     * Create a Select field with the given name.
     * <p/>
     * If required is true, tri-state will automatically be set to true.
     *
     * @param name the name of the field
     * @param required the required property
     */
    public BooleanSelect(String name, boolean required) {
        super(name, required);
        setTristate(required);
    }

    /**
     * Create a Select field with the given name and label.
     *
     * @param name the name of the field
     * @param label the label of the field
     */
    public BooleanSelect(String name, String label) {
        super(name, label);
    }

    /**
     * Create a Select field with the given name and label.
     *
     * @param name the name of the field
     * @param label the label of the field
     * @param notation the notation to be used for the option labels
     */
    public BooleanSelect(String name, String label, String notation) {
        super(name, label);
        setNotation(notation);
    }

    /**
     * Create a Select field with the given name and label.
     * <p/>
     * If required is true, tri-state will automatically be set to true.
     *
     * @param name the name of the field
     * @param label the label of the field
     * @param required the required property
     */
    public BooleanSelect(String name, String label, boolean required) {
        super(name, label, required);
        setTristate(required);
    }

    /**
     * Create a Select field with the given name and label.
     * <p/>
     * If required is true, tri-state will automatically be set to true.
     *
     * @param name the name of the field
     * @param label the label of the field
     * @param notation the notation to be used for the option labels
     * @param required the required property
     */
    public BooleanSelect(String name, String label, String notation, boolean required) {
        super(name, label, required);
        setTristate(required);
        setNotation(notation);
    }

    // ------------------------------------------------------------------

    /**
     * Options are added to the Select control. Make sure you call
     * super.onInit() if you override this method.
     */
    @Override
    public void onInit() {
        List optionList = getOptionList();

        // Being called more than once? We could keep the existing options,
        // but they might have changed
        if (optionList.size() > 0) {
            optionList.clear();
        }

        if (tristate) {
            add(new StyledOption("", "unset", getOptionLabelUnset()));
        }
        add(new StyledOption(Boolean.TRUE.toString(), "true", getOptionLabelTrue()));

        add(new StyledOption(Boolean.FALSE.toString(), "false", getOptionLabelFalse()));

        super.onInit();
    }

    /**
     * Return the value of the field as a Boolean, or null if the value was not
     * set.
     *
     * @return <code>True</code> or <code>False</code> if value was set,
     * <code>null</code> otherwise
     */
    public Boolean getBoolean() {
        String value = getValue();

        // We need this extra check as Boolean.valueOf does not return null but
        // false on illegal values.
        if (StringUtils.isEmpty(value)) {
            return null;
        }
        return Boolean.valueOf(getValue());
    }

    /**
     * Set the value of the field to the given Boolean value. The Boolean can
     * be null, meaning the value is not set.
     *
     * @param value the field's value, can be <tt>null</tt>, meaning the value
     * is not set
     */
    public void setBoolean(Boolean value) {
        this.value = ((value == null) ? "" : value.toString());
    }

    /**
     * Return the value of the field.
     *
     * @return the value of the field
     */
    @Override
    public Object getValueObject() {
        return getBoolean();
    }

    /**
     * Set the value of the field to the given object.
     *
     * @param object the value of the field
     */
    @Override
    public void setValueObject(Object object) {
        if (object == null) {
            setValue("");
        } else {
            setValue(object.toString());
        }
    }

    /**
     * @throws UnsupportedOperationException if invoked
     */
    @Override
    public void setMultiple(boolean value) {
        throw new UnsupportedOperationException("This operation is not" + " supported.");
    }

    /**
     * Convenience method to set the options labels. The notation will be set
     * to {@link #CUSTOM}.
     * <p/>
     * The unset option label value will default to "".
     *
     * @param trueOptionLabel the true option label
     * @param falseOptionLabel the false option label
     */
    public void setOptionLabels(String trueOptionLabel, String falseOptionLabel) {
        setOptionLabels(trueOptionLabel, falseOptionLabel, "");
    }

    /**
     * Convenience method to set the options labels. The notation will be set
     * to {@link #CUSTOM}.
     *
     * @param trueOptionLabel the true option label
     * @param falseOptionLabel the false option label
     * @param unsetOptionLabel the unset option label
     */
    public void setOptionLabels(String trueOptionLabel, String falseOptionLabel, String unsetOptionLabel) {

        setOptionLabelTrue(trueOptionLabel);
        setOptionLabelFalse(falseOptionLabel);
        setOptionLabelUnset(unsetOptionLabel);
        setNotation(CUSTOM);
    }

    /**
     * Returns the notation used for the BooleanSelect.
     *
     * @return the notation for the BooleanSelect
     */
    public String getNotation() {
        return notation;
    }

    /**
     * Change the option labels to one of the built-in notations.
     * <p/>
     * The following notations are provided which is also available through
     * the resource-bundle for i18n support.
     * <p/>
     * <ul>
     * <li>{@link #TRUEFALSE} (true/false}</li>
     * <li>{@link #YESNO} (yes/no)</li>
     * <li>{@link #ONOFF} (on/off)</li>
     * <li>{@link #ACTIVEINACTIVE} (active/inactive)</li>
     * <li>{@link #OPENCLOSED} (open/closed)</li>
     * <li>{@link #CUSTOM} (this option is automatically set when you provide
     * custom labels with: <tt>setOptionLabels()</tt>)</li>
     * </ul>
     *
     * The preferred way of setting the notation is by using the static
     * properties of this class:
     * <p/>
     * <code>setNotation(BooleanSelect.YESNO);</code>
     *
     * @param notation the notation to set the field's labels to
     */
    public void setNotation(String notation) {
        // TODO caveat: this method is not very robust as you can add an
        // illegal argument, it does allow you to add custom values to the
        // i18n resource bundle without recompiling though
        if (StringUtils.isEmpty(notation)) {
            throw new IllegalArgumentException(notation + " is not a valid option for notation.");
        }
        this.notation = notation;
    }

    /**
     * Return true if the tri-state option is enabled, false otherwise.
     *
     * @return true if the tri-state option is enabled, false otherwise.
     */
    public boolean isTristate() {
        return tristate;
    }

    /**
     * Set the tri-state option of the field. If tri-state is set to true this
     * indicates that the select field will contain three options, true, false
     * and unset. Otherwise the select will only contain two options, true and
     * false.
     *
     * @param tristate false = 2 options, true = 3 options
     */
    public void setTristate(boolean tristate) {
        this.tristate = tristate;
    }

    /**
     * Return the the label to use for the <tt>true</tt> option.
     *
     * @return custom value or message from language bundle according to the
     * chosen notation
     */
    public String getOptionLabelTrue() {
        String result;
        if (CUSTOM.equals(notation)) {
            if (customTrue == null)
                throw new IllegalStateException(
                        "You must" + " set custom option labels when you choose CUSTOM notation.");
            result = customTrue;
        } else {
            result = getMessage(notation + "-true");
            if (result == null)
                throw new RuntimeException("Could not find" + " resource with name: " + notation + "-true");
        }
        return result;
    }

    /**
     * Set the label of the <tt>true</tt> option.
     *
     * @param optionLabel the label of the true option
     */
    public void setOptionLabelTrue(String optionLabel) {
        if (StringUtils.isEmpty(optionLabel)) {
            throw new IllegalArgumentException("You must provide a value for" + " the TrueOptionLabel");
        }
        this.customTrue = optionLabel;
    }

    /**
     * Return the the label to use for the <tt>false</tt> option.
     *
     * @return custom value or message from language bundle according to the
     * chosen notation
     */
    public String getOptionLabelFalse() {
        String res;
        if (CUSTOM.equals(notation)) {
            if (customFalse == null)
                throw new IllegalStateException(
                        "You must" + " set custom option labels when you choose CUSTOM notation.");
            res = customFalse;
        } else {
            res = getMessage(notation + "-false");
            if (res == null)
                throw new RuntimeException("Could not find" + " resource with name: " + notation + "-false");
        }
        return res;
    }

    /**
     * Set the label of the <tt>false</tt> option.
     *
     * @param optionLabel the label of the false option
     */
    public void setOptionLabelFalse(String optionLabel) {
        if (StringUtils.isEmpty(optionLabel)) {
            throw new IllegalArgumentException("You must provide a value for the FalseOptionLabel");
        }
        this.customFalse = optionLabel;
    }

    /**
     * Return the the label to use for the <tt>unset</tt> option.
     *
     * @return custom value or message from language bundle according to the
     * chosen notation
     */
    public String getOptionLabelUnset() {
        String res;
        if (CUSTOM.equals(notation)) {
            if (customUnset == null)
                throw new IllegalStateException(
                        "You must" + " set custom option labels when you choose CUSTOM notation.");
            res = customUnset;
        } else {
            // are individual messages for the unset option, needed?
            res = "";
        }
        return res;
    }

    /**
     * Set the label of the <tt>unset</tt> option.
     *
     * @param optionLabel the label of the unset option
     */
    public void setOptionLabelUnset(String optionLabel) {
        if (optionLabel == null)
            throw new IllegalArgumentException("You must" + " provide a value for the UnsetOptionLabel"); // empty is allowed
        this.customUnset = optionLabel;
    }
}