    001    package org.apache.turbine.util;
    002
    003    /*
    004     * Licensed to the Apache Software Foundation (ASF) under one
    005     * or more contributor license agreements.  See the NOTICE file
    006     * distributed with this work for additional information
    007     * regarding copyright ownership.  The ASF licenses this file
    008     * to you under the Apache License, Version 2.0 (the
    009     * "License"); you may not use this file except in compliance
    010     * with the License.  You may obtain a copy of the License at
    011     *
    012     *   http://www.apache.org/licenses/LICENSE-2.0
    013     *
    014     * Unless required by applicable law or agreed to in writing,
    015     * software distributed under the License is distributed on an
    016     * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
    017     * KIND, either express or implied.  See the License for the
    018     * specific language governing permissions and limitations
    019     * under the License.
    020     */
    021
    022    import java.text.NumberFormat;
    023    import java.util.Calendar;
    024    import java.util.Date;
    025
    026    import org.apache.ecs.ConcreteElement;
    027    import org.apache.ecs.ElementContainer;
    028    import org.apache.ecs.html.Comment;
    029    import org.apache.ecs.html.Input;
    030    import org.apache.ecs.html.Option;
    031    import org.apache.ecs.html.Select;
    032
    033    /**
    034     * TimeSelector is a utility class to handle the creation of a set of
    035     * time drop-down menus.  The code is broken into a set of static methods
    036     * for quick and easy access to the individual select objects:
    037     *
    038     *  <pre>
    039     *  ElementContainer ec timeSelect = new ElementContainer();
    040     *  String myName = "mytime";
    041     *  ec.addElement(TimeSelector.getHourSelector(myName));
    042     *  ec.addElement(TimeSelector.getMinuteSelector(myName));
    043     *  ec.addElement(TimeSelector.getAMPMSelector(myName));
    044     *  </pre>
    045     *
    046     * There are also methods which will use attributes to build a
    047     * complete time selector in the default 12hr format (eg HH:MM am/pm):
    048     *
    049     *  <pre>
    050     *  TimeSelector ts = new TimeSelector(myName);
    051     *  timeSelect = ts.ecsOutput();
    052     *  </pre>
    053     *
    054     * Minutes/Seconds are by default rounded to the nearest 5 units
    055     * although this can be easily changed.
    056     *
    057     * 24hr TimeSelectors can also be produced. The following example
    058     * creates a full precision TimeSelector (eg HH:MM:SS):
    059     *
    060     *  <pre>
    061     *  TimeSelector ts = new TimeSelector(myName);
    062     *  ts.setTimeFormat(TimeSelector.TWENTY_FOUR_HOUR);
    063     *  ts.setMinuteInterval(1);
    064     *  ts.setSecondInterval(1);
    065     *  ts.setShowSeconds(true);
    066     *  timeSelect = ts.toString();
    067     *  </pre>
    068     *
    069     * @author <a href="mailto:ekkerbj@netscape.net">Jeffrey D. Brekke</a>
    070     * @author <a href="mailto:rich@thenetrevolution.com">Rich Aston</a>
    071     * @version $Id: TimeSelector.java 1078552 2011-03-06 19:58:46Z tv $
    072     */
    073    public class TimeSelector
    074    {
    075        /** Prefix for time names. */
    076        public static final String DEFAULT_PREFIX = "TimeSelector";
    077
    078        /** Suffix for hour parameter. */
    079        public static final String HOUR_SUFFIX = "_hour";
    080
    081        /** Suffix for minute parameter. */
    082        public static final String MINUTE_SUFFIX = "_minute";
    083
    084        /** Suffix for second parameter. */
    085        public static final String SECOND_SUFFIX = "_second";
    086
    087        /** Suffix for am/pm parameter. */
    088        public static final String AMPM_SUFFIX = "_ampm";
    089
    090        /** Constant for 12hr format */
    091        public static final int TWELVE_HOUR = 0;
    092
    093        /** Constant for 24hr format */
    094        public static final int TWENTY_FOUR_HOUR = 1;
    095
    096        /** TODO: Add ability to specify Locale. */
    097        private static final NumberFormat nbrFmt;
    098
    099        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>&lt;SELECT&gt;</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    }