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
006 package fc.web.forms;
007
008 import java.lang.reflect.*;
009 import java.io.*;
010 import java.text.*;
011 import java.util.*;
012
013 import fc.jdbc.*;
014 import fc.io.*;
015 import fc.util.*;
016 import fc.web.forms.*;
017 //for testing
018 import fc.jdbc.dbo.generated.*;
019
020 /**
021 Misc. form related utilities.
022
023 @author hursh jain
024 */
025 public class FormUtil
026 {
027 private static final Class[] classarr = new Class[] { };
028 private static final Object[] objarr = new Object[] { };
029
030 /**
031 <b>Note: This method is almost never needed. Use the {@link Select#useQuery(Connection, String)}
032 method instead.
033 </b>
034 <p>
035 Fills in the specified select with values from the supplied list. This is
036 intended to show a select widget corresponding to a lookup table in the
037 database. The list will typically be returned by <tt>getAll/getWhere</tt>
038 methods of some generated {@link fc.jdbc.dbo.DBOMgr} class.
039 <p>
040 For example, given a lookup table object <tt>Foo</tt> and a corresponding
041 manager object <tt>FooMgr</tt> and an empty previously-instantiated
042 select:
043 <tt>
044 <blockquote>
045 <pre>
046 Select select = new Select("myselect")
047 fillSelect(select, FooMgr.getAll(),
048 "--choose--",
049 Foo.class, <font color=red>"getID"</font>,
050 <font color=red>"getValue"</font>);
051 </pre>
052 </blockquote>
053 </tt>
054 and where table Foo has the following data
055 <blockquote>
056 <tt><pre>
057 Table Foo
058 <font color=red>
059 ID Value</font>
060 -----------------------------------
061 1 "lookup_one"
062 2 "lookup_two"
063 3 "lookup_three"
064 </pre></tt>
065 </blockquote>
066 will add the following values to the select:
067 <blockquote>
068 <tt>
069 <pre>
070 <option>--choose--</option>
071 <option value=1>lookup_one</option>
072 <option value=2>lookup_two</option>
073 <option value=3>lookup_three</option>
074 </pre>
075 </tt>
076 </blockquote>
077 <p>
078
079 @param select
080 a select object to be filled in
081 @param list
082 list of objects of type beanClass. Typically
083 this would be obtained via invoking the
084 <tt>beanClassMgr.getAll()</tt> method
085 @param message
086 an optional message to show as the first value of
087 the select option (typically <tt>---select--</tt>
088 or <tt>--choose an option--</tt> etc.). Specify
089 <tt>null</tt> to skip creating this optional message.
090 @param beanClass
091 the {@link DBO} class corresponding to some lookuptable in the
092 database
093 @param valueMethodName
094 the name of the method in the {@link DBO} class which will be used to
095 create the value for a radio button [ without "()"]
096 @param htmlTextMethodName
097 the name of the method in the {@link DBO} class which will be used to
098 create the html text displayed to the user for a radio button [name
099 should be without "()"]
100
101 @throws IllegalArgumentException
102 if an error occurred in getting the specified methods
103 from the specified class and invoking them on the
104 specified list
105 */
106 public static void fillSelect(
107 Select select, List list, String message,
108 Class beanClass,
109 String valueMethodName, String htmlTextMethodName)
110 {
111 if (message != null)
112 select.add(new Select.Option(message));
113
114 try {
115 Method value_method = beanClass.getDeclaredMethod(
116 valueMethodName, classarr);
117 Method html_method = beanClass.getDeclaredMethod(
118 htmlTextMethodName, classarr);
119
120 for (int n = 0; n < list.size(); n++)
121 {
122 Object obj = list.get(n);
123 String value = String.valueOf(value_method.invoke(obj, objarr));
124 String html = String.valueOf(html_method.invoke(obj, objarr));
125 select.add(new Select.Option(html, value));
126 }
127 }
128 catch (Exception e) {
129 throw new IllegalArgumentException(IOUtil.throwableToString(e));
130 }
131 }
132
133 /**
134 <b>Note: This method is almost never needed. Use the {@link Select#useQuery(Connection, String)}
135 method instead.
136 </b>
137 <p>
138 Fills in the specified select with values from the supplied map. This is
139 intended to show a select widget corresponding to a lookup table in the
140 database. The list will typically be returned by <tt>getAll/getWhere</tt>
141 methods of some generated {@link fc.jdbc.dbo.DBOMgr} class.
142 <p>
143 For example, given a lookup table object <tt>Foo</tt> and a corresponding
144 manager object <tt>FooMgr</tt> and an empty previously-instantiated
145 select:
146 <tt>
147 <blockquote>
148 <pre>
149 Select select = new Select("myselect")
150 fillSelect(select, FooMgr.getAll(),
151 "--choose--",
152 Foo.class, <font color=red>"getID"</font>,
153 <font color=red>"getValue"</font>);
154 </pre>
155 </blockquote>
156 </tt>
157 and where table Foo has the following data
158 <blockquote>
159 <tt><pre>
160 Table Foo
161 <font color=red>
162 ID Value</font>
163 -----------------------------------
164 1 "lookup_one"
165 2 "lookup_two"
166 3 "lookup_three"
167 </pre></tt>
168 </blockquote>
169 will add the following values to the select:
170 <blockquote>
171 <tt>
172 <pre>
173 <option>--choose--</option>
174 <option value=1>lookup_one</option>
175 <option value=2>lookup_two</option>
176 <option value=3>lookup_three</option>
177 </pre>
178 </tt>
179 </blockquote>
180 <p>
181
182 @param select
183 a select object to be filled in
184 @param values
185 A map containing the values for the select. For each key, value pair,
186 the following will be generated for the select:
187 <pre><option value="key-part">value-part</option>
188 @param message
189 an optional message to show as the first value of the select option
190 (typically <tt>---select--</tt> or <tt>--choose an option--</tt> etc.).
191 Specify <tt>null</tt> to skip creating this optional message.
192
193 */
194 public static void fillSelect(Select select, Map values, String message)
195 {
196 if (message != null)
197 select.add(new Select.Option(message));
198
199 try {
200 Iterator it = values.entrySet().iterator();
201 while (it.hasNext()) {
202 Map.Entry e = (Map.Entry)it.next();
203 select.add(new Select.Option((String)e.getKey(), (String)e.getValue()));
204 }
205 }
206 catch (Exception e) {
207 throw new IllegalArgumentException(IOUtil.throwableToString(e));
208 }
209 }
210
211
212 /**
213 Fills in the specified radiogroup with values from the supplied list. This
214 is intended to show radio groups corresponding to a lookup table in the
215 database. The list will typically be returned by <tt>getAll/getWhere</tt>
216 methods of some generated {@link fc.jdbc.dbo.DBOMgr} class. <p> For
217 example, given a lookup table object <tt>Foo</tt> and a corresponding
218 manager object <tt>FooMgr</tt> and a empty previously-instantiated radio
219 group:
220 <tt>
221 <blockquote>
222 <pre>
223 RadioGroup rg = new RadioGroup("myradio")
224 fillRadioGroup(select, FooMgr.getAll(),
225 Foo.class, <font color=red>"getID"</font>,
226 <font color=red>"getValue"</font>);
227 </pre>
228 </blockquote>
229 </tt>
230 and where table Foo has the following data:
231 <blockquote>
232 <tt><pre>
233 Table Foo
234 <font color=red>
235 ID Value</font>
236 -----------------------------------
237 1 "lookup_one"
238 2 "lookup_two"
239 3 "lookup_three"
240 </pre></tt>
241 </blockquote>
242 will add those values to the radio group.
243
244 @param rg
245 a radio group object to be filled in
246 @param list
247 list of objects of type beanClass. Typically
248 this would be obtained via invoking the
249 <tt>beanClassMgr.getAll()</tt> method
250 @param beanClass
251 the {@link DBO} class corresponding to some lookuptable in the
252 database
253 @param valueMethodName
254 the name of the method in the {@link DBO} class which will be used to
255 create the value for a radio button [ without "()"]
256 @param htmlTextMethodName
257 the name of the method in the {@link DBO} class which will be used to
258 create the html text displayed to the user for a radio button [name
259 should be without "()"]
260
261 @throws IllegalArgumentException
262 if an error occurred in getting the specified methods
263 from the specified class and invoking them on the
264 specified list
265 */
266 public static void fillRadioGroup(
267 RadioGroup rg, List list, Class beanClass,
268 String valueMethodName, String htmlTextMethodName)
269 {
270 try {
271 Method value_method = beanClass.getDeclaredMethod(
272 valueMethodName, classarr);
273 Method html_method = beanClass.getDeclaredMethod(
274 htmlTextMethodName, classarr);
275 for (int n = 0; n < list.size(); n++)
276 {
277 Object obj = list.get(n);
278 String value = String.valueOf(value_method.invoke(obj, objarr));
279 String html = String.valueOf(html_method.invoke(obj, objarr));
280 ChoiceGroup.Choice c = new ChoiceGroup.Choice(html, value); //auto adds it to rg
281 rg.add(c);
282 }
283 }
284 catch (Exception e) {
285 throw new IllegalArgumentException(IOUtil.throwableToString(e));
286 }
287 }
288
289 /**
290 Fills in the specified checkboxgroup with values from the supplied list.
291 This is intended to show checkbox groups corresponding to a lookup table
292 in the database. The list will typically be returned by <tt>getAll or
293 getWhere</tt> methods of some generated {@link fc.jdbc.dbo.DBOMgr} class.
294 <p>
295 For example, given a lookup table object <tt>Foo</tt> and a corresponding
296 manager object <tt>FooMgr</tt> and a empty previously-instantiated
297 checkbox group:
298 <tt>
299 <blockquote>
300 <pre>
301 CheckboxGroup rg = new CheckboxGroup("mycbgroup")
302 fillCheckboxGroup(select, FooMgr.getAll(),
303 Foo.class, <font color=red>"getID"</font>,
304 <font color=red>"getValue"</font>);
305 </pre>
306 </blockquote>
307 </tt>
308 and where table Foo has the following data:
309 <blockquote>
310 <tt><pre>
311 Table Foo
312 <font color=red>
313 ID Value</font>
314 -----------------------------------
315 1 "lookup_one"
316 2 "lookup_two"
317 3 "lookup_three"
318 </pre></tt>
319 </blockquote>
320 will add those values to the checkbox group.
321
322 @param cbg
323 a checkbox group object to be filled in
324 @param list
325 list of objects of type beanClass. Typically
326 this would be obtained via invoking the
327 <tt>beanClassMgr.getAll()</tt> method
328 @param beanClass
329 the {@link DBO} class corresponding to some lookuptable in the
330 database
331 @param valueMethodName
332 the name of the method in the {@link DBO} class which will be used to
333 create the value for a radio button [ without "()"]
334 @param htmlTextMethodName
335 the name of the method in the {@link DBO} class which will be used to
336 create the html text displayed to the user for a radio button [name
337 should be without "()"]
338
339 @throws IllegalArgumentException
340 if an error occurred in getting the specified methods
341 from the specified class and invoking them on the
342 specified list
343 */
344 public static void fillCheckboxGroup(
345 CheckboxGroup cbg, List list, Class beanClass,
346 String valueMethodName, String htmlTextMethodName)
347 {
348 try {
349 Method value_method = beanClass.getDeclaredMethod(
350 valueMethodName, classarr);
351 Method html_method = beanClass.getDeclaredMethod(
352 htmlTextMethodName, classarr);
353 for (int n = 0; n < list.size(); n++)
354 {
355 Object obj = list.get(n);
356 String value = String.valueOf(value_method.invoke(obj, objarr));
357 String html = String.valueOf(html_method.invoke(obj, objarr));
358 ChoiceGroup.Choice c = new ChoiceGroup.Choice(html, value); //auto adds it to rg
359 cbg.add(c);
360 }
361 }
362 catch (Exception e) {
363 throw new IllegalArgumentException(IOUtil.throwableToString(e));
364 }
365 }
366
367
368 /**
369 Fills the specified select from years, starting with the specified year
370 till the current year. No year option is pre-selected.
371 */
372 public static Select fillSelectWithYears(Select s, int startYear)
373 {
374 int now = Calendar.getInstance().get(Calendar.YEAR);
375 for (int n = startYear; n <= now; n++)
376 {
377 Select.Option so = new Select.Option(n + "");
378 s.add(so);
379 }
380 return s;
381 }
382
383 /**
384 Fills the specified select from years, starting with the specified year.
385 The current year (on the server) is pre-selected.
386 */
387 public static Select fillSelectWithYearsToday(Select s, int startYear)
388 {
389 return fillSelectWithYears(s, startYear, Calendar.getInstance());
390 }
391
392 /**
393 Fills the specified select from years, starting with the specified year,
394 upto the current year. The date from the specified calendar is
395 pre-selected.
396 */
397 public static Select fillSelectWithYears(
398 Select s, int startYear, Calendar yearToSelect)
399 {
400 int now = Calendar.getInstance().get(Calendar.YEAR);
401 int select = yearToSelect.get(Calendar.YEAR);
402
403 for (int n = startYear; n <= now; n++)
404 {
405 Select.Option so = (n == select) ? new Select.Option(n + "", true) :
406 new Select.Option(n + "");
407 s.add(so);
408 }
409 return s;
410 }
411
412 /**
413 Fills the specified select from years, from the specified start and end
414 years (both inclusive). The date from the specified calendar is
415 pre-selected.
416 */
417 public static Select fillSelectWithYears(
418 Select s, int startYear, int endYear, Calendar cal)
419 {
420 int select = cal.get(Calendar.YEAR);
421
422 for (int n = startYear; n <= endYear; n++)
423 {
424 Select.Option so = (n == select) ? new Select.Option(n + "", true) :
425 new Select.Option(n + "");
426 s.add(so);
427 }
428 return s;
429 }
430
431 private static String[] months = new String[]
432 {
433 /*0-th is empty -->*/ "",
434 "Jan", "Feb", "March", "Apr", "May", "June", "July",
435 "Aug", "Sept", "Oct", "Nov", "Dec"
436 };
437
438 //TODO: i18n
439 /**
440 Fills the specified select from years, starting with the specified year.
441 <tt>monthsAsText</tt> specifies whether months are displayed as names
442 or numbers. (true for names). No month is preselected.
443 */
444 public static Select fillSelectWithMonths(Select s, boolean monthsAsText)
445 {
446 String month = null;
447 for (int n = 1; n <= 12; n++)
448 {
449 if (monthsAsText)
450 month = months[n];
451 else
452 month = n + "";
453
454 Select.Option so = new Select.Option(n+"", month);
455 s.add(so);
456 }
457 return s;
458 }
459
460 /**
461 Fills the specified select from years, starting with the specified year.
462 <tt>monthsAsText</tt> specifies whether months are displayed as names or
463 numbers. (true for names). The current month (on the server) is preselected.
464 */
465 public static Select fillSelectWithMonthsToday(Select s, boolean monthsAsText)
466 {
467 return fillSelectWithMonths(s, monthsAsText, Calendar.getInstance());
468 }
469
470 /**
471 Fills the specified select from years, starting with the specified year.
472 <tt>monthsAsText</tt> specifies whether months are displayed as names or
473 numbers. (true for names). The current month from the specified calendar is
474 is preselected.
475 */
476 public static Select fillSelectWithMonths(
477 Select s, boolean monthsAsText, Calendar cal)
478 {
479 String month = null;
480 int current_month = cal.get(Calendar.MONTH)/*0-based*/ + 1;
481
482 for (int n = 1; n <= 12; n++)
483 {
484 if (monthsAsText)
485 month = months[n];
486 else
487 month = n + "";
488
489 Select.Option so = (n == current_month) ?
490 new Select.Option(n+"", month, true)
491 : new Select.Option(n+"", month);
492 s.add(so);
493 }
494 return s;
495 }
496
497
498 /**
499 Fills the specified select from years, starting with the specified year.
500 No day is pre-selected.
501 */
502 public static Select fillSelectWithDays(Select s)
503 {
504 for (int n = 1; n <= 31; n++)
505 {
506 Select.Option so = new Select.Option(n + "");
507 s.add(so);
508 }
509 return s;
510 }
511
512 /**
513 Fills the specified select from years, starting with the specified year.
514 Today (on the server side) is preselected.
515 */
516 public static Select fillSelectWithDaysToday(Select s)
517 {
518 return fillSelectWithDays(s, Calendar.getInstance());
519 }
520
521 /**
522 Fills the specified select from years, starting with the specified year.
523 The day in the specified date is preselected.
524 */
525 public static Select fillSelectWithDays(Select s, Calendar cal)
526 {
527 int today = cal.get(Calendar.DATE);
528 for (int n = 1; n <= 31; n++)
529 {
530 Select.Option so = (n == today) ? new Select.Option(n + "", true)
531 : new Select.Option(n + "");
532 s.add(so);
533 }
534 return s;
535 }
536
537 /**
538 Converts a year, month and day into a java.sql.Date
539 */
540 public static java.sql.Date toDate(String year, String month, String day)
541 {
542
543 java.sql.Date date = new java.sql.Date(
544 new java.util.Date(
545 Integer.parseInt(year)-1900,
546 Integer.parseInt(month)-1,
547 Integer.parseInt(day)).getTime());
548 return date;
549 }
550
551 /**
552 Converts a time string into a java.sql.Time. Time is of the format: HH:MM
553 (for example: <tt>1:23</tt> or <tt>01:23</tt>). Returns null if the
554 string could not be parsed. (Hours upto 12 are allowed but not 13 or
555 more). This method is suitable for a text box that takes 1-12 hours
556 and a seperate am/pm select option next to it.
557 */
558 public static java.sql.Time toTime(final String time)
559 {
560 java.util.Date date = null;
561 final DateFormat df = new SimpleDateFormat("h:mm");
562 try {
563 date = df.parse(time);
564 }
565 catch (Exception e) {
566 return null;
567 }
568
569 return new java.sql.Time(date.getTime());
570 }
571
572
573 public static void main(String args[]) throws Exception
574 {
575 PrintWriter pw = new PrintWriter(System.out);
576 Select select = new Select("foo");
577
578 Args myargs = new Args(args);
579 myargs.setUsage("java fc.web.form.FormUtil -conf conf-file");
580
581 String propfile = myargs.getRequired("conf");
582
583 ConnectionMgr mgr = new SimpleConnectionMgr(
584 new FilePropertyMgr(
585 new File(propfile)));
586 java.sql.Connection con = mgr.getConnection();
587
588 List list = alltypesMgr.getAll(con);
589
590 long start = System.currentTimeMillis();
591 fillSelect(select, list, "--choose--", alltypes.class,
592 "get_id", "get_char_val");
593 System.out.println("time for first fillSelect() calls = " + (System.currentTimeMillis() - start) + " ms");
594 select.render(pw);
595 fillSelect(select, list, "--choose--", alltypes.class,
596 "get_id", "get_date_val");
597 select.render(pw);
598 fillSelect(select, list, "--choose--", alltypes.class,
599 "get_id", "get_int_val");
600 select.render(pw);
601 fillSelect(select, list, "--choose--", alltypes.class,
602 "get_id", "get_boolean_val");
603 select.render(pw);
604
605
606 RadioGroup rg = new RadioGroup("rg");
607 start = System.currentTimeMillis();
608 fillRadioGroup(rg, list, alltypes.class,
609 "get_id", "get_char_val");
610 System.out.println("time for first fillRadioGroup() calls = " + (System.currentTimeMillis() - start) + " ms");
611 rg.render(pw);
612 fillRadioGroup(rg, list, alltypes.class,
613 "get_id", "get_date_val");
614 rg.render(pw);
615 fillRadioGroup(rg, list, alltypes.class,
616 "get_id", "get_int_val");
617 rg.render(pw);
618 fillRadioGroup(rg, list, alltypes.class,
619 "get_id", "get_boolean_val");
620 rg.render(pw);
621
622 Date d = new Date();
623 System.out.println(d.getYear() + " " + d.getMonth() + " " + d.getDay());
624
625 select = new Select("years");
626 fillSelectWithYears(select, 1995);
627 select.render(pw);
628
629 fillSelectWithYears(select, 1995);
630 select.render(pw);
631
632 select = new Select("months");
633 fillSelectWithMonths(select, true);
634 select.render(pw);
635
636 select = new Select("days");
637 fillSelectWithDays(select);
638 select.render(pw);
639
640 pw.close();
641 // con.close();
642 }
643
644 } //~class