001 // Copyright 2004, 2005 The Apache Software Foundation 002 // 003 // Licensed under the Apache License, Version 2.0 (the "License"); 004 // you may not use this file except in compliance with the License. 005 // You may obtain a copy of the License at 006 // 007 // http://www.apache.org/licenses/LICENSE-2.0 008 // 009 // Unless required by applicable law or agreed to in writing, software 010 // distributed under the License is distributed on an "AS IS" BASIS, 011 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 012 // See the License for the specific language governing permissions and 013 // limitations under the License. 014 015 package org.apache.tapestry.contrib.form; 016 017 import java.util.ArrayList; 018 import java.util.Collection; 019 import java.util.List; 020 021 import org.apache.tapestry.IMarkupWriter; 022 import org.apache.tapestry.IRequestCycle; 023 import org.apache.tapestry.Tapestry; 024 import org.apache.tapestry.form.AbstractFormComponent; 025 import org.apache.tapestry.form.IPropertySelectionModel; 026 import org.apache.tapestry.form.ValidatableField; 027 import org.apache.tapestry.form.ValidatableFieldSupport; 028 import org.apache.tapestry.valid.ValidatorException; 029 030 /** 031 * A component which uses <input type=checkbox> to set a property of some 032 * object. Typically, the values for the object are defined using an 033 * {@link java.lang.Enum}. A MultiplePropertySelection is 034 * dependent on an {link IPropertySelectionModel} to provide the list of 035 * possible values. 036 * <p> 037 * Often, this is used to select one or more 038 * {@link java.lang.Enum} to assign to a property; the 039 * {@link org.apache.tapestry.form.EnumPropertySelectionModel}class simplifies 040 * this. 041 * <p> 042 * The {@link org.apache.tapestry.contrib.palette.Palette}component is more 043 * powerful, but requires client-side JavaScript and is not fully cross-browser 044 * compatible. 045 * <p> 046 * <table border=1> 047 * <tr> 048 * <td>Parameter</td> 049 * <td>Type</td> 050 * <td>Direction</td> 051 * <td>Required</td> 052 * <td>Default</td> 053 * <td>Description</td> 054 * </tr> 055 * <tr> 056 * <td>selectedList</td> 057 * <td>java.util.List</td> 058 * <td>in-out</td> 059 * <td>yes</td> 060 * <td> </td> 061 * <td>The property to set. During rendering, this property is read, and sets 062 * the default value of the options in the select. When the form is submitted, 063 * list is cleared, then has each selected option added to it.</td> 064 * </tr> 065 * <tr> 066 * <td>renderer</td> 067 * <td>{@link IMultiplePropertySelectionRenderer}</td> 068 * <td>in</td> 069 * <td>no</td> 070 * <td>shared instance of {@link CheckBoxMultiplePropertySelectionRenderer}</td> 071 * <td>Defines the object used to render this component. The default renders a 072 * table of checkboxes. </td> 073 * </tr> 074 * <tr> 075 * <td>model</td> 076 * <td>{@link IPropertySelectionModel}</td> 077 * <td>in</td> 078 * <td>yes</td> 079 * <td> </td> 080 * <td>The model provides a list of possible labels, and matches those labels 081 * against possible values that can be assigned back to the property.</td> 082 * </tr> 083 * <tr> 084 * <td>disabled</td> 085 * <td>boolean</td> 086 * <td>in</td> 087 * <td>no</td> 088 * <td>false</td> 089 * <td>Controls whether the <select> is active or not. A disabled 090 * PropertySelection does not update its value parameter. 091 * <p> 092 * Corresponds to the <code>disabled</code> HTML attribute.</td> 093 * </tr> 094 * </table> 095 * <p> 096 * Informal parameters are not allowed. 097 * <p> 098 * As of 4.0, this component can be validated. 099 * 100 * @author Sanjay Munjal 101 */ 102 103 public abstract class MultiplePropertySelection extends AbstractFormComponent 104 implements ValidatableField 105 { 106 107 /** 108 * A shared instance of {@link CheckBoxMultiplePropertySelectionRenderer}. 109 */ 110 public static final IMultiplePropertySelectionRenderer DEFAULT_CHECKBOX_RENDERER = new CheckBoxMultiplePropertySelectionRenderer(); 111 112 public abstract Collection getSelectedList(); 113 114 public abstract void setSelectedList(Collection selectedList); 115 116 protected void finishLoad() 117 { 118 setRenderer(DEFAULT_CHECKBOX_RENDERER); 119 } 120 121 protected void renderFormComponent(IMarkupWriter writer, IRequestCycle cycle) 122 { 123 Collection selectedList = getSelectedList(); 124 125 if (selectedList == null) 126 throw Tapestry.createRequiredParameterException(this, 127 "selectedList"); 128 129 IPropertySelectionModel model = getModel(); 130 131 if (model == null) 132 throw Tapestry.createRequiredParameterException(this, "model"); 133 134 IMultiplePropertySelectionRenderer renderer = getRenderer(); 135 136 // Start rendering 137 renderer.beginRender(this, writer, cycle); 138 139 int count = model.getOptionCount(); 140 141 for(int i = 0; i < count; i++) 142 { 143 Object option = model.getOption(i); 144 145 // Try to find the option in the list and if yes, then it is 146 // checked. 147 boolean optionSelected = selectedList.contains(option); 148 149 renderer.renderOption(this, writer, cycle, model, option, i, 150 optionSelected); 151 } 152 153 // A PropertySelection doesn't allow a body, so no need to worry about 154 // wrapped components. 155 renderer.endRender(this, writer, cycle); 156 } 157 158 /** 159 * @see org.apache.tapestry.form.AbstractRequirableField#rewindFormComponent(org.apache.tapestry.IMarkupWriter, 160 * org.apache.tapestry.IRequestCycle) 161 */ 162 protected void rewindFormComponent(IMarkupWriter writer, IRequestCycle cycle) 163 { 164 // get all the values 165 String[] optionValues = cycle.getParameters(getName()); 166 167 IPropertySelectionModel model = getModel(); 168 169 List selectedList = new ArrayList(getModel().getOptionCount()); 170 171 // Nothing was selected 172 if (optionValues != null) 173 { 174 // Go through the array and translate and put back in the list 175 for(int i = 0; i < optionValues.length; i++) 176 { 177 // Translate the new value 178 Object selectedValue = model.translateValue(optionValues[i]); 179 180 // Add this element in the list back 181 selectedList.add(selectedValue); 182 } 183 } 184 185 try 186 { 187 getValidatableFieldSupport().validate(this, writer, cycle, 188 selectedList); 189 190 setSelectedList(selectedList); 191 } 192 catch (ValidatorException e) 193 { 194 getForm().getDelegate().record(e); 195 } 196 } 197 198 public abstract IPropertySelectionModel getModel(); 199 200 public abstract IMultiplePropertySelectionRenderer getRenderer(); 201 202 public abstract void setRenderer(IMultiplePropertySelectionRenderer renderer); 203 204 public abstract ValidatableFieldSupport getValidatableFieldSupport(); 205 206 /** 207 * @see org.apache.tapestry.form.AbstractFormComponent#isRequired() 208 */ 209 public boolean isRequired() 210 { 211 return getValidatableFieldSupport().isRequired(this); 212 } 213 }