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