| // 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 org.apache.tapestry5.corelib.components; |
| |
| import org.apache.tapestry5.*; |
| import org.apache.tapestry5.annotations.Parameter; |
| import org.apache.tapestry5.annotations.Property; |
| import org.apache.tapestry5.corelib.base.AbstractField; |
| import org.apache.tapestry5.dom.Element; |
| import org.apache.tapestry5.ioc.annotations.Inject; |
| import org.apache.tapestry5.ioc.internal.util.CollectionFactory; |
| import org.apache.tapestry5.services.Request; |
| |
| import java.util.Collections; |
| import java.util.List; |
| import java.util.Set; |
| |
| /** |
| * A list of checkboxes, allowing selection of multiple items in a list. |
| * |
| * For an alternative component that can be used for similar purposes, see |
| * {@link Palette}. |
| * |
| * @tapestrydoc |
| * @see Form |
| * @see Palette |
| * @since 5.3 |
| */ |
| public class Checklist extends AbstractField |
| { |
| |
| /** |
| * Model used to define the values and labels used when rendering the |
| * checklist. |
| */ |
| @Parameter(required = true) |
| private SelectModel model; |
| |
| /** |
| * The list of selected values from the |
| * {@link org.apache.tapestry5.SelectModel}. This will be updated when the |
| * form is submitted. If the value for the parameter is null, a new list |
| * will be created, otherwise the existing list will be cleared. If unbound, |
| * defaults to a property of the container matching this component's id. |
| */ |
| @Parameter(required = true, autoconnect = true) |
| private List<Object> selected; |
| |
| /** |
| * A ValueEncoder used to convert server-side objects (provided from the |
| * "source" parameter) into unique client-side strings (typically IDs) and |
| * back. Note: this component does NOT support ValueEncoders configured to |
| * be provided automatically by Tapestry. |
| */ |
| @Parameter(required = true, allowNull = false) |
| private ValueEncoder<Object> encoder; |
| |
| /** |
| * The object that will perform input validation. The validate binding prefix is generally used to provide |
| * this object in a declarative fashion. |
| */ |
| @Parameter(defaultPrefix = BindingConstants.VALIDATE) |
| @SuppressWarnings("unchecked") |
| private FieldValidator<Object> validate; |
| |
| @Inject |
| private Request request; |
| |
| @Inject |
| private FieldValidationSupport fieldValidationSupport; |
| |
| @Property |
| private List<Renderable> availableOptions; |
| |
| private final class RenderCheckbox implements Renderable |
| { |
| private final OptionModel model; |
| |
| private RenderCheckbox(final OptionModel model) |
| { |
| this.model = model; |
| } |
| |
| public void render(MarkupWriter writer) |
| { |
| final String clientValue = encoder.toClient(model.getValue()); |
| |
| writer.element("label"); |
| |
| final Element checkbox = writer.element("input", |
| "type", "checkbox", |
| "name", getControlName(), |
| "value", clientValue); |
| |
| if (getSelected().contains(model.getValue())) |
| { |
| checkbox.attribute("checked", "checked"); |
| } |
| |
| if (isDisabled()) { |
| writer.attributes("disabled", "disabled"); |
| } |
| |
| writer.write(model.getLabel()); |
| writer.end(); |
| |
| writer.end(); |
| |
| } |
| } |
| |
| void setupRender() |
| { |
| availableOptions = CollectionFactory.newList(); |
| |
| final SelectModelVisitor visitor = new SelectModelVisitor() |
| { |
| public void beginOptionGroup(final OptionGroupModel groupModel) |
| { |
| } |
| |
| public void option(final OptionModel optionModel) |
| { |
| availableOptions.add(new RenderCheckbox(optionModel)); |
| } |
| |
| public void endOptionGroup(final OptionGroupModel groupModel) |
| { |
| } |
| |
| }; |
| |
| model.visit(visitor); |
| } |
| |
| @Override |
| protected void processSubmission(final String controlName) |
| { |
| |
| final String[] parameters = request.getParameters(controlName); |
| |
| List<Object> selected = this.selected; |
| |
| if (selected == null) |
| { |
| selected = CollectionFactory.newList(); |
| } else |
| { |
| selected.clear(); |
| } |
| |
| if (parameters != null) |
| { |
| for (final String value : parameters) |
| { |
| final Object objectValue = encoder.toValue(value); |
| |
| selected.add(objectValue); |
| } |
| |
| } |
| |
| putPropertyNameIntoBeanValidationContext("selected"); |
| |
| try |
| { |
| fieldValidationSupport.validate(selected, this.resources, this.validate); |
| |
| this.selected = selected; |
| } catch (final ValidationException e) |
| { |
| validationTracker.recordError(this, e.getMessage()); |
| } |
| |
| removePropertyNameFromBeanValidationContext(); |
| } |
| |
| Set<Object> getSelected() |
| { |
| if (selected == null) |
| { |
| return Collections.emptySet(); |
| } |
| |
| return CollectionFactory.newSet(selected); |
| } |
| |
| /** |
| * Computes a default value for the "validate" parameter using |
| * {@link org.apache.tapestry5.services.FieldValidatorDefaultSource}. |
| */ |
| |
| Binding defaultValidate() |
| { |
| return this.defaultProvider.defaultValidatorBinding("selected", resources); |
| } |
| |
| @Override |
| public boolean isRequired() |
| { |
| return validate.isRequired(); |
| } |
| |
| void beginRender(MarkupWriter writer) { |
| writer.element("div", "id", getClientId()); |
| } |
| |
| void afterRender(MarkupWriter writer) { |
| writer.end(); |
| } |
| } |
| |