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