1 package org.apache.turbine.util;
2
3 /*
4 * Licensed to the Apache Software Foundation (ASF) under one
5 * or more contributor license agreements. See the NOTICE file
6 * distributed with this work for additional information
7 * regarding copyright ownership. The ASF licenses this file
8 * to you under the Apache License, Version 2.0 (the
9 * "License"); you may not use this file except in compliance
10 * with the License. You may obtain a copy of the License at
11 *
12 * http://www.apache.org/licenses/LICENSE-2.0
13 *
14 * Unless required by applicable law or agreed to in writing,
15 * software distributed under the License is distributed on an
16 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17 * KIND, either express or implied. See the License for the
18 * specific language governing permissions and limitations
19 * under the License.
20 */
21
22 import java.text.NumberFormat;
23 import java.util.Calendar;
24 import java.util.Date;
25
26 import org.apache.ecs.ConcreteElement;
27 import org.apache.ecs.ElementContainer;
28 import org.apache.ecs.html.Comment;
29 import org.apache.ecs.html.Input;
30 import org.apache.ecs.html.Option;
31 import org.apache.ecs.html.Select;
32
33 /**
34 * TimeSelector is a utility class to handle the creation of a set of
35 * time drop-down menus. The code is broken into a set of static methods
36 * for quick and easy access to the individual select objects:
37 *
38 * <pre>
39 * ElementContainer ec timeSelect = new ElementContainer();
40 * String myName = "mytime";
41 * ec.addElement(TimeSelector.getHourSelector(myName));
42 * ec.addElement(TimeSelector.getMinuteSelector(myName));
43 * ec.addElement(TimeSelector.getAMPMSelector(myName));
44 * </pre>
45 *
46 * There are also methods which will use attributes to build a
47 * complete time selector in the default 12hr format (eg HH:MM am/pm):
48 *
49 * <pre>
50 * TimeSelector ts = new TimeSelector(myName);
51 * timeSelect = ts.ecsOutput();
52 * </pre>
53 *
54 * Minutes/Seconds are by default rounded to the nearest 5 units
55 * although this can be easily changed.
56 *
57 * 24hr TimeSelectors can also be produced. The following example
58 * creates a full precision TimeSelector (eg HH:MM:SS):
59 *
60 * <pre>
61 * TimeSelector ts = new TimeSelector(myName);
62 * ts.setTimeFormat(TimeSelector.TWENTY_FOUR_HOUR);
63 * ts.setMinuteInterval(1);
64 * ts.setSecondInterval(1);
65 * ts.setShowSeconds(true);
66 * timeSelect = ts.toString();
67 * </pre>
68 *
69 * @author <a href="mailto:ekkerbj@netscape.net">Jeffrey D. Brekke</a>
70 * @author <a href="mailto:rich@thenetrevolution.com">Rich Aston</a>
71 * @version $Id: TimeSelector.java 1078552 2011-03-06 19:58:46Z tv $
72 */
73 public class TimeSelector
74 {
75 /** Prefix for time names. */
76 public static final String DEFAULT_PREFIX = "TimeSelector";
77
78 /** Suffix for hour parameter. */
79 public static final String HOUR_SUFFIX = "_hour";
80
81 /** Suffix for minute parameter. */
82 public static final String MINUTE_SUFFIX = "_minute";
83
84 /** Suffix for second parameter. */
85 public static final String SECOND_SUFFIX = "_second";
86
87 /** Suffix for am/pm parameter. */
88 public static final String AMPM_SUFFIX = "_ampm";
89
90 /** Constant for 12hr format */
91 public static final int TWELVE_HOUR = 0;
92
93 /** Constant for 24hr format */
94 public static final int TWENTY_FOUR_HOUR = 1;
95
96 /** TODO: Add ability to specify Locale. */
97 private static final NumberFormat nbrFmt;
98
99 private static final int DEFAULT_MINUTE_INTERVAL = 5;
100 private static final int DEFAULT_SECOND_INTERVAL = 5;
101 private static final int DEFAULT_TIME_FORMAT = TWELVE_HOUR;
102
103 private int timeFormat = DEFAULT_TIME_FORMAT;
104 private int minuteInterval = DEFAULT_MINUTE_INTERVAL;
105 private int secondInterval = DEFAULT_SECOND_INTERVAL;
106
107 private Calendar useDate = null;
108 private String selName = null;
109 private String onChange = null;
110 private boolean onChangeSet = false;
111 private boolean showSeconds = false;
112 private int setSeconds = 0;
113
114 static
115 {
116 nbrFmt = NumberFormat.getInstance();
117 nbrFmt.setMinimumIntegerDigits(2);
118 nbrFmt.setMaximumIntegerDigits(2);
119 }
120
121 /**
122 * Constructor defaults to current date/time and uses the default
123 * prefix: <pre>TimeSelector.DEFAULT</pre>
124 */
125 public TimeSelector()
126 {
127 this.selName = DEFAULT_PREFIX;
128 this.useDate = Calendar.getInstance();
129 this.useDate.setTime(new Date());
130 }
131
132 /**
133 * Constructor, uses the date/time set in the calendar
134 * passed in (with the date/time set correctly).
135 *
136 * @param selName A String with the selector name.
137 * @param useDate A Calendar with a date/time.
138 */
139 public TimeSelector(String selName, Calendar useDate)
140 {
141 this.useDate = useDate;
142 this.selName = selName;
143 }
144
145 /**
146 * Constructor defaults to current date/time.
147 *
148 * @param selName A String with the selector name.
149 */
150 public TimeSelector(String selName)
151 {
152 this.selName = selName;
153 this.useDate = Calendar.getInstance();
154 this.useDate.setTime(new Date());
155 }
156
157 /**
158 * Adds the onChange to all of <code><SELECT></code> tags.
159 * This is limited to one function for all three popups and is only
160 * used when the output() methods are used. Individual getHour,
161 * getMinute, getSecond, getAMPM static methods will not use this
162 * setting.
163 *
164 * @param onChange A String to use for onChange attribute. If null,
165 * then nothing will be set.
166 * @return A TimeSelector (self).
167 */
168 public TimeSelector setOnChange(String onChange)
169 {
170 if (onChange != null)
171 {
172 this.onChange = onChange;
173 this.onChangeSet = true;
174 }
175 else
176 {
177 this.onChange = null;
178 this.onChangeSet = false;
179 }
180 return this;
181 }
182
183 /**
184 * Select the second to be selected if the showSeconds(false) behavior
185 * is used. Individual getHour, getMinute, getSecond, getAMPM
186 * static methods will not use this setting.
187 *
188 * @param seconds The second.
189 * @return A TimeSelector (self).
190 */
191 public TimeSelector setSeconds(int seconds)
192 {
193 this.setSeconds = seconds;
194 this.showSeconds = false;
195 return this;
196 }
197
198 /**
199 * Set the interval between options in the minute select box.
200 * Individual getHour, getMinute, getSecond, getAMPM static methods
201 * will not use this setting.
202 *
203 * @param minutes Interval in minutes.
204 * @return A TimeSelector (self).
205 */
206 public TimeSelector setMinuteInterval(int minutes)
207 {
208 this.minuteInterval = minutes;
209 return this;
210 }
211
212 /**
213 * Set the interval between options in the second select box.
214 * Individual getHour, getMinute, getSecond, getAMPM static methods
215 * will not use this setting.
216 *
217 * @param seconds Interval in seconds.
218 * @return A TimeSelector (self).
219 */
220 public TimeSelector setSecondInterval(int seconds)
221 {
222 this.secondInterval = seconds;
223 return this;
224 }
225
226 /**
227 * Set the time format to 12 or 24 hour. Individual getHour,
228 * getMinute, getSecond, getAMPM static methods
229 * will not use this setting.
230 *
231 * @param format Time format.
232 * @return A TimeSelector (self).
233 */
234 public TimeSelector setTimeFormat(int format)
235 {
236 this.timeFormat = format;
237 return this;
238 }
239
240 /**
241 * Whether or not to show the seconds as a popup menu. The seconds will
242 * be a hidden parameter and the value set with setSeconds is used.
243 * Individual getHour, getMinute, getSecond, getAMPM static methods
244 * will not use this setting.
245 *
246 * @param show True if the second should be shown.
247 * @return A TimeSelector (self).
248 */
249 public TimeSelector setShowSeconds(boolean show)
250 {
251 this.showSeconds = show;
252 return this;
253 }
254
255 /**
256 * Set the selector name prefix. Individual getHour, getMinute,
257 * getSeconds, getAMPM static methods will not use this setting.
258 *
259 * @param selname A String with the select name prefix.
260 */
261 public void setSelName(String selName)
262 {
263 this.selName = selName;
264 }
265
266 /**
267 * Get the selector name prefix.
268 *
269 * @return A String with the select name prefix.
270 */
271 public String getSelName()
272 {
273 return selName;
274 }
275
276 /**
277 * Return a second selector.
278 *
279 * @param name The name to use for the selected second.
280 * @return A select object with second options.
281 */
282 public static Select getSecondSelector(String name)
283 {
284 return (getSecondSelector(name, Calendar.getInstance()));
285 }
286
287 /**
288 * Return a second selector.
289 *
290 * @param name The name to use for the selected second.
291 * @param now Calendar to start with.
292 * @return A select object with second options.
293 */
294 public static Select getSecondSelector(String name, Calendar now)
295 {
296 return (getSecondSelector(name, Calendar.getInstance(),
297 DEFAULT_SECOND_INTERVAL));
298 }
299
300 /**
301 * Return a second selector.
302 *
303 * @param name The name to use for the selected second.
304 * @param now Calendar to start with.
305 * @param interval Interval between options.
306 * @return A select object with second options.
307 */
308 public static Select getSecondSelector(String name, Calendar now,
309 int interval)
310 {
311 Select secondSelect = new Select().setName(name);
312
313 for (int currentSecond = 0; currentSecond <= 59; currentSecond += interval)
314 {
315 Option o = new Option();
316 o.addElement(nbrFmt.format(currentSecond));
317 o.setValue(currentSecond);
318 int nearestSecond =
319 ((now.get(Calendar.SECOND) / interval) * interval);
320
321 if (nearestSecond == currentSecond)
322 {
323 o.setSelected(true);
324 }
325 secondSelect.addElement(o);
326 }
327 return (secondSelect);
328 }
329
330 /**
331 * Return a minute selector.
332 *
333 * @param name The name to use for the selected minute.
334 * @return A select object with minute options.
335 */
336 public static Select getMinuteSelector(String name)
337 {
338 return (getMinuteSelector(name, Calendar.getInstance()));
339 }
340
341 /**
342 * Return a minute selector.
343 *
344 * @param name The name to use for the selected minute.
345 * @return A select object with minute options.
346 */
347 public static Select getMinuteSelector(String name, Calendar now)
348 {
349 return (getMinuteSelector(name, now, DEFAULT_MINUTE_INTERVAL));
350 }
351
352 /**
353 * Return a minute selector.
354 *
355 * @param name The name to use for the selected minute.
356 * @param now Calendar to start with.
357 * @param interval Interval between options.
358 * @return A select object with minute options.
359 */
360 public static Select getMinuteSelector(String name, Calendar now,
361 int interval)
362 {
363 Select minuteSelect = new Select().setName(name);
364
365 for (int curMinute = 0; curMinute <= 59; curMinute += interval)
366 {
367 Option o = new Option();
368 o.addElement(nbrFmt.format(curMinute));
369 o.setValue(curMinute);
370 int nearestMinute =
371 ((now.get(Calendar.MINUTE)) / interval) * interval;
372
373 if (nearestMinute == curMinute)
374 {
375 o.setSelected(true);
376 }
377 minuteSelect.addElement(o);
378 }
379 return (minuteSelect);
380 }
381
382 /**
383 * Return an 12 hour selector.
384 *
385 * @param name The name to use for the selected hour.
386 * @return A select object with all the hours.
387 */
388 public static Select getHourSelector(String name)
389 {
390 return (getHourSelector(name, Calendar.getInstance()));
391 }
392
393 /**
394 * Return an 12 hour selector.
395 *
396 * @param name The name to use for the selected hour.
397 * @param now Calendar to start with.
398 * @return A select object with all the hours.
399 */
400 public static Select getHourSelector(String name, Calendar now)
401 {
402 return (getHourSelector(name, Calendar.getInstance(), TWELVE_HOUR));
403 }
404
405 /**
406 * Return an hour selector (either 12hr or 24hr depending on
407 * <code>format</code>.
408 *
409 * @param name The name to use for the selected hour.
410 * @param now Calendar to start with.
411 * @param format Time format.
412 * @return A select object with all the hours.
413 */
414 @SuppressWarnings("cast")
415 public static Select getHourSelector(String name, Calendar now, int format)
416 {
417 Select hourSelect = new Select().setName(name);
418
419 if (format == TWENTY_FOUR_HOUR)
420 {
421 for (int currentHour = 0; currentHour <= 23; currentHour++)
422 {
423 Option o = new Option();
424 o.addElement(nbrFmt.format(currentHour));
425 o.setValue(currentHour);
426 if (now.get(Calendar.HOUR_OF_DAY) == currentHour)
427 {
428 o.setSelected(true);
429 }
430 hourSelect.addElement(o);
431 }
432 }
433 else
434 {
435 for (int curHour = 1; curHour <= 12; curHour++)
436 {
437 Option o = new Option();
438
439 o.addElement(nbrFmt.format((long) curHour));
440 o.setValue(curHour);
441 if (now.get(Calendar.AM_PM) == Calendar.AM)
442 {
443 if (((now.get(Calendar.HOUR_OF_DAY)) == 0) &&
444 (curHour == 12))
445 {
446 o.setSelected(true);
447 }
448 else
449 {
450 if (now.get(Calendar.HOUR_OF_DAY) == curHour)
451 {
452 o.setSelected(true);
453 }
454 }
455 }
456 else
457 {
458 if (((now.get(Calendar.HOUR_OF_DAY)) == 12) &&
459 (curHour == 12))
460 {
461 o.setSelected(true);
462 }
463 else
464 {
465 if (now.get(Calendar.HOUR_OF_DAY) == curHour + 12)
466 {
467 o.setSelected(true);
468 }
469 }
470 }
471 hourSelect.addElement(o);
472 }
473 }
474 return (hourSelect);
475 }
476
477 /**
478 * Return an am/pm selector.
479 *
480 * @param name The name to use for the selected am/pm.
481 * @return A select object with am/pm
482 */
483 public static Select getAMPMSelector(String name)
484 {
485 Calendar c = Calendar.getInstance();
486 c.setTime(new Date());
487 return (getAMPMSelector(name, c));
488 }
489
490 /**
491 * Return an am/pm selector.
492 *
493 * @param name The name to use for the selected am/pm.
494 * @param now Calendar to start with.
495 * @return A select object with am/pm.
496 */
497 public static Select getAMPMSelector(String name,
498 Calendar now)
499 {
500 Select ampmSelect = new Select().setName(name);
501
502 Option o = new Option();
503 o.addElement("am");
504 o.setValue(Calendar.AM);
505 if (now.get(Calendar.AM_PM) == Calendar.AM)
506 {
507 o.setSelected(true);
508 }
509 ampmSelect.addElement(o);
510
511 o = new Option();
512 o.addElement("pm");
513 o.setValue(Calendar.PM);
514 if (now.get(Calendar.AM_PM) == Calendar.PM)
515 {
516 o.setSelected(true);
517 }
518 ampmSelect.addElement(o);
519
520 return (ampmSelect);
521 }
522
523 /**
524 * Used to build the popupmenu in HTML. The properties set in the
525 * object are used to generate the correct HTML. The selName
526 * attribute is used to seed the names of the select lists. The
527 * names will be generated as follows:
528 *
529 * <ul>
530 * <li>selName + "_hour"</li>
531 * <li>selName + "_minute"</li>
532 * <li>selName + "_ampm"</li>
533 * </ul>
534 *
535 * If onChange was set it is also used in the generation of the
536 * output. The output HTML will list the select lists in the
537 * following order: hour minute ampm.
538 *
539 * If setShowSeconds(true) is used then an addition second select box
540 * is produced after the minute select box.
541 *
542 * If setTimeFormat(TimeSelector.TWENTY_FOUR_HOUR) is used then
543 * the ampm select box is omitted.
544 *
545 * @return A String with the correct HTML for the date selector.
546 */
547 public String output()
548 {
549 return (ecsOutput().toString());
550 }
551
552 /**
553 * Used to build the popupmenu in HTML. The properties set in the
554 * object are used to generate the correct HTML. The selName
555 * attribute is used to seed the names of the select lists. The
556 * names will be generated as follows:
557 *
558 * <ul>
559 * <li>selName + "_hour"</li>
560 * <li>selName + "_minute"</li>
561 * <li>selName + "_ampm"</li>
562 * </ul>
563 *
564 * If onChange was set it is also used in the generation of the
565 * output. The output HTML will list the select lists in the
566 * following order: hour minute ampm.
567 *
568 * If setShowSeconds(true) is used then an addition second select box
569 * is produced after the minute select box.
570 *
571 * If setTimeFormat(TimeSelector.TWENTY_FOUR_HOUR) is used then
572 * the ampm select box is omitted.
573 *
574 * @return A String with the correct HTML for the date selector.
575 */
576 @Override
577 public String toString()
578 {
579 return (ecsOutput().toString());
580 }
581
582 /**
583 * Return an ECS container with the select objects inside.
584 *
585 * @return An ECS container.
586 */
587 public ElementContainer ecsOutput()
588 {
589 if (this.useDate == null)
590 {
591 this.useDate = Calendar.getInstance();
592 this.useDate.setTime(new Date());
593 }
594
595 ConcreteElement secondSelect = null;
596
597 Select ampmSelect = getAMPMSelector(selName + AMPM_SUFFIX, useDate);
598
599 Select hourSelect = getHourSelector(selName + HOUR_SUFFIX,
600 useDate, this.timeFormat);
601
602 Select minuteSelect = getMinuteSelector(selName + MINUTE_SUFFIX,
603 useDate, this.minuteInterval);
604
605 if (this.showSeconds)
606 {
607 Select tmp = getSecondSelector(selName + SECOND_SUFFIX, useDate,
608 this.secondInterval);
609 if (onChangeSet)
610 tmp.setOnChange(onChange);
611 secondSelect = tmp;
612 }
613 else
614 {
615 secondSelect = new Input(Input.hidden,
616 selName + SECOND_SUFFIX,
617 setSeconds);
618 }
619
620 if (onChangeSet)
621 {
622 hourSelect.setOnChange(onChange);
623 minuteSelect.setOnChange(onChange);
624 ampmSelect.setOnChange(onChange);
625 }
626
627 ElementContainer ec = new ElementContainer();
628 ec.addElement(new Comment(
629 "== BEGIN org.apache.turbine.util.TimeSelector.ecsOutput() =="));
630 ec.addElement(hourSelect);
631 ec.addElement(":");
632 ec.addElement(minuteSelect);
633 if (this.showSeconds == true)
634 ec.addElement(":");
635 ec.addElement(secondSelect);
636 if (this.timeFormat == TimeSelector.TWELVE_HOUR)
637 {
638 ec.addElement(ampmSelect);
639 }
640 ec.addElement(new Comment(
641 "== END org.apache.turbine.util.TimeSelector.ecsOutput() =="));
642 return (ec);
643 }
644 }