001// Copyright (c) 2001 Hursh Jain (http://www.mollypages.org) 002// The Molly framework is freely distributable under the terms of an 003// MIT-style license. For details, see the molly pages web site at: 004// http://www.mollypages.org/. Use, modify, have fun ! 005 006package fc.web.forms; 007 008import javax.servlet.*; 009import javax.servlet.http.*; 010import java.io.*; 011import java.util.*; 012 013import fc.jdbc.*; 014import fc.io.*; 015import fc.util.*; 016 017/** 018Abstracts an HTML choice type such as choicebox or radio. 019Does <b>not</b> abstract a HTML select element for which the 020{@link Select} class should be used. Concrete subclasses 021represent a particular choice element such as {@link 022Checkbox} and {@link Radio} 023 024@author hursh jain 025**/ 026public abstract class Choice extends Field 027{ 028//if this choice object's original state == selected 029private boolean orig_selected; 030//can be null if not specified 031private String value; 032 033static class Data { 034 //the value actually submitted by the browser (could 035 //be 'on', 'ON' etc., or the value for that option (if set) 036 private String submit_value; 037 } 038 039/** 040Creates a new choice object. 041 042@param name the field name 043@param value the value of this choice item (can be null 044 for unspecified) 045@param selected <tt>true</tt> is this choice is 046 originally selected 047**/ 048protected Choice(String name, String value, boolean selected) 049 { 050 super(name); 051 this.value = value; 052 this.orig_selected = selected; 053 } 054 055public abstract Field.Type getType(); 056 057/** 058Returns the current <b>value</b> of this field. This can be: 059<blockquote> 060 <li><tt>null</tt>: if no value is currently set which can happen if 061 this field was not selected when the parent form was submitted. 062 Browsers send nothing at all if choice type fields are not selected 063 in an HTML form. 064 <li>the value attribute of this field (if this choice field was 065 created/displayed with a value attribute) or the string "on" (which 066 is sent by browsers if there is no specific value attribute for this 067 choice field). Note, the default value should be treated as case 068 <u>in</u>sensitive, since browsers can send <tt>on</tt>, <tt>ON</tt> 069 etc. 070</blockquote> 071**/ 072public String getValue(FormData fd) 073 { 074 Choice.Data data = (Choice.Data) fd.getData(name); 075 076 if (data == null) 077 return null; 078 079 return data.submit_value; 080 } 081 082/** 083Sets the <u>selected or non-selected state</u> for this choice in the 084specified form data. Selected choices are returned by the browser as 085<tt>on, ON, oN</tt> etc., the value returned is not important as long as 086something is returned. Therefore <i>any non-null value</i> set by this method 087will have the effect of selecting this choice when it is rendered. A <tt> 088null</tt> value wil unselect this choice. 089 090@param fd a non-null form data object 091@param value any non-null value 092*/ 093public void setValue(FormData fd, String value) 094 { 095 Argcheck.notnull(fd, "specified fd param was null"); 096 097 if (value == null) 098 return; 099 100 Choice.Data data = new Choice.Data(); 101 fd.putData(name, data); 102 data.submit_value = value; 103 } 104 105/** 106Convenience method that sets this choice to be selected/non-selected. 107 108@param fd a non-null form data object 109@param selected true to select this choice, false otherwise 110*/ 111public void setValue(FormData fd, boolean selected) 112 { 113 Argcheck.notnull(fd, "specified fd param was null"); 114 115 if (selected) { 116 Choice.Data data = new Choice.Data(); 117 fd.putData(name, data); 118 //not submit_value = value since value can be null 119 data.submit_value = "on"; 120 } 121 } 122 123/** 124Sets the value for this choice. 125*/ 126public void setValue(String value, boolean selected) 127 { 128 Argcheck.notnull(value, "specified value was null"); 129 130 this.value = value; 131 this.orig_selected = selected; 132 } 133 134/** 135Convenience method that returns the value of this 136field as a Integer. 137 138@throws NumberFormatException if the value could not be 139 returned as in integer. 140*/ 141public int getIntValue(FormData fd) { 142 String value = getValue(fd); 143 if (value != null) 144 value = value.trim(); 145 return Integer.parseInt(value); 146 } 147 148/** 149Convenience method that returns the value of this 150field as a Short. 151 152@throws NumberFormatException if the value could not be 153 returned as a short. 154*/ 155public short getShortValue(FormData fd) { 156 String value = getValue(fd); 157 if (value != null) 158 value = value.trim(); 159 return Short.parseShort(value); 160 } 161 162 163/** 164Convenience method that returns the value of this field as a boolean. 165<u>The returned value will be <tt>true</tt> if the submitted value is 166"true" or "on" (both case insensitive), else <tt>false</tt></u> 167*/ 168public boolean getBooleanValue(FormData fd) 169 { 170 String value = getValue(fd); 171 if (value == null) 172 return false; 173 174 if (value.equalsIgnoreCase("on")) 175 value = "true"; 176 177 return Boolean.valueOf(value).booleanValue(); 178 } 179 180//the value actually submitted by the browser (could 181//be 'on', 'ON' etc., or the value for that option if set 182public void setValueFromSubmit(FormData fd, HttpServletRequest req) 183throws SubmitHackedException 184 { 185 String submittedValue = req.getParameter(name); 186 187 //choice was not selected 188 if (submittedValue == null) 189 return; 190 191 Choice.Data data = new Choice.Data(); 192 fd.putData(name, data); 193 194 if (value != null && ! value.equals(submittedValue)) 195 hacklert(req, "submitted value: [" + submittedValue + "] does not equal the value [" + value + "]of this field."); 196 197 data.submit_value = submittedValue; 198 //log.bug(name, "setting data=", submittedValue); 199 } 200 201public void renderImpl(FormData fd, Writer writer) throws IOException 202 { 203 boolean selected = false; 204 205 //no formdata, rendering first time 206 if (fd == null) { 207 selected = this.orig_selected; 208 } 209 else { //submit or initial data 210 String returned_value = getValue(fd); //can be null 211 if (returned_value != null) 212 selected = true; 213 } 214 215 writer.write("<input type='"); 216 writer.write(getType().toString()); 217 writer.write("' name='"); 218 writer.write(name); 219 writer.write("'"); 220 221 if (value != null) { 222 //we always write the orig. value, not the returned 223 //one (since the returned value should be the same 224 //as the original value unless hacked) 225 writer.write(" value='"); 226 writer.write(value); 227 writer.write("'"); 228 } 229 230 if (! enabled || ! isEnabled(fd)) { 231 writer.write(" disabled"); 232 } 233 234 if (selected) { 235 writer.write(" checked"); 236 } 237 238 if (renderStyleTag) { 239 writer.write(" style='"); 240 writer.write(styleTag); 241 writer.write("'"); 242 } 243 244 final int arlen = arbitraryString.size(); 245 for (int n = 0; n < arlen; n++) { 246 writer.write(" "); 247 writer.write(arbitraryString.get(n).toString()); 248 } 249 250 writer.write(">"); 251 writer.write("</input>"); 252 } 253 254 255/** 256@return <tt>true</tt> if this field is selected, 257 <tt>false</tt> otherwise 258**/ 259public boolean isFilled(FormData fd) 260 { 261 return getValue(fd) != null; 262 } 263 264/** 265Sets the <b>initial</b> selection status for this field. 266 267@param select <tt>true</tt> if this field should be selected 268 <tt>false</tt> otherwise. 269**/ 270public void setSelected(boolean select) { 271 this.orig_selected = select; 272 } 273 274 275public String toString() 276 { 277 return super.toString() + 278 "; Orig. value: [" + value + "]" + 279 "; Orig. selected: [" + orig_selected + "]"; 280 } 281 282}