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 java.lang.reflect.*; 009import java.io.*; 010import java.text.*; 011import java.util.*; 012 013import fc.jdbc.*; 014import fc.io.*; 015import fc.util.*; 016import fc.web.forms.*; 017//for testing 018import fc.jdbc.dbo.generated.*; 019 020/** 021Misc. form related utilities. 022 023@author hursh jain 024*/ 025public class FormUtil 026{ 027private static final Class[] classarr = new Class[] { }; 028private static final Object[] objarr = new Object[] { }; 029 030/** 031<b>Note: This method is almost never needed. Use the {@link Select#useQuery(Connection, String)} 032method instead. 033</b> 034<p> 035Fills in the specified select with values from the supplied list. This is 036intended to show a select widget corresponding to a lookup table in the 037database. The list will typically be returned by <tt>getAll/getWhere</tt> 038methods of some generated {@link fc.jdbc.dbo.DBOMgr} class. 039<p> 040For example, given a lookup table object <tt>Foo</tt> and a corresponding 041manager object <tt>FooMgr</tt> and an empty previously-instantiated 042select: 043<tt> 044<blockquote> 045<pre> 046Select select = new Select("myselect") 047fillSelect(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> 054and 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> 066will 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*/ 106public 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)} 135method instead. 136</b> 137<p> 138Fills in the specified select with values from the supplied map. This is 139intended to show a select widget corresponding to a lookup table in the 140database. The list will typically be returned by <tt>getAll/getWhere</tt> 141methods of some generated {@link fc.jdbc.dbo.DBOMgr} class. 142<p> 143For example, given a lookup table object <tt>Foo</tt> and a corresponding 144manager object <tt>FooMgr</tt> and an empty previously-instantiated 145select: 146<tt> 147<blockquote> 148<pre> 149Select select = new Select("myselect") 150fillSelect(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> 157and 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> 169will 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*/ 194public 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/** 213Fills in the specified radiogroup with values from the supplied list. This 214is intended to show radio groups corresponding to a lookup table in the 215database. The list will typically be returned by <tt>getAll/getWhere</tt> 216methods of some generated {@link fc.jdbc.dbo.DBOMgr} class. <p> For 217example, given a lookup table object <tt>Foo</tt> and a corresponding 218manager object <tt>FooMgr</tt> and a empty previously-instantiated radio 219group: 220<tt> 221<blockquote> 222<pre> 223RadioGroup rg = new RadioGroup("myradio") 224fillRadioGroup(select, FooMgr.getAll(), 225 Foo.class, <font color=red>"getID"</font>, 226 <font color=red>"getValue"</font>); 227</pre> 228</blockquote> 229</tt> 230and 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> 242will 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*/ 266public 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/** 290Fills in the specified checkboxgroup with values from the supplied list. 291This is intended to show checkbox groups corresponding to a lookup table 292in the database. The list will typically be returned by <tt>getAll or 293getWhere</tt> methods of some generated {@link fc.jdbc.dbo.DBOMgr} class. 294<p> 295For example, given a lookup table object <tt>Foo</tt> and a corresponding 296manager object <tt>FooMgr</tt> and a empty previously-instantiated 297checkbox group: 298<tt> 299<blockquote> 300<pre> 301CheckboxGroup rg = new CheckboxGroup("mycbgroup") 302fillCheckboxGroup(select, FooMgr.getAll(), 303 Foo.class, <font color=red>"getID"</font>, 304 <font color=red>"getValue"</font>); 305</pre> 306</blockquote> 307</tt> 308and 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> 320will 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*/ 344public 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/** 369Fills the specified select from years, starting with the specified year 370till the current year. No year option is pre-selected. 371*/ 372public 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/** 384Fills the specified select from years, starting with the specified year. 385The current year (on the server) is pre-selected. 386*/ 387public static Select fillSelectWithYearsToday(Select s, int startYear) 388 { 389 return fillSelectWithYears(s, startYear, Calendar.getInstance()); 390 } 391 392/** 393Fills the specified select from years, starting with the specified year, 394upto the current year. The date from the specified calendar is 395pre-selected. 396*/ 397public 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/** 413Fills the specified select from years, from the specified start and end 414years (both inclusive). The date from the specified calendar is 415pre-selected. 416*/ 417public 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 431private 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/** 440Fills the specified select from years, starting with the specified year. 441<tt>monthsAsText</tt> specifies whether months are displayed as names 442or numbers. (true for names). No month is preselected. 443*/ 444public 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/** 461Fills the specified select from years, starting with the specified year. 462<tt>monthsAsText</tt> specifies whether months are displayed as names or 463numbers. (true for names). The current month (on the server) is preselected. 464*/ 465public static Select fillSelectWithMonthsToday(Select s, boolean monthsAsText) 466 { 467 return fillSelectWithMonths(s, monthsAsText, Calendar.getInstance()); 468 } 469 470/** 471Fills the specified select from years, starting with the specified year. 472<tt>monthsAsText</tt> specifies whether months are displayed as names or 473numbers. (true for names). The current month from the specified calendar is 474is preselected. 475*/ 476public 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/** 499Fills the specified select from years, starting with the specified year. 500No day is pre-selected. 501*/ 502public 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/** 513Fills the specified select from years, starting with the specified year. 514Today (on the server side) is preselected. 515*/ 516public static Select fillSelectWithDaysToday(Select s) 517 { 518 return fillSelectWithDays(s, Calendar.getInstance()); 519 } 520 521/** 522Fills the specified select from years, starting with the specified year. 523The day in the specified date is preselected. 524*/ 525public 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/** 538Converts a year, month and day into a java.sql.Date 539*/ 540public 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/** 552Converts 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 554string could not be parsed. (Hours upto 12 are allowed but not 13 or 555more). This method is suitable for a text box that takes 1-12 hours 556and a seperate am/pm select option next to it. 557*/ 558public 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 573public 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