Hi,

I have made several enhancements to DateSelector which I here submit back. The 
following changes have been made:

- The selector now uses Locale for output of Month names
- It can prepopulate the date from parameters in RunData
- It gives access to the Date/Calendar stored
- Accessors and Mutators have been added for all fields
   (Many could only be set as side effects and in constructors).
- Information on the selected year is not held separately, but in the
   Calendar member.

The DateSelector can now be used 'round trip'. The following example initially 
offers the user the current date. Once changed, the new date will appear after 
the submit and ds.getDate() will return that date as a java.util.Date.

DateScreen.java:
----------------
Calendar cal = GregorianCalendar.getInstance(runData.getLocale());
cal.set(2002, 2, 19, 23, 11);
DateSelector ds =
     new DateSelector("theDate", cal, runData);
//ds.getDate();
context.put("ds", ds);

DateScreen.vm:
--------------
<form action="$link.setPage("DateScreen.vm")">
$ds<br>
<input type="submit"/>
</form>


If you think that others might profit from these enhancements, feel free to 
apply the attached patch and modify the result to your liking.

Cheers,
Ben
-- 
Benjamin Peter                                          +49-69-96244395
Application Engineer                             Moerfelder Landstr. 55
(zentropy:partners)                            60598 Frankfurt, Germany
Index: src/java/org/apache/turbine/util/DateSelector.java
===================================================================
RCS file: 
/home/cvspublic/jakarta-turbine-2/src/java/org/apache/turbine/util/DateSelector.java,v
retrieving revision 1.2
diff -u -r1.2 DateSelector.java
--- src/java/org/apache/turbine/util/DateSelector.java  15 Nov 2001 23:11:55 -0000     
 1.2
+++ src/java/org/apache/turbine/util/DateSelector.java  13 Apr 2002 06:23:47 -0000
@@ -57,6 +57,12 @@
 import java.text.DateFormatSymbols;
 import java.util.Calendar;
 import java.util.Date;
+import java.util.HashMap;
+import java.util.Locale;
+
+import org.apache.turbine.util.RunData;
+import org.apache.turbine.util.ParameterParser;
+
 import org.apache.ecs.ConcreteElement;
 import org.apache.ecs.Element;
 import org.apache.ecs.ElementContainer;
@@ -90,9 +96,26 @@
  * The above element container would use the onChange setting and may
  * hide the selected day if set via showDays().<br>
  *
+ * You can also use DateSelector to regain the Date and Calendar resulting
+ * from the user's submission:
+ *
+ *  <pre>
+ *  Screen class: 
+ *     DateSelector ds = new DateSelector(myName, myCalendar, runData);
+ *     context.put("dateSelector", ds);
+ *  
+ *  Screen tpl.:  
+ *     $dateSelector.ecsOutput 
+ *  ...
+ *  Action class:
+ *     DateSelector ds = new DateSelector(myName, myCalendar, runData);
+ *     Calendar result = ds.getCalendar();
+ *  </pre>
+ *
  * @author <a href="mailto:[EMAIL PROTECTED]";>Jeffrey D. Brekke</a>
  * @author <a href="mailto:[EMAIL PROTECTED]";>Jon S. Stevens</a>
  * @author <a href="mailto:[EMAIL PROTECTED]";>Leon Atkinson</a>
+ * @author <a href="mailto:[EMAIL PROTECTED]";>Ben Peter</a>
  * @version $Id: DateSelector.java,v 1.2 2001/11/15 23:11:55 jvanzyl Exp $
  */
 public class DateSelector
@@ -108,20 +131,30 @@
 
     /** Suffix for year parameter. */
     public static final String YEAR_SUFFIX  = "_year";
+    
+    /** Holds the months' names for different locales. **/
+    private static HashMap monthNames;
 
     private Calendar useDate = null;
+
+    private Locale locale = null;
+    
+    /** whether locale inforamtion is evaluated. **/
+    private boolean useLocale = true;
+    
     private String selName = null;
-    private static final String[] monthName =
-        new DateFormatSymbols().getMonths();
     private String onChange = null;
+    private RunData runData = null;
     private boolean onChangeSet = false;
     private boolean showDays = true;
     private int setDay = 0;
     private boolean useYears = false;
     private int firstYear = 0;
     private int lastYear = 0;
-    private int selectedYear = 0;
 
+    static {
+        monthNames = new HashMap();
+    }
 
     /**
      * Constructor defaults to current date and uses the default
@@ -132,6 +165,7 @@
         this.selName = DEFAULT_PREFIX;
         this.useDate = Calendar.getInstance();
         this.useDate.setTime ( new Date() );
+        this.locale = Locale.getDefault();
     }
 
     /**
@@ -145,6 +179,47 @@
     {
         this.useDate = useDate;
         this.selName = selName;
+        this.locale = Locale.getDefault();
+    }
+    
+    /**
+     * <p>Constructor, presets the year, month and day values from
+     * <code>useDate</code>. It will then override these presets if it
+     * finds a value for any of year, month, or day in <code>runData</code>'s
+     * parameters.</p>
+     * 
+     * <p>Also, the <code>runData</code> is used to extract the locale.</p>
+     *
+     * @param selName A String with the selector name.
+     * @param useDate A Calendar to preset values from.
+     * @param runData RunData object to get submitted values and the Locale from.
+     */
+    public DateSelector( String selName, Calendar useDate, RunData runData)
+    {
+        this.useDate = useDate;
+        this.selName = selName;
+        this.runData = runData;
+        this.locale = runData.getLocale();
+        
+        int lYear = runData.getParameters()
+            .getInt(selName + YEAR_SUFFIX, -1);
+        int lMonth = runData.getParameters()
+            .getInt(selName + MONTH_SUFFIX, -1);
+        int lDay = runData.getParameters()
+            .getInt(selName + DAY_SUFFIX, -1);
+        
+        if ( lYear > -1 ) 
+        {
+            useDate.set(Calendar.YEAR, lYear);
+        }
+        if ( lMonth > -1 ) 
+        {
+            useDate.set(Calendar.MONTH, lMonth);
+        }
+        if ( lDay > -1 ) 
+        {
+            useDate.set(Calendar.DAY_OF_MONTH, lDay);
+        }
     }
 
     /**
@@ -160,7 +235,7 @@
     }
 
     /**
-     * Adds the onChange to all of <SELECT> tags.  This is limited to
+     * Adds the onChange to all of &lt;SELECT&gt; tags.  This is limited to
      * one function for all three popups and is only used when the
      * output() methods are used.  Individual getMonth, getDay,
      * getYear static methods will not use this setting.
@@ -234,7 +309,154 @@
     {
         return selName;
     }
+    
+    /**
+     * <p>Set whether the locale should be used when determining months' names.
+     * Defaults to <code>true</code>.</p>
+     *
+     * @param useLocale If <code>false</code>, the default locale will be used
+     * instead of the locale in runData.
+     */
+     public void setUseLocale(boolean useLocale) 
+     {
+         this.useLocale = useLocale;
+     }
+     
+     /**
+      * <p>Determine whether the locale is used when months' names are 
+      * determined.</p>
+      *
+      * @return <code>true</code> if the locale is used.
+      */
+     public boolean getUseLocale() 
+     {
+         return this.useLocale;
+     }
+         
+    
+    /** 
+     * Getter for property runData.
+     * @return Value of property runData.
+     */
+    public RunData getRunData()
+    {
+        return this.runData;
+    }
+    
+    /** 
+     * <p>Setter for property runData - locale is not overridden
+     * if already set.</p>
+     *
+     * <p>This will <em>not</em> override
+     * the locale from the information in <code>runData</code> if it is
+     * already set.</p>
+     *
+     * @param runData New value of property runData.
+     */
+    public void setRunData(RunData runData)
+    {
+        this.runData = runData;
+        if ( locale == null ) {
+            locale = runData.getLocale();
+        }
+    }
+    
+    /** 
+     * Which is the first year that is displayed.
+     * @return Value of property firstYear.
+     */
+    public int getFirstYear()
+    {
+        return this.firstYear;
+    }
+    
+    /** 
+     * Set the first year to be displayed.
+     * @param firstYear New value of property firstYear.
+     */
+    public void setFirstYear(int firstYear)
+    {
+        this.firstYear = firstYear;
+    }
+    
+    /** 
+     * Which is the last year that is displayed.
+     * @return Value of property lastYear.
+     */
+    public int getLastYear()
+    {
+        return this.lastYear;
+    }
+    
+    /** 
+     * Set the last year to be displayed.
+     * @param lastYear New value of property lastYear.
+     */
+    public void setLastYear(int lastYear)
+    {
+        this.lastYear = lastYear;
+    }    
+    
+    /** 
+     * Get the locale used for months' names.
+     * @return Value of locale.
+     */
+    public Locale getLocale()
+    {
+        return this.locale;
+    }
+    
+    /** 
+     * Set the locale used for months' names.
+     * @param locale New value of locale.
+     */
+    public void setLocale(Locale locale)
+    {
+        this.locale = locale;
+    }
 
+    /** 
+     * Whether a custom range of years is displayed.
+     *
+     * The range is gotten with {@link #getFirstYear}
+     * and {@link #getLastYear}.
+     *
+     * @return Value of property useYears.
+     */
+    public boolean getUseYears()
+    {
+        return this.useYears;
+    }
+    
+    /** 
+     * Set whether a custom range of year is displauyed.
+     *
+     * The range is set with {@link #setFirstYear} and
+     * {@link #setLastYear}.
+     *
+     * @param useYears New value of property useYears.
+     */
+    public void setUseYears(boolean useYears)
+    {
+        this.useYears = useYears;
+    }
+        
+    /**
+     * Get the Date currently stored in the calendar.
+     */
+    public Date getDate() 
+    {
+        return useDate.getTime();
+    }
+     
+    /**
+     * <p>Get the calendar currently stored.</p>
+     */
+    public Calendar getCalendar() 
+    {
+        return useDate;
+    }
+    
     /**
      * Return a month selector.
      *
@@ -260,8 +482,28 @@
     public static Select getMonthSelector(String name,
                                           Calendar now)
     {
+        return getMonthSelector(name, now, Locale.getDefault());
+    }
+    
+    /**
+     * Return a month selector.
+     *
+     * Note: The values of the month placed into the select list are
+     * the month integers starting at 0 (ie: if the user selects
+     * February, the selected value will be 1).
+     *
+     * @param name The name to use for the selected month.
+     * @param now <code>Calendar</code> to start with.
+     * @param locale <code>Locale</code> to use for month names.
+     * @return A select object with all the months.
+     */
+    public static Select getMonthSelector
+        (String name, Calendar now, Locale locale)
+    {
         Select monthSelect = new Select().setName(name);
-
+        String[] monthName = null;
+        monthName = getMonthNames(locale);
+        
         for (int curMonth = 0;curMonth <= 11; curMonth++)
         {
             Option o = new Option();
@@ -358,7 +600,6 @@
 
         for(int currentYear = firstYear;
             currentYear <= lastYear;
-
             currentYear++)
         {
             Option o = new Option();
@@ -390,7 +631,7 @@
             this.useYears = true;
             this.firstYear = firstYear;
             this.lastYear = lastYear;
-            this.selectedYear = selectedYear;
+            this.useDate.set(Calendar.YEAR, selectedYear);
             return true;
         }
         else
@@ -457,7 +698,17 @@
             this.useDate.setTime ( new Date() );
         }
 
-        Select monthSelect = getMonthSelector(selName + MONTH_SUFFIX, useDate);
+        Select monthSelect = null;
+        if ( useLocale ) 
+        {
+            monthSelect = 
+                getMonthSelector(selName + MONTH_SUFFIX, useDate, locale);
+        } 
+        else 
+        {
+            monthSelect = 
+                getMonthSelector(selName + MONTH_SUFFIX, useDate);
+        }
         ConcreteElement daySelect = null;
         if (!showDays)
         {
@@ -476,7 +727,7 @@
         if (useYears)
         {
             yearSelect = getYearSelector(selName + YEAR_SUFFIX,
-                            firstYear, lastYear, selectedYear);
+                            firstYear, lastYear, useDate.get(Calendar.YEAR));
         }
         else
         {
@@ -493,6 +744,40 @@
         ec.addElement(daySelect);
         ec.addElement(yearSelect);
         // ec.addElement(new Comment("== END 
org.apache.turbine.util.DateSelector.ecsOutput() =="));
-        return (ec);
+        return (ec);        
     }
+    
+    /**
+     * Retrieve the names of Months for a given locale.
+     *
+     * @param locale The locale to retrieve the names for
+     * @return An array with the names of the 12 months.
+     */
+    protected static String[] getMonthNames(Locale locale) 
+    {
+        if ( locale == null ) 
+        {
+            locale = Locale.getDefault();
+        }
+        
+        Object names = monthNames.get(locale);
+        if ( names == null ) 
+        {
+            synchronized (DateSelector.class) 
+            {
+                names = monthNames.get(locale);
+                if ( (names = monthNames.get(locale)) == null ) 
+                {
+                    names = new DateFormatSymbols(locale).getMonths();
+                    monthNames.put(locale, names);
+                }
+            }
+        }
+        // Shouldn't happen, but just to make sure.
+        if ((names == null) || (!(names instanceof String[]))) 
+        {
+            return new DateFormatSymbols().getMonths();
+        }
+        return (String[]) names;
+    }               
 }

--
To unsubscribe, e-mail:   <mailto:[EMAIL PROTECTED]>
For additional commands, e-mail: <mailto:[EMAIL PROTECTED]>

Reply via email to