001: /*
002: * $Id: CheckGroup.java 482799 2006-12-05 21:56:22Z dashorst $ $Revision: 482799 $
003: * $Date: 2006-12-05 22:56:22 +0100 (Tue, 05 Dec 2006) $
004: *
005: * ==============================================================================
006: * Licensed under the Apache License, Version 2.0 (the "License"); you may not
007: * use this file except in compliance with the License. You may obtain a copy of
008: * the License at
009: *
010: * http://www.apache.org/licenses/LICENSE-2.0
011: *
012: * Unless required by applicable law or agreed to in writing, software
013: * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
014: * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
015: * License for the specific language governing permissions and limitations under
016: * the License.
017: */
018: package wicket.markup.html.form;
019:
020: import java.io.Serializable;
021: import java.util.ArrayList;
022: import java.util.Collection;
023: import java.util.List;
024:
025: import wicket.Component;
026: import wicket.WicketRuntimeException;
027: import wicket.markup.html.WebMarkupContainer;
028: import wicket.model.IModel;
029: import wicket.model.Model;
030: import wicket.util.convert.ConversionException;
031: import wicket.util.string.StringList;
032:
033: /**
034: * Component used to connect instances of Check components into a group.
035: * Instances of Check have to be in the component hierarchy somewhere below the
036: * group component. The model of the CheckGroup component has to be an instance
037: * of java.util.Collection. The model collection of the group is filled with
038: * model objects of all selected Check components.
039: *
040: * ie
041: *
042: * <code>
043: * <span wicket:id="checkboxgroup">
044: * ...
045: * <input type="radio" wicket:id="checkbox1">choice 1</input>
046: * ...
047: * <input type="radio" wicket:id="checkbox2">choice 2</input>
048: * ...
049: * </span>
050: * </code>
051: *
052: * @see wicket.markup.html.form.Check
053: * @see wicket.markup.html.form.CheckGroupSelector
054: *
055: * <p>
056: * Note: This component does not support cookie persistence
057: *
058: * @author Igor Vaynberg (ivaynberg@users.sf.net)
059: *
060: */
061: public class CheckGroup extends FormComponent implements
062: IOnChangeListener {
063: private static final long serialVersionUID = 1L;
064:
065: /**
066: * Constructor that will create a default model collection
067: *
068: * @param id
069: * component id
070: */
071: public CheckGroup(String id) {
072: super (id);
073: setRenderBodyOnly(true);
074: }
075:
076: /**
077: * Constructor that wraps the provided collection with the
078: * wicket.model.Model object
079: *
080: * @param id
081: * component id
082: * @param collection
083: * collection to be used as the model
084: *
085: */
086: public CheckGroup(String id, Collection collection) {
087: this (id, new Model((Serializable) collection));
088: }
089:
090: /**
091: * @see WebMarkupContainer#WebMarkupContainer(String, IModel)
092: */
093: public CheckGroup(String id, IModel model) {
094: super (id, model);
095: setRenderBodyOnly(true);
096: }
097:
098: /**
099: * @see wicket.markup.html.form.FormComponent#convertValue(String[])
100: */
101: protected Object convertValue(String[] values)
102: throws ConversionException {
103: List collection = new ArrayList();
104:
105: /*
106: * if the input is null we do not need to do anything since the model
107: * collection has already been cleared
108: */
109:
110: if (values != null && values.length > 0) {
111: for (int i = 0; i < values.length; i++) {
112: final String value = values[i];
113:
114: if (value != null) {
115: Check checkbox = (Check) visitChildren(new Component.IVisitor() {
116:
117: public Object component(Component component) {
118: if (component instanceof Check) {
119: final Check check = (Check) component;
120: if (String.valueOf(check.getValue())
121: .equals(value)) {
122: return check;
123: }
124: }
125: return CONTINUE_TRAVERSAL;
126: }
127:
128: });
129:
130: if (checkbox == null) {
131: throw new WicketRuntimeException(
132: "submitted http post value ["
133: + StringList.valueOf(values)
134: .toString()
135: + "] for CheckGroup component ["
136: + getPath()
137: + "] contains an illegal relative path "
138: + "element ["
139: + value
140: + "] 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 componment hierarchy changed between rendering and form submission.");
141: }
142:
143: // assign the value of the group's model
144: collection.add(checkbox.getModelObject());
145: }
146: }
147: }
148: return collection;
149: }
150:
151: /**
152: * @see FormComponent#updateModel()
153: */
154: public void updateModel() {
155: Collection collection = (Collection) getModelObject();
156: if (collection == null) {
157: collection = (Collection) getConvertedInput();
158: setModelObject(collection);
159: } else {
160: modelChanging();
161: collection.clear();
162: collection.addAll((Collection) getConvertedInput());
163: modelChanged();
164: }
165: }
166:
167: /**
168: * Check group does not support persistence through cookies
169: *
170: * @see wicket.markup.html.form.FormComponent#supportsPersistence()
171: */
172: protected final boolean supportsPersistence() {
173: return false;
174: }
175:
176: /**
177: * Called when a selection changes.
178: */
179: public final void onSelectionChanged() {
180: convert();
181: updateModel();
182: onSelectionChanged((Collection) getModelObject());
183: }
184:
185: /**
186: * Template method that can be overriden by clients that implement
187: * IOnChangeListener to be notified by onChange events of a select element.
188: * This method does nothing by default.
189: * <p>
190: * Called when a {@link Check} is clicked in a {@link CheckGroup} that wants
191: * to be notified of this event. This method is to be implemented by clients
192: * that want to be notified of selection events.
193: *
194: * @param newSelection
195: * The new selection of the {@link CheckGroup}. NOTE this is the
196: * same as you would get by calling getModelObject() if the new
197: * selection were current
198: */
199: protected void onSelectionChanged(final Collection newSelection) {
200: }
201:
202: /**
203: * This method should be overridden to return true if it is desirable to
204: * have on-selection-changed notifiaction.
205: *
206: * @return true if component should receive on-selection-changed
207: * notifications, false otherwise
208: */
209: protected boolean wantOnSelectionChangedNotifications() {
210: return false;
211: }
212:
213: }
|