/* * 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.Collection; import java.util.List; import org.apache.wicket.WicketRuntimeException; import org.apache.wicket.markup.ComponentTag; import org.apache.wicket.markup.html.WebMarkupContainer; import org.apache.wicket.model.IModel; import org.apache.wicket.model.util.CollectionModel; import org.apache.wicket.util.convert.ConversionException; import org.apache.wicket.util.lang.Generics; import org.apache.wicket.util.string.Strings; import org.apache.wicket.util.visit.IVisit; import org.apache.wicket.util.visit.IVisitor; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * Component used to connect instances of Check components into a group. Instances of Check have to * be in the component hierarchy somewhere below the group component. The model of the CheckGroup * component has to be an instance of java.util.Collection. The model collection of the group is * filled with model objects of all selected Check components. * * ie <code> * <span wicket:id="checkboxgroup"> * ... * <input type="checkbox" wicket:id="checkbox1">choice 1</input> * ... * <input type="checkbox" wicket:id="checkbox2">choice 2</input> * ... * </span> * </code> * * @see org.apache.wicket.markup.html.form.Check * @see org.apache.wicket.markup.html.form.CheckGroupSelector <p> * Note: This component does not support cookie persistence * * @author Igor Vaynberg * * @param <T> * The model object type */ public class CheckGroup<T> extends FormComponent<Collection<T>> { private static final long serialVersionUID = 1L; private static final Logger log = LoggerFactory.getLogger(CheckGroup.class); /** * Constructor that will create a default model collection * * @param id * component id */ public CheckGroup(String id) { super(id); setRenderBodyOnly(true); } /** * Constructor that wraps the provided collection with the org.apache.wicket.model.Model object * * @param id * component id * @param collection * collection to be used as the model * */ public CheckGroup(String id, Collection<T> collection) { this(id, new CollectionModel<T>(collection)); } /** * @param id * @param model * @see WebMarkupContainer#WebMarkupContainer(String, IModel) */ @SuppressWarnings("unchecked") public CheckGroup(String id, IModel<? extends Collection<T>> model) { super(id, (IModel<Collection<T>>)model); setRenderBodyOnly(true); } /** * @see FormComponent#getModelValue() */ @Override protected String getModelValue() { final StringBuilder builder = new StringBuilder(); final Collection<T> ts = getModelObject(); visitChildren(Check.class, new IVisitor<Check<T>, Void>() { @Override public void component(Check<T> check, IVisit<Void> visit) { if (ts.contains(check.getModelObject())) { if (builder.length() > 0) { builder.append(VALUE_SEPARATOR); } builder.append(check.getValue()); } } }); return builder.toString(); } @Override protected Collection<T> convertValue(String[] values) throws ConversionException { List<T> collection = Generics.newArrayList(); /* * if the input is null we do not need to do anything since the model collection has already * been cleared */ if (values != null && values.length > 0) { for (final String value : values) { if (value != null) { Check<T> checkbox = visitChildren(Check.class, new org.apache.wicket.util.visit.IVisitor<Check<T>, Check<T>>() { @Override public void component(final Check<T> check, final IVisit<Check<T>> visit) { if (String.valueOf(check.getValue()).equals(value)) { visit.stop(check); } } }); if (checkbox == null) { throw new WicketRuntimeException( "submitted http post value [" + Strings.join(",", values) + "] for CheckGroup component [" + getPath() + "] contains an illegal value [" + value + "] which does not point to a Check component. Due to this the CheckGroup component cannot resolve the selected Check component pointed to by the illegal value. A possible reason is that component hierarchy changed between rendering and form submission."); } // assign the value of the group's model collection.add(checkbox.getModelObject()); } } } return collection; } /** * See {@link FormComponent#updateCollectionModel(FormComponent)} for details on how the model * is updated. */ @Override public void updateModel() { FormComponent.updateCollectionModel(this); } @Override protected void onComponentTag(ComponentTag tag) { super.onComponentTag(tag); // No longer applicable, breaks XHTML validation. tag.remove("disabled"); tag.remove("name"); } }