001    package org.apache.turbine.util;
002    
003    
004    /*
005     * Licensed to the Apache Software Foundation (ASF) under one
006     * or more contributor license agreements.  See the NOTICE file
007     * distributed with this work for additional information
008     * regarding copyright ownership.  The ASF licenses this file
009     * to you under the Apache License, Version 2.0 (the
010     * "License"); you may not use this file except in compliance
011     * with the License.  You may obtain a copy of the License at
012     *
013     *   http://www.apache.org/licenses/LICENSE-2.0
014     *
015     * Unless required by applicable law or agreed to in writing,
016     * software distributed under the License is distributed on an
017     * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
018     * KIND, either express or implied.  See the License for the
019     * specific language governing permissions and limitations
020     * under the License.
021     */
022    
023    
024    import java.text.DateFormatSymbols;
025    import java.util.Calendar;
026    import java.util.Date;
027    
028    import org.apache.ecs.ConcreteElement;
029    import org.apache.ecs.ElementContainer;
030    import org.apache.ecs.html.Input;
031    import org.apache.ecs.html.Option;
032    import org.apache.ecs.html.Select;
033    
034    /**
035     * DateSelector is a utility class to handle the creation of a set of
036     * date popup menus.  The code is broken into a set of static methods
037     * for quick and easy access to the individual select objects:
038     *
039     *  <pre>
040     *  ElementContainer ec dateSelect = new ElementContainer();
041     *  String myName = "mydate";
042     *  ec.addElement(DateSelector.getMonthSelector(myName));
043     *  ec.addElement(DateSelector.getDaySelector(myName));
044     *  ec.addElement(DateSelector.getYearSelector(myName));
045     *  </pre>
046     *
047     * There are also methods which will use attributes to build a
048     * complete month,day,year selector:
049     *
050     *  <pre>
051     *  DateSelector ds = new DateSelector(myName);
052     *  dateSelect = ds.ecsOutput();
053     *  </pre>
054     *
055     * The above element container would use the onChange setting and may
056     * hide the selected day if set via showDays().<br>
057     *
058     * @author <a href="mailto:ekkerbj@netscape.net">Jeffrey D. Brekke</a>
059     * @author <a href="mailto:jon@clearink.com">Jon S. Stevens</a>
060     * @author <a href="mailto:leon@clearink.com">Leon Atkinson</a>
061     * @version $Id: DateSelector.java 615328 2008-01-25 20:25:05Z tv $
062     */
063    public class DateSelector
064    {
065        /** Prefix for date names. */
066        public static final String DEFAULT_PREFIX = "DateSelector";
067    
068        /** Suffix for day parameter. */
069        public static final String DAY_SUFFIX = "_day";
070    
071        /** Suffix for month parameter. */
072        public static final String MONTH_SUFFIX = "_month";
073    
074        /** Suffix for year parameter. */
075        public static final String YEAR_SUFFIX = "_year";
076    
077        private Calendar useDate = null;
078        private String selName = null;
079        private static final String[] monthName =
080                new DateFormatSymbols().getMonths();
081        private String onChange = null;
082        private boolean onChangeSet = false;
083        private boolean showDays = true;
084        private int setDay = 0;
085        private boolean useYears = false;
086        private int firstYear = 0;
087        private int lastYear = 0;
088        private int selectedYear = 0;
089    
090        /**
091         * Constructor defaults to current date and uses the default
092         * prefix: <pre>DateSelector.DEFAULT</pre>
093         */
094        public DateSelector()
095        {
096            this.selName = DEFAULT_PREFIX;
097            this.useDate = Calendar.getInstance();
098            this.useDate.setTime(new Date());
099        }
100    
101        /**
102         * Constructor, uses the date set in a calendar that has been
103         * already passed in (with the date set correctly).
104         *
105         * @param selName A String with the selector name.
106         * @param useDate A Calendar with a date.
107         */
108        public DateSelector(String selName, Calendar useDate)
109        {
110            this.useDate = useDate;
111            this.selName = selName;
112        }
113    
114        /**
115         * Constructor defaults to current date.
116         *
117         * @param selName A String with the selector name.
118         */
119        public DateSelector(String selName)
120        {
121            this.selName = selName;
122            this.useDate = Calendar.getInstance();
123            this.useDate.setTime(new Date());
124        }
125    
126        /**
127         * Adds the onChange to all of &lt;SELECT&gt; tags.  This is limited to
128         * one function for all three popups and is only used when the
129         * output() methods are used.  Individual getMonth, getDay,
130         * getYear static methods will not use this setting.
131         *
132         * @param string A String to use for onChange attribute.  If null,
133         * then nothing will be set.
134         * @return A DateSelector (self).
135         */
136        public DateSelector setOnChange(String onChange)
137        {
138            if (onChange != null)
139            {
140                this.onChange = onChange;
141                this.onChangeSet = true;
142            }
143            else
144            {
145                this.onChange = null;
146                this.onChangeSet = false;
147            }
148            return this;
149        }
150    
151        /**
152         * Select the day to be selected if the showDays(false) behavior
153         * is used.  Individual getMonth, getDay, getYear static methods
154         * will not use this setting.
155         *
156         * @param day The day.
157         * @return A DateSelector (self).
158         */
159        public DateSelector setDay(int day)
160        {
161            this.setDay = day;
162            this.showDays = false;
163            return this;
164        }
165    
166        /**
167         * Whether or not to show the days as a popup menu.  The days will
168         * be a hidden parameter and the value set with setDay is used.
169         * Individual getMonth, getDay, getYear static methods will not
170         * use this setting.
171         *
172         * @param show True if the day should be shown.
173         * @return A DateSelector (self).
174         */
175        public DateSelector setShowDay(boolean show)
176        {
177            this.showDays = false;
178            return this;
179        }
180    
181        /**
182         * Set the selector name prefix.  Individual getMonth, getDay,
183         * getYear static methods will not use this setting.
184         *
185         * @param selname A String with the select name prefix.
186         */
187        public void setSelName(String selName)
188        {
189            this.selName = selName;
190        }
191    
192        /**
193         * Get the selector name prefix.
194         *
195         * @return A String with the select name prefix.
196         */
197        public String getSelName()
198        {
199            return selName;
200        }
201    
202        /**
203         * Return a month selector.
204         *
205         * @param name The name to use for the selected month.
206         * @return A select object with all the months.
207         */
208        public static Select getMonthSelector(String name)
209        {
210            return (getMonthSelector(name, Calendar.getInstance()));
211        }
212    
213        /**
214         * Return a month selector.
215         *
216         * Note: The values of the month placed into the select list are
217         * the month integers starting at 0 (ie: if the user selects
218         * February, the selected value will be 1).
219         *
220         * @param name The name to use for the selected month.
221         * @param now Calendar to start with.
222         * @return A select object with all the months.
223         */
224        public static Select getMonthSelector(String name, Calendar now)
225        {
226            Select monthSelect = new Select().setName(name);
227    
228            for (int curMonth = 0; curMonth <= 11; curMonth++)
229            {
230                Option o = new Option();
231                o.addElement(monthName[curMonth]);
232                o.setValue(curMonth);
233                if ((now.get(Calendar.MONTH)) == curMonth)
234                {
235                    o.setSelected(true);
236                }
237                monthSelect.addElement(o);
238            }
239            return (monthSelect);
240        }
241    
242        /**
243         * Return a day selector.
244         *
245         * @param name The name to use for the selected day.
246         * @return A select object with all the days in a month.
247         */
248        public static Select getDaySelector(String name)
249        {
250            return (getDaySelector(name, Calendar.getInstance()));
251        }
252    
253        /**
254         * Return a day selector.
255         *
256         * @param name The name to use for the selected day.
257         * @param now Calendar to start with.
258         * @return A select object with all the days in a month.
259         */
260        public static Select getDaySelector(String name, Calendar now)
261        {
262            Select daySelect = new Select().setName(name);
263    
264            for (int currentDay = 1; currentDay <= 31; currentDay++)
265            {
266                Option o = new Option();
267                o.addElement(Integer.toString(currentDay));
268                o.setValue(currentDay);
269                if (now.get(Calendar.DAY_OF_MONTH) == currentDay)
270                {
271                    o.setSelected(true);
272                }
273                daySelect.addElement(o);
274            }
275            return (daySelect);
276        }
277    
278        /**
279         * Return a year selector.
280         *
281         * @param name The name to use for the selected year.
282         * @return A select object with all the years starting five years
283         * from now and five years before this year.
284         */
285        public static Select getYearSelector(String name)
286        {
287            return (getYearSelector(name, Calendar.getInstance()));
288        }
289    
290        /**
291         * Return a year selector.
292         *
293         * @param name The name to use for the selected year.
294         * @param now Calendar to start with.
295         * @return A select object with all the years starting five years
296         * from now and five years before this year.
297         */
298        public static Select getYearSelector(String name, Calendar now)
299        {
300            int startYear = now.get(Calendar.YEAR);
301            return (getYearSelector(name, startYear - 5, startYear + 5, startYear));
302        }
303    
304        /**
305         * Return a year selector.
306         *
307         * @param name The name to use for the selected year.
308         * @param firstYear the first (earliest) year in the selector.
309         * @param lastYear the last (latest) year in the selector.
310         * @param selectedYear the year initially selected in the Select html.
311         * @return A select object with all the years from firstyear
312         * to lastyear..
313         */
314        public static Select getYearSelector(String name,
315                                             int firstYear, int lastYear,
316                                             int selectedYear)
317        {
318            Select yearSelect = new Select().setName(name);
319    
320            for (int currentYear = firstYear;
321                 currentYear <= lastYear;
322    
323                 currentYear++)
324            {
325                Option o = new Option();
326                o.addElement(Integer.toString(currentYear));
327                o.setValue(currentYear);
328                if (currentYear == selectedYear)
329                {
330                    o.setSelected(true);
331                }
332                yearSelect.addElement(o);
333            }
334            return (yearSelect);
335        }
336    
337        /**
338         * Select the day to be selected if the showDays(false) behavior
339         * is used.  Individual getMonth, getDay, getYear static methods
340         * will not use this setting.
341         *
342         * @param day The day.
343         * @return A DateSelector (self).
344         */
345        public boolean setYear(int firstYear, int lastYear, int selectedYear)
346        {
347            if (firstYear <= lastYear && firstYear <= selectedYear
348                    && selectedYear <= lastYear)
349            {
350                this.useYears = true;
351                this.firstYear = firstYear;
352                this.lastYear = lastYear;
353                this.selectedYear = selectedYear;
354                return true;
355            }
356            else
357            {
358                return false;
359            }
360        }
361    
362        /**
363         * Used to build the popupmenu in HTML.  The properties set in the
364         * object are used to generate the correct HTML.  The selName
365         * attribute is used to seed the names of the select lists.  The
366         * names will be generated as follows:
367         *
368         * <ul>
369         *  <li>selName + "_month"</li>
370         *  <li>selName + "_day"</li>
371         *  <li>selName + "_year"</li>
372         * </ul>
373         *
374         * If onChange was set it is also used in the generation of the
375         * output.  The output HTML will list the select lists in the
376         * following order: month day year.
377         *
378         * @return A String with the correct HTML for the date selector.
379         */
380        public String output()
381        {
382            return (ecsOutput().toString());
383        }
384    
385        /**
386         * Used to build the popupmenu in HTML.  The properties set in the
387         * object are used to generate the correct HTML.  The selName
388         * attribute is used to seed the names of the select lists.  The
389         * names will be generated as follows:
390         *
391         * <ul>
392         *  <li>selName + "_month"</li>
393         *  <li>selName + "_day"</li>
394         *  <li>selName + "_year"</li>
395         * </ul>
396         *
397         * The output HTML will list the select lists in the following
398         * order: month day year.
399         *
400         * @return A String with the correct HTML for the date selector.
401         */
402        public String toString()
403        {
404            return (ecsOutput().toString());
405        }
406    
407        /*
408         * Return an ECS container with the month, day, and year select
409         * objects inside.
410         *
411         * @return An ECS container.
412         */
413        public ElementContainer ecsOutput()
414        {
415            if (this.useDate == null)
416            {
417                this.useDate.setTime(new Date());
418            }
419    
420            Select monthSelect = getMonthSelector(selName + MONTH_SUFFIX, useDate);
421            ConcreteElement daySelect = null;
422            if (!showDays)
423            {
424                daySelect = new Input(Input.hidden, selName + DAY_SUFFIX, setDay);
425            }
426            else
427            {
428                Select tmp = getDaySelector(selName + DAY_SUFFIX, useDate);
429                if (onChangeSet)
430                {
431                    tmp.setOnChange(onChange);
432                }
433                daySelect = tmp;
434            }
435            Select yearSelect = null;
436            if (useYears)
437            {
438                yearSelect = getYearSelector(selName + YEAR_SUFFIX,
439                        firstYear, lastYear, selectedYear);
440            }
441            else
442            {
443                yearSelect = getYearSelector(selName + YEAR_SUFFIX, useDate);
444            }
445            if (onChangeSet)
446            {
447                monthSelect.setOnChange(onChange);
448                yearSelect.setOnChange(onChange);
449            }
450            ElementContainer ec = new ElementContainer();
451            // ec.addElement(new Comment("== BEGIN org.apache.turbine.util.DateSelector.ecsOutput() =="));
452            ec.addElement(monthSelect);
453            ec.addElement(daySelect);
454            ec.addElement(yearSelect);
455            // ec.addElement(new Comment("== END org.apache.turbine.util.DateSelector.ecsOutput() =="));
456            return (ec);
457        }
458    }