View Javadoc

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