| /* |
| * Licensed to the Apache Software Foundation (ASF) under one or more |
| * contributor license agreements. See the NOTICE file distributed with |
| * this work for additional information regarding copyright ownership. |
| * The ASF licenses this file to You 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 org.apache.wicket.markup.html.form; |
| |
| import java.util.List; |
| |
| import org.apache.wicket.Localizer; |
| import org.apache.wicket.model.IModel; |
| import org.apache.wicket.util.string.AppendingStringBuffer; |
| import org.apache.wicket.util.string.Strings; |
| |
| |
| /** |
| * Abstract base class for single-select choices. |
| * |
| * @author Jonathan Locke |
| * @author Eelco Hillenius nm |
| * @author Johan Compagner |
| * |
| * @param <T> |
| * The model object type |
| */ |
| public abstract class AbstractSingleSelectChoice<T> extends AbstractChoice<T, T> |
| { |
| private static final long serialVersionUID = 1L; |
| |
| /** String to display when the selected value is null and nullValid is false. */ |
| private static final String CHOOSE_ONE = "Choose One"; |
| |
| /** whether or not null will be offered as a choice once a nonnull value is saved */ |
| private boolean nullValid = false; |
| |
| /** |
| * Constructor. |
| * |
| * @param id |
| * See Component |
| */ |
| public AbstractSingleSelectChoice(final String id) |
| { |
| super(id); |
| } |
| |
| /** |
| * Constructor. |
| * |
| * @param id |
| * See Component |
| * @param choices |
| * The collection of choices in the dropdown |
| */ |
| public AbstractSingleSelectChoice(final String id, final List<? extends T> choices) |
| { |
| super(id, choices); |
| } |
| |
| /** |
| * Constructor. |
| * |
| * @param id |
| * See Component |
| * @param renderer |
| * The rendering engine |
| * @param choices |
| * The collection of choices in the dropdown |
| */ |
| public AbstractSingleSelectChoice(final String id, final List<? extends T> choices, |
| final IChoiceRenderer<? super T> renderer) |
| { |
| super(id, choices, renderer); |
| } |
| |
| /** |
| * Constructor. |
| * |
| * @param id |
| * See Component |
| * @param model |
| * See Component |
| * @param choices |
| * The collection of choices in the dropdown |
| */ |
| public AbstractSingleSelectChoice(final String id, IModel<T> model, |
| final List<? extends T> choices) |
| { |
| super(id, model, choices); |
| } |
| |
| /** |
| * Constructor. |
| * |
| * @param id |
| * See Component |
| * @param model |
| * See Component |
| * @param choices |
| * The drop down choices |
| * @param renderer |
| * The rendering engine |
| */ |
| public AbstractSingleSelectChoice(final String id, IModel<T> model, |
| final List<? extends T> choices, final IChoiceRenderer<? super T> renderer) |
| { |
| super(id, model, choices, renderer); |
| } |
| |
| /** |
| * Constructor. |
| * |
| * @param id |
| * See Component |
| * @param choices |
| * The collection of choices in the dropdown |
| */ |
| public AbstractSingleSelectChoice(String id, IModel<? extends List<? extends T>> choices) |
| { |
| super(id, choices); |
| } |
| |
| /** |
| * Constructor. |
| * |
| * @param id |
| * See Component |
| * @param model |
| * See Component |
| * @param choices |
| * The drop down choices |
| */ |
| public AbstractSingleSelectChoice(String id, IModel<T> model, |
| IModel<? extends List<? extends T>> choices) |
| { |
| super(id, model, choices); |
| } |
| |
| /** |
| * Constructor. |
| * |
| * @param id |
| * See Component |
| * @param choices |
| * The drop down choices |
| * @param renderer |
| * The rendering engine |
| */ |
| public AbstractSingleSelectChoice(String id, IModel<? extends List<? extends T>> choices, |
| IChoiceRenderer<? super T> renderer) |
| { |
| super(id, choices, renderer); |
| } |
| |
| /** |
| * Constructor. |
| * |
| * @param id |
| * See Component |
| * @param model |
| * See Component |
| * @param choices |
| * The drop down choices |
| * @param renderer |
| * The rendering engine |
| */ |
| public AbstractSingleSelectChoice(String id, IModel<T> model, |
| IModel<? extends List<? extends T>> choices, IChoiceRenderer<? super T> renderer) |
| { |
| super(id, model, choices, renderer); |
| } |
| |
| /** |
| * @see FormComponent#getModelValue() |
| */ |
| @Override |
| public String getModelValue() |
| { |
| final T object = getModelObject(); |
| if (object != null) |
| { |
| int index = getChoices().indexOf(object); |
| return getChoiceRenderer().getIdValue(object, index); |
| } |
| else |
| { |
| return ""; |
| } |
| } |
| |
| /** |
| * Determines whether or not the null value should be included in the list of choices when the |
| * field's model value is nonnull, and whether or not the null_valid string property (e.g. |
| * "Choose One") should be displayed until a nonnull value is selected. |
| * |
| * If set to false, then "Choose One" will be displayed when the value is null. After a value is |
| * selected, and that change is propagated to the underlying model, the user will no longer see |
| * the "Choose One" option, and there will be no way to reselect null as the value. |
| * |
| * If set to true, the null string property (the empty string, by default) will always be |
| * displayed as an option, whether or not a nonnull value has ever been selected. |
| * |
| * Note that this setting has no effect on validation; in order to guarantee that a value will |
| * be specified on form validation, {@link #setRequired(boolean)}. This is because even if |
| * setNullValid() is called with false, the user can fail to provide a value simply by never |
| * activating (i.e. clicking on) the component. |
| * |
| * @return <code>true</code> when the <code>null</code> value is allowed. |
| */ |
| public boolean isNullValid() |
| { |
| return nullValid; |
| } |
| |
| /** |
| * Determines whether or not the null value should be included in the list of choices when the |
| * field's model value is nonnull, and whether or not the null_valid string property (e.g. |
| * "Choose One") should be displayed until a nonnull value is selected. |
| * |
| * If set to false, then "Choose One" will be displayed when the value is null. After a value is |
| * selected, and that change is propagated to the underlying model, the user will no longer see |
| * the "Choose One" option, and there will be no way to reselect null as the value. |
| * |
| * If set to true, the null string property (the empty string, by default) will always be |
| * displayed as an option, whether or not a nonnull value has ever been selected. |
| * |
| * Note that this setting has no effect on validation; in order to guarantee that a value will |
| * be specified on form validation, {@link #setRequired(boolean)}. This is because even if |
| * setNullValid() is called with false, the user can fail to provide a value simply by never |
| * activating (i.e. clicking on) the component. |
| * |
| * @param nullValid |
| * whether null is a valid value |
| * @return this for chaining |
| */ |
| public AbstractSingleSelectChoice<T> setNullValid(boolean nullValid) |
| { |
| this.nullValid = nullValid; |
| return this; |
| } |
| |
| /** |
| * @see org.apache.wicket.markup.html.form.FormComponent#convertValue(String[]) |
| */ |
| @Override |
| protected final T convertValue(final String[] value) |
| { |
| String tmp = ((value != null) && (value.length > 0)) ? value[0] : null; |
| return convertChoiceIdToChoice(tmp); |
| } |
| |
| /** |
| * Converts submitted choice id string back to choice object. |
| * |
| * @param id |
| * string id of one of the choice objects in the choices list. can be null. |
| * @return choice object. null if none match the specified id. |
| */ |
| protected T convertChoiceIdToChoice(String id) |
| { |
| final IModel<? extends List<? extends T>> choices = getChoicesModel(); |
| final IChoiceRenderer<? super T> renderer = getChoiceRenderer(); |
| T object = (T) renderer.getObject(id, choices); |
| return object; |
| } |
| |
| /** |
| * Asks the {@link Localizer} for the property to display for an additional default choice |
| * depending on {@link #isNullValid()}: |
| * |
| * <ul> |
| * <li> |
| * "nullValid" if {@code null} is valid, defaulting to an empty string.</li> |
| * <li> |
| * "null" if {@code null} is not valid but no choice is selected (i.e. {@code selectedValue} is |
| * empty), defaulting to "Choose one".</li> |
| * </ul> |
| * |
| * Otherwise no additional default choice will be returned. |
| * |
| * @see #getNullValidKey() |
| * @see #getNullKey() |
| * @see org.apache.wicket.markup.html.form.AbstractChoice#getDefaultChoice(String) |
| */ |
| @Override |
| protected CharSequence getDefaultChoice(final String selectedValue) |
| { |
| // Is null a valid selection value? |
| if (isNullValid()) |
| { |
| // Null is valid, so look up the value for it |
| String option = getNullValidDisplayValue(); |
| |
| // The <option> tag buffer |
| final AppendingStringBuffer buffer = new AppendingStringBuffer(64 + option.length()); |
| |
| // Add option tag |
| buffer.append("\n<option"); |
| |
| // If null is selected, indicate that |
| if (selectedValue != null && selectedValue.isEmpty()) |
| { |
| buffer.append(" selected=\"selected\""); |
| } |
| |
| // Add body of option tag |
| buffer.append(" value=\"\">").append(option).append("</option>"); |
| return buffer; |
| } |
| else |
| { |
| // Null is not valid. Is it selected anyway? |
| if (selectedValue != null && selectedValue.isEmpty()) |
| { |
| // Force the user to pick a non-null value |
| String option = getNullKeyDisplayValue(); |
| return "\n<option selected=\"selected\" value=\"\">" + option + "</option>"; |
| } |
| } |
| return ""; |
| } |
| |
| /** |
| * Returns the display value for the null value. The default behavior is to look the value up by |
| * using the key from <code>getNullValidKey()</code>. |
| * |
| * @return The value to display for null |
| */ |
| protected String getNullValidDisplayValue() |
| { |
| String option = getLocalizer().getStringIgnoreSettings(getNullValidKey(), this, null, null); |
| if (Strings.isEmpty(option)) |
| { |
| option = getLocalizer().getString("nullValid", this, ""); |
| } |
| return option; |
| } |
| |
| /** |
| * Return the localization key for nullValid value |
| * |
| * @return getId() + ".nullValid" |
| */ |
| protected String getNullValidKey() |
| { |
| return getId() + ".nullValid"; |
| } |
| |
| /** |
| * Returns the display value if null is not valid but is selected. The default behavior is to |
| * look the value up by using the key from <code>getNullKey()</code>. |
| * |
| * @return The value to display if null is not value but selected, e.g. "Choose One" |
| */ |
| protected String getNullKeyDisplayValue() |
| { |
| String option = getLocalizer().getStringIgnoreSettings(getNullKey(), this, null, null); |
| |
| if (Strings.isEmpty(option)) |
| { |
| option = getLocalizer().getString("null", this, CHOOSE_ONE); |
| } |
| return option; |
| } |
| |
| /** |
| * Return the localization key for null value |
| * |
| * @return getId() + ".null" |
| */ |
| protected String getNullKey() |
| { |
| return getId() + ".null"; |
| } |
| |
| /** |
| * Gets whether the given value represents the current selection. |
| * |
| * |
| * @param object |
| * The object to check |
| * @param index |
| * The index of the object in the collection |
| * @param selected |
| * The current selected id value |
| * @return Whether the given value represents the current selection |
| */ |
| @Override |
| protected boolean isSelected(final T object, int index, String selected) |
| { |
| return (selected != null) && selected.equals(getChoiceRenderer().getIdValue(object, index)); |
| } |
| } |