View Javadoc

1   /*
2    * $Id: DateTimePicker.java 658363 2008-05-20 17:59:18Z jmitchell $
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  package org.apache.struts2.components;
22  
23  import java.text.ParseException;
24  import java.text.MessageFormat;
25  import java.text.SimpleDateFormat;
26  import java.util.Calendar;
27  import java.util.Date;
28  
29  import javax.servlet.http.HttpServletRequest;
30  import javax.servlet.http.HttpServletResponse;
31  
32  import org.apache.commons.logging.Log;
33  import org.apache.commons.logging.LogFactory;
34  import org.apache.struts2.views.annotations.StrutsTag;
35  import org.apache.struts2.views.annotations.StrutsTagAttribute;
36  
37  import com.opensymphony.xwork2.util.ValueStack;
38  
39  /***
40   * <!-- START SNIPPET: javadoc -->
41   * <p>
42   * Renders a date/time picker in a dropdown container.
43   * </p>
44   * <p>
45   * A stand-alone DateTimePicker widget that makes it easy to select a date/time, or increment by week, month,
46   * and/or year.
47   * </p>
48   *
49   * <p>
50   * It is possible to customize the user-visible formatting with either the
51   * 'formatLength' (long, short, medium or full) or 'displayFormat' attributes. By defaulty current
52   * locale will be used.</p>
53   * </p>
54   * 
55   * Syntax supported by 'displayFormat' is (http://www.unicode.org/reports/tr35/tr35-4.html#Date_Format_Patterns):-
56   * <table border="1">
57   *   <tr>
58   *      <td>Format</td>
59   *      <td>Description</td>
60   *   </tr>
61   *   <tr>
62   *      <td>d</td>
63   *      <td>Day of the month</td>
64   *   </tr>
65   *   <tr>
66   *      <td>D</td>
67   *      <td>Day of year</td>
68   *   </tr>
69   *   <tr>
70   *      <td>M</td>
71   *      <td>Month - Use one or two for the numerical month, three for the abbreviation, or four for the full name, or 5 for the narrow name.</td>
72   *   </tr>
73   *   <tr>
74   *      <td>h</td>
75   *      <td>Hour [1-12].</td>
76   *   </tr>
77   *   <tr>
78   *      <td>H</td>
79   *      <td>Hour [0-23].</td>
80   *   </tr>
81   *   <tr>
82   *      <td>m</td>
83   *      <td>Minute. Use one or two for zero padding.</td>
84   *   </tr>
85   *   <tr>
86   *      <td>s</td>
87   *      <td>Second. Use one or two for zero padding.</td>
88   *   </tr>
89   * </table>
90   * 
91   * <p>
92   * The value sent to the server is
93   * typically a locale-independent value in a hidden field as defined by the name
94   * attribute. RFC3339 representation is the format used.
95   * </p>
96   *
97   * <p/>
98   *
99   * <!-- END SNIPPET: javadoc -->
100  *
101  * <b>Examples</b>
102  *
103  * <pre>
104  * <!-- START SNIPPET: expl1 -->
105  *
106  * Example 1:
107  *     &lt;s:datetimepicker name="order.date" label="Order Date" /&gt;
108  * Example 2:
109  *     &lt;s:datetimepicker name="delivery.date" label="Delivery Date" format="yyyy-MM-dd"  /&gt;
110  *
111  * <!-- END SNIPPET: expl1 -->
112  * </pre>
113  * <p/>
114  *
115  * <!-- START SNIPPET: expldesc2 -->
116  *
117  * The css could be changed by using the following :-
118  *
119  * <!-- END SNIPPET: expldesc2 -->
120  *
121  * <pre>
122  * <!-- START SNIPPET: expl2 -->
123  *
124  * &lt;s:datetimepicker name="birthday" label="Birthday" templateCss="...." /&gt;
125  *
126  * <!-- END SNIPPET: expl2 -->
127  * </pre>
128  *
129  */
130 @StrutsTag(name="datetimepicker", tldTagClass="org.apache.struts2.views.jsp.ui.DateTimePickerTag", description="Render datetimepicker")
131 public class DateTimePicker extends UIBean {
132 
133     final public static String TEMPLATE = "datetimepicker";
134 //  Backported changes from s2 trunk (r657936)
135 //    final private static SimpleDateFormat RFC3339_FORMAT = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss");
136 	final private static String RFC3339_FORMAT = "yyyy-MM-dd'T'HH:mm:ss";
137     final private static String RFC3339_PATTERN = "{0,date," + RFC3339_FORMAT + "}";
138     final protected static Log LOG = LogFactory.getLog(DateTimePicker.class);
139     
140     protected String iconPath;
141     protected String formatLength;
142     protected String displayFormat;
143     protected String toggleType;
144     protected String toggleDuration;
145     protected String type;
146 
147     protected String displayWeeks;
148     protected String adjustWeeks;
149     protected String startDate;
150     protected String endDate;
151     protected String weekStartsOn;
152     protected String staticDisplay;
153     protected String dayWidth;
154     protected String language;
155     protected String templateCssPath;
156 
157     public DateTimePicker(ValueStack stack, HttpServletRequest request, HttpServletResponse response) {
158         super(stack, request, response);
159     }
160 
161     protected String getDefaultTemplate() {
162         return TEMPLATE;
163     }
164 
165     public void evaluateParams() {
166         super.evaluateParams();
167 
168         if(displayWeeks != null)
169             addParameter("displayWeeks", findString(displayWeeks));
170         if(adjustWeeks != null)
171             addParameter("adjustWeeks", findValue(adjustWeeks, Boolean.class));
172         if(startDate != null)
173             addParameter("startDate", findString(startDate));
174         if(endDate != null)
175             addParameter("endDate", findString(endDate));
176         if(weekStartsOn != null)
177             addParameter("weekStartsOn", findString(weekStartsOn));
178         if(staticDisplay != null)
179             addParameter("staticDisplay", findValue(staticDisplay, Boolean.class));
180         if(dayWidth != null)
181             addParameter("dayWidth", findValue(dayWidth, Integer.class));
182         if(language != null)
183             addParameter("language", findString(language));
184         if(value != null)
185             addParameter("value", findString(value));
186         if(iconPath != null)
187             addParameter("iconPath", findString(iconPath));
188         if(formatLength != null)
189             addParameter("formatLength", findString(formatLength));
190         if(displayFormat != null)
191             addParameter("displayFormat", findString(displayFormat));
192         if(toggleType != null)
193             addParameter("toggleType", findString(toggleType));
194         if(toggleDuration != null)
195             addParameter("toggleDuration", findValue(toggleDuration,
196                     Integer.class));
197         if(type != null)
198             addParameter("type", findString(type));
199         else
200             addParameter("type", "date");
201         if(templateCssPath != null)
202             addParameter("templateCssPath", findString(templateCssPath));
203         
204         // format the value to RFC 3399
205         if(parameters.containsKey("value")) {
206             parameters.put("nameValue", format(parameters.get("value")));
207         } else {
208             if(name != null) {
209                 String expr = name;
210                 if(altSyntax()) {
211                     expr = "%{" + expr + "}";
212                 }
213                 addParameter("nameValue", format(findValue(expr)));
214             }
215         }
216     }
217 
218     @StrutsTagAttribute(description="If true, weekly size of calendar changes to acomodate the month if false," +
219                 " 42 day format is used", type="Boolean", defaultValue="false")
220     public void setAdjustWeeks(String adjustWeeks) {
221         this.adjustWeeks = adjustWeeks;
222     }
223 
224     @StrutsTagAttribute(description="How to render the names of the days in the header(narrow, abbr or wide)", defaultValue="narrow")
225     public void setDayWidth(String dayWidth) {
226         this.dayWidth = dayWidth;
227     }
228 
229     @StrutsTagAttribute(description="Total weeks to display", type="Integer", defaultValue="6")
230     public void setDisplayWeeks(String displayWeeks) {
231         this.displayWeeks = displayWeeks;
232     }
233 
234     @StrutsTagAttribute(description="Last available date in the calendar set", type="Date", defaultValue="2941-10-12")
235     public void setEndDate(String endDate) {
236         this.endDate = endDate;
237     }
238 
239     @StrutsTagAttribute(description="First available date in the calendar set", type="Date", defaultValue="1492-10-12")
240     public void setStartDate(String startDate) {
241         this.startDate = startDate;
242     }
243 
244     @StrutsTagAttribute(description="Disable all incremental controls, must pick a date in the current display", type="Boolean", defaultValue="false")
245     public void setStaticDisplay(String staticDisplay) {
246         this.staticDisplay = staticDisplay;
247     }
248 
249     @StrutsTagAttribute(description="Adjusts the first day of the week 0==Sunday..6==Saturday", type="Integer", defaultValue="0")
250     public void setWeekStartsOn(String weekStartsOn) {
251         this.weekStartsOn = weekStartsOn;
252     }
253 
254     @StrutsTagAttribute(description="Language to display this widget in", defaultValue="brower's specified preferred language")
255     public void setLanguage(String language) {
256         this.language = language;
257     }
258     
259     @StrutsTagAttribute(description="A pattern used for the visual display of the formatted date, e.g. dd/MM/yyyy")
260     public void setDisplayFormat(String displayFormat) {
261         this.displayFormat = displayFormat;
262     }
263 
264     @StrutsTagAttribute(description="Type of formatting used for visual display. Possible values are " +
265                 "long, short, medium or full", defaultValue="short")
266     public void setFormatLength(String formatLength) {
267         this.formatLength = formatLength;
268     }
269 
270     @StrutsTagAttribute(description="Path to icon used for the dropdown")
271     public void setIconPath(String iconPath) {
272         this.iconPath = iconPath;
273     }
274 
275     @StrutsTagAttribute(description="Duration of toggle in milliseconds", type="Integer", defaultValue="100")
276     public void setToggleDuration(String toggleDuration) {
277         this.toggleDuration = toggleDuration;
278     }
279 
280     @StrutsTagAttribute(description="Defines the type of the picker on the dropdown. Possible values are 'date'" +
281                 " for a DateTimePicker, and 'time' for a timePicker", defaultValue="date")
282     public void setType(String type) {
283         this.type = type;
284     }
285 
286     @StrutsTagAttribute(description="oggle type of the dropdown. Possible values are plain,wipe,explode,fade", defaultValue="plain")
287     public void setToggleType(String toggleType) {
288         this.toggleType = toggleType;
289     }
290     
291     @StrutsTagAttribute(description="Template css path")
292     public void setTemplateCssPath(String templateCssPath) {
293         this.templateCssPath = templateCssPath;
294     }
295     
296     private String format(Object obj) {
297         if(obj == null)
298             return null;
299 
300         if(obj instanceof Date) {
301             return MessageFormat.format(RFC3339_PATTERN, (Date) obj);
302         } else if(obj instanceof Calendar) {
303             return MessageFormat.format(RFC3339_PATTERN, ((Calendar) obj).getTime());
304         } else {
305             // try to parse a date
306             String dateStr = obj.toString();
307             if(dateStr.equalsIgnoreCase("today"))
308                 return MessageFormat.format(RFC3339_PATTERN, new Date());
309 
310             try {
311                 Date date = null;
312                 if(this.displayFormat != null) {
313                     SimpleDateFormat format = new SimpleDateFormat(
314                             (String) getParameters().get("displayFormat"));
315                     date = format.parse(dateStr);
316                     return MessageFormat.format(RFC3339_PATTERN, date);
317                 } else {
318                     // last resource to assume already in correct/default format
319                     return dateStr;
320                 }
321             } catch (ParseException e) {
322                 LOG.error("Could not parse date", e);
323                 return dateStr;
324             }
325         }
326     }
327 
328 }