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