Classes in this File | Line Coverage | Branch Coverage | Complexity | ||||
Form |
|
| 0.0;0 | ||||
Form$1 |
|
| 0.0;0 |
1 | package net.sf.jolene.dom; | |
2 | ||
3 | import net.sf.jolene.constants.Elements; | |
4 | import net.sf.jolene.constants.Tags; | |
5 | import net.sf.jolene.html.Attributes; | |
6 | import org.apache.commons.beanutils.BeanUtils; | |
7 | ||
8 | import java.util.*; | |
9 | ||
10 | /** | |
11 | * A form in a html document. This acts as a container for other html objects. | |
12 | * | |
13 | * @author Dan Howard | |
14 | * @since Oct 21, 2003 | |
15 | */ | |
16 | 0 | public final class Form extends HTMLElement { |
17 | ||
18 | List<HTMLElement> elements; | |
19 | ||
20 | 43 | Form() { |
21 | 43 | tag = Tags.form; |
22 | 43 | elements = new ArrayList<HTMLElement>(16); |
23 | 43 | } |
24 | ||
25 | ||
26 | @Override | |
27 | public Form clone() { | |
28 | 1 | Form form = (Form) super.clone(); |
29 | 13 | for (int j = 0; j < elements.size(); j++) { |
30 | 12 | HTMLElement element = elements(j).clone(); |
31 | 12 | form.addElement(element); |
32 | } | |
33 | 1 | return form; |
34 | } | |
35 | ||
36 | ||
37 | /** | |
38 | * This method returns the widget specified by the numeric index. | |
39 | * The prefered way of retrieving an object from the form is to | |
40 | * use it's name or id instead since the order of the objects can be | |
41 | * changed easily by a page designer. | |
42 | * | |
43 | * @param element - The integer element number of the object desired. | |
44 | * @return HTMLElement | |
45 | */ | |
46 | public HTMLElement elements(int element) { | |
47 | 1310 | return elements.get(element); |
48 | } | |
49 | ||
50 | /** | |
51 | * This method retrieves an object from the document by name or id. | |
52 | * When the document is opened it creates objects by looking at the ID | |
53 | * attribute first. If that attribute doesn't exist it uses the NAME | |
54 | * attribute. If neither exist then the only way to address these | |
55 | * objects is by number (not recommended).<br> | |
56 | * This method returns the base HTMLElement object so if you want a Select or | |
57 | * Grid object you can either cast it: | |
58 | * <pre> | |
59 | * Grid grid grid = (Grid)document.forms(0).elements("Grid1"); | |
60 | * </pre> | |
61 | * or use the appropriate getter: | |
62 | * <pre> | |
63 | * Grid grid = document.forms(0).getGrid("Grid1"); | |
64 | * </pre> | |
65 | * | |
66 | * @param elementName - The string name or id of the object desired. | |
67 | * @return HTMLElement or null if not found or elementName is null. | |
68 | */ | |
69 | public HTMLElement elements(String elementName) { | |
70 | ||
71 | 100 | if (elementName == null) { |
72 | 0 | return null; |
73 | } | |
74 | ||
75 | // locate the object whose name == this string. | |
76 | 100 | String name = ""; |
77 | HTMLElement element; | |
78 | int j; | |
79 | ||
80 | 603 | for (j = 0; j < elements.size(); j++) { |
81 | ||
82 | 597 | if (elementName.equalsIgnoreCase(elements.get(j).getName())) { |
83 | 94 | break; |
84 | } | |
85 | /* | |
86 | if (element.hasAttribute("id")) { | |
87 | name = element.getAttribute("id"); | |
88 | if (name.equalsIgnoreCase(elementName)) { | |
89 | break; // found it. | |
90 | } | |
91 | } else if (element.hasAttribute("name")) { | |
92 | name = (String) element.getAttribute("name"); | |
93 | if (name.equalsIgnoreCase(elementName)) { | |
94 | break; // found it. | |
95 | } | |
96 | } else { | |
97 | // We have to throw an exception here? We have an object with no NAME!!!!! | |
98 | ||
99 | } | |
100 | */ | |
101 | ||
102 | } | |
103 | ||
104 | 100 | if (j < elements.size()) { |
105 | 94 | return elements(j); |
106 | } else { | |
107 | // THROW EXCEPTION | |
108 | // Based on the HashMap, no exception is thrown but a null is returned which | |
109 | // will cause a null pointer exception later. | |
110 | 6 | return null; |
111 | } | |
112 | } | |
113 | ||
114 | ||
115 | /** | |
116 | * @return Number of elements in the form. | |
117 | */ | |
118 | public int getElementCount() { | |
119 | 17 | return elements.size(); |
120 | } | |
121 | ||
122 | /** | |
123 | * Returns the specified element casted to a Grid object. | |
124 | * | |
125 | * @param name name of grid | |
126 | * @return Grid | |
127 | */ | |
128 | public Grid getGrid(String name) { | |
129 | 0 | return (Grid) elements(name); |
130 | } | |
131 | ||
132 | /** | |
133 | * Returns a Map of Radio objects based the specified radio group name. | |
134 | * The map's order is insertion-order. | |
135 | * | |
136 | * @param groupName of radios | |
137 | * @return Map<String, HTMLElement> | |
138 | */ | |
139 | public Map<String, HTMLElement> getRadioGroup(String groupName) { | |
140 | 2 | Map<String, HTMLElement> map = new LinkedHashMap<String, HTMLElement>(3); |
141 | // loop through the objects for radios with the specified name | |
142 | // and add each to a hashmap based on their VALUE attribute. | |
143 | // If no value exists, log a warn and add each with an integer as | |
144 | // the key. | |
145 | 32 | for (int j = 0; j < elements.size(); j++) { |
146 | 30 | HTMLElement element = elements.get(j); |
147 | 30 | if (element instanceof Radio) { |
148 | 6 | if (groupName.equalsIgnoreCase(element.getName())) { |
149 | 6 | log.debug("Radio " + groupName + " found."); |
150 | String key; | |
151 | 6 | if (element.hasAttribute("value")) { |
152 | 6 | key = element.getAttribute("value"); |
153 | 6 | log.debug("Radio " + groupName + " key " + key); |
154 | } else { | |
155 | 0 | key = String.valueOf(j); |
156 | 0 | log.debug("getRadioGroup: Radio has no value: " + element + " assigning " + key); |
157 | } | |
158 | 6 | map.put(key, element); |
159 | } | |
160 | } | |
161 | } | |
162 | 2 | return map; |
163 | } | |
164 | ||
165 | /** | |
166 | * Returns the specified element casted to a Select object. | |
167 | * | |
168 | * @param name name of select | |
169 | * @return Select | |
170 | */ | |
171 | public Select getSelect(String name) { | |
172 | 4 | return (Select) elements(name); |
173 | } | |
174 | ||
175 | /** | |
176 | * Checks if the specified object exists in the form. | |
177 | * | |
178 | * @param name name to check | |
179 | * @return boolean | |
180 | */ | |
181 | public boolean hasElement(String name) { | |
182 | 10 | return elements(name) != null; |
183 | } | |
184 | ||
185 | /* | |
186 | public Label getLabel(String name) { | |
187 | return (Label) elements(name); | |
188 | } | |
189 | ||
190 | public Button getButton(String name) { | |
191 | return (Button) elements(name); | |
192 | } | |
193 | */ | |
194 | ||
195 | /** | |
196 | * Poplates the form objects based on the supplied java bean. | |
197 | * | |
198 | * @param bean any object which can be examined by BeanUtils. | |
199 | * @throws FormPolulateException if BeanUtils fails. | |
200 | */ | |
201 | public void populate(Object bean) throws FormPolulateException { | |
202 | ||
203 | 1 | Map<String, String> map = null; |
204 | //@todo should this support nested properties like the grid? | |
205 | try { | |
206 | 1 | map = BeanUtils.describe(bean); |
207 | 0 | } catch (Exception e) { |
208 | 0 | throw new FormPolulateException(e); |
209 | 1 | } |
210 | 1 | populate(map); |
211 | 1 | } |
212 | ||
213 | /** | |
214 | * Populates the form object from the supplied map object. | |
215 | * | |
216 | * @param map - name/values where names match element names | |
217 | */ | |
218 | public void populate(Map<String, String> map) { | |
219 | 1 | Map<String, String> radios = new HashMap<String, String>(3); |
220 | ||
221 | 1 | Iterator it = map.keySet().iterator(); |
222 | 11 | while (it.hasNext()) { |
223 | 10 | String key = (String) it.next(); |
224 | ||
225 | // Prevent null values in the bean from throwing null pointer | |
226 | String value; | |
227 | 10 | if (map.get(key) == null) { |
228 | 0 | value = ""; |
229 | } else { | |
230 | 10 | value = (String) map.get(key); |
231 | } | |
232 | ||
233 | 10 | if (hasElement(key.toString())) { |
234 | // Do not auto populate Radios since we don't really | |
235 | // know which radio to assign the value to since usually | |
236 | // they would have the same name. See getRadioGroup() method. | |
237 | 9 | if (elements(key) instanceof Radio) { |
238 | 1 | radios.put(key, ""); |
239 | } else { | |
240 | 8 | if (elements(key) instanceof CheckBox) { |
241 | 1 | if (value.equalsIgnoreCase("true")) { |
242 | 1 | elements(key).setChecked(true); |
243 | } else { | |
244 | 0 | elements(key).setChecked(false); |
245 | } | |
246 | } else { | |
247 | 7 | elements(key).setValue(value); |
248 | } | |
249 | } | |
250 | } | |
251 | 10 | } |
252 | ||
253 | /* | |
254 | Check radios. If there are any radios that matched a field in the bean | |
255 | then it means that maybe that fields value matches a radio value from the | |
256 | group. For each group check if the values match and set the CHECKED for | |
257 | the ones that do. | |
258 | */ | |
259 | 1 | it = radios.keySet().iterator(); |
260 | 2 | while (it.hasNext()) { |
261 | String key; | |
262 | 1 | key = it.next().toString(); |
263 | ||
264 | Iterator<HTMLElement> itGroup; | |
265 | 1 | itGroup = getRadioGroup(key).values().iterator(); |
266 | 4 | while (itGroup.hasNext()) { |
267 | 3 | HTMLElement radio = itGroup.next(); |
268 | 3 | radio.setChecked(false); |
269 | 3 | if (radio.getValue() != null && map.get(key) != null) { |
270 | 3 | if (radio.getValue().equalsIgnoreCase(map.get(key).toString())) { |
271 | 1 | radio.setChecked(true); |
272 | } | |
273 | } | |
274 | 3 | } |
275 | 1 | } |
276 | ||
277 | 1 | } |
278 | ||
279 | final HTMLElement addObject(Elements type, Attributes attributes, int start, int end) { | |
280 | ||
281 | HTMLElement element; | |
282 | ||
283 | 309 | log.debug("TYPE:" + type); |
284 | ||
285 | 1 | switch (type) { |
286 | ||
287 | case select: | |
288 | 30 | element = new Select(); |
289 | 30 | break; |
290 | ||
291 | case textarea: | |
292 | 7 | element = new TextArea(); |
293 | 7 | break; |
294 | ||
295 | case label: | |
296 | 15 | element = new Label(); |
297 | 15 | break; |
298 | ||
299 | case button: | |
300 | 4 | element = new Button(); |
301 | 4 | break; |
302 | ||
303 | case image: | |
304 | 78 | element = new Image(); |
305 | 78 | break; |
306 | ||
307 | case grid: | |
308 | 11 | element = new Grid(); |
309 | 11 | break; |
310 | ||
311 | case radio: | |
312 | 18 | element = new Radio(); |
313 | 18 | break; |
314 | ||
315 | case checkbox: | |
316 | 14 | element = new CheckBox(); |
317 | 14 | break; |
318 | ||
319 | case text: | |
320 | 3 | element = new Text(); |
321 | 3 | break; |
322 | ||
323 | default: | |
324 | 129 | element = new Input(); |
325 | } | |
326 | ||
327 | 309 | log.debug("CLASS:" + element.getClass().getName()); |
328 | ||
329 | 309 | Iterator i = attributes.keySet().iterator(); |
330 | ||
331 | 1233 | while (i.hasNext()) { |
332 | String key, value; | |
333 | 924 | key = (String) i.next(); |
334 | 924 | value = attributes.getAttribute(key); |
335 | 924 | element.setAttribute(key, value); |
336 | ||
337 | // Ensure to call setValue for values. | |
338 | 924 | if ("value".equalsIgnoreCase(key)) { |
339 | 94 | element.setValue(value); |
340 | } | |
341 | 924 | } |
342 | ||
343 | // Also assign the object's name if found. | |
344 | 309 | if (attributes.hasAttribute("name")) { |
345 | 183 | element.setName(attributes.getAttribute("name")); |
346 | 126 | } else if (attributes.hasAttribute("id")) { |
347 | 29 | element.setName(attributes.getAttribute("id")); |
348 | } | |
349 | ||
350 | 309 | element.setStartPoint(start); |
351 | 309 | element.setEndPoint(end); |
352 | ||
353 | 309 | elements.add(element); |
354 | 309 | return element; |
355 | } | |
356 | ||
357 | /** | |
358 | * Used for cloning. | |
359 | * | |
360 | * @param element to add | |
361 | * @return HTMLElement | |
362 | */ | |
363 | HTMLElement addElement(HTMLElement element) { | |
364 | 12 | elements.add(element); |
365 | 12 | return element; |
366 | } | |
367 | ||
368 | ||
369 | } |