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