Save This Page
Home » struts-2.1.8.1-src » org.apache.struts2.dojo » components » [javadoc | source]
    1   /*
    2    * $Id: DateTimePicker.java 667791 2008-06-14 12:41:00Z hermanns $
    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   
   22   package org.apache.struts2.dojo.components;
   23   
   24   import java.text.DateFormat;
   25   import java.text.Format;
   26   import java.text.MessageFormat;
   27   import java.text.SimpleDateFormat;
   28   import java.util.ArrayList;
   29   import java.util.Calendar;
   30   import java.util.Date;
   31   import java.util.List;
   32   import java.util.Random;
   33   
   34   import javax.servlet.http.HttpServletRequest;
   35   import javax.servlet.http.HttpServletResponse;
   36   
   37   import org.apache.struts2.components.UIBean;
   38   import org.apache.struts2.views.annotations.StrutsTag;
   39   import org.apache.struts2.views.annotations.StrutsTagAttribute;
   40   import org.apache.struts2.views.annotations.StrutsTagSkipInheritance;
   41   
   42   import com.opensymphony.xwork2.util.ValueStack;
   43   import com.opensymphony.xwork2.util.logging.Logger;
   44   import com.opensymphony.xwork2.util.logging.LoggerFactory;
   45   
   46   /**
   47    * <!-- START SNIPPET: javadoc -->
   48    * <p>
   49    * Renders a date/time picker in a dropdown container.
   50    * </p>
   51    * <p>
   52    * A stand-alone DateTimePicker widget that makes it easy to select a date/time, or increment by week, month,
   53    * and/or year.
   54    * </p>
   55    *
   56    * <p>
   57    * It is possible to customize the user-visible formatting with either the
   58    * 'formatLength' (long, short, medium or full) or 'displayFormat' attributes. By defaulty current
   59    * locale will be used.</p>
   60    * </p>
   61    * 
   62    * Syntax supported by 'displayFormat' is (http://www.unicode.org/reports/tr35/tr35-4.html#Date_Format_Patterns):-
   63    * <table border="1">
   64    *   <tr>
   65    *      <td>Format</td>
   66    *      <td>Description</td>
   67    *   </tr>
   68    *   <tr>
   69    *      <td>d</td>
   70    *      <td>Day of the month</td>
   71    *   </tr>
   72    *   <tr>
   73    *      <td>D</td>
   74    *      <td>Day of year</td>
   75    *   </tr>
   76    *   <tr>
   77    *      <td>M</td>
   78    *      <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>
   79    *   </tr>
   80    *   <tr>
   81    *      <td>y</td>
   82    *      <td>Year</td>
   83    *   </tr>
   84    *   <tr>
   85    *      <td>h</td>
   86    *      <td>Hour [1-12].</td>
   87    *   </tr>
   88    *   <tr>
   89    *      <td>H</td>
   90    *      <td>Hour [0-23].</td>
   91    *   </tr>
   92    *   <tr>
   93    *      <td>m</td>
   94    *      <td>Minute. Use one or two for zero padding.</td>
   95    *   </tr>
   96    *   <tr>
   97    *      <td>s</td>
   98    *      <td>Second. Use one or two for zero padding.</td>
   99    *   </tr>
  100    * </table>
  101    * 
  102    * <p>
  103    * The value sent to the server is a locale-independent value, in a hidden field as defined 
  104    * by the name attribute. The value will be formatted conforming to RFC3 339 
  105    * (yyyy-MM-dd'T'HH:mm:ss)
  106    * </p>
  107    * <p>
  108    * The following formats(in order) will be used to parse the values of the attributes 'value', 
  109    * 'startDate' and 'endDate':
  110    * </p>
  111    * <ul>
  112    *   <li>SimpleDateFormat built using RFC 3339 (yyyy-MM-dd'T'HH:mm:ss)
  113    *   <li>SimpleDateFormat.getTimeInstance(DateFormat.SHORT)
  114    *   <li>SimpleDateFormat.getDateInstance(DateFormat.SHORT)
  115    *   <li>SimpleDateFormat.getDateInstance(DateFormat.MEDIUM)
  116    *   <li>SimpleDateFormat.getDateInstance(DateFormat.FULL)
  117    *   <li>SimpleDateFormat.getDateInstance(DateFormat.LONG)
  118    *   <li>SimpleDateFormat built using the value of the 'displayFormat' attribute(if any)
  119    * </ul>
  120    * <!-- END SNIPPET: javadoc -->
  121    *
  122    * <b>Examples</b>
  123    *
  124    * <pre>
  125    * <!-- START SNIPPET: example1 -->
  126    *   &lt;sx:datetimepicker name="order.date" label="Order Date" /&gt;
  127    *   &lt;sx:datetimepicker name="delivery.date" label="Delivery Date" displayFormat="yyyy-MM-dd"  /&gt;
  128    *   &lt;sx:datetimepicker name="delivery.date" label="Delivery Date" value="%{date}"  /&gt;
  129    *   &lt;sx:datetimepicker name="delivery.date" label="Delivery Date" value="%{'2007-01-01'}"  /&gt;
  130    *   &lt;sx:datetimepicker name="order.date" label="Order Date" value="%{'today'}"/&gt;
  131    * <!-- END SNIPPET: example1 -->
  132    * </pre>
  133    * 
  134    * <!-- START SNIPPET: example2 -->
  135    * &lt;sx:datetimepicker id="picker" label="Order Date" /&gt;
  136    * &lt;script type="text/javascript"&gt;
  137    *   function setValue() {
  138    *      var picker = dojo.widget.byId("picker");
  139    *      
  140    *      //string value
  141    *      picker.setValue('2007-01-01');
  142    *      
  143    *      //Date value
  144    *      picker.setValue(new Date());
  145    *   }
  146    *   
  147    *   function showValue() {
  148    *      var picker = dojo.widget.byId("picker");
  149    *      
  150    *      //string value
  151    *      var stringValue = picker.getValue();
  152    *      alert(stringValue);
  153    *      
  154    *      //date value
  155    *      var dateValue = picker.getDate();
  156    *      alert(dateValue);
  157    *   }
  158    * &lt;/script&gt;
  159    * <!-- END SNIPPET: example2 -->
  160    * 
  161    * <!-- START SNIPPET: example3 -->
  162    * &lt;sx:datetimepicker id="picker" label="Order Date" valueNotifyTopics="/value"/&gt;
  163    * 
  164    * &lt;script type="text/javascript"&gt;
  165    * dojo.event.topic.subscribe("/value", function(textEntered, date, widget){
  166    *     alert('value changed');
  167    *     //textEntered: String enetered in the textbox
  168    *     //date: JavaScript Date object with the value selected
  169    *     //widet: widget that published the topic 
  170    * });
  171    * &lt;/script&gt;  
  172    * <!-- END SNIPPET: example3 -->
  173    */
  174   @StrutsTag(name="datetimepicker", tldTagClass="org.apache.struts2.dojo.views.jsp.ui.DateTimePickerTag", description="Render datetimepicker")
  175   public class DateTimePicker extends UIBean {
  176   
  177       final public static String TEMPLATE = "datetimepicker";
  178       // SimpleDateFormat is not thread-safe see:
  179       //   http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6231579
  180       //   http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6178997
  181       // solution is to use stateless MessageFormat instead:
  182       final private static String RFC3339_FORMAT = "yyyy-MM-dd'T'HH:mm:ss";
  183       final private static String RFC3339_PATTERN = "{0,date," + RFC3339_FORMAT + "}";
  184       final protected static Logger LOG = LoggerFactory.getLogger(DateTimePicker.class);
  185       final private static transient Random RANDOM = new Random();    
  186       
  187       protected String iconPath;
  188       protected String formatLength;
  189       protected String displayFormat;
  190       protected String toggleType;
  191       protected String toggleDuration;
  192       protected String type;
  193   
  194       protected String displayWeeks;
  195       protected String adjustWeeks;
  196       protected String startDate;
  197       protected String endDate;
  198       protected String weekStartsOn;
  199       protected String staticDisplay;
  200       protected String dayWidth;
  201       protected String language;
  202       protected String templateCssPath;
  203       protected String valueNotifyTopics;
  204       
  205       public DateTimePicker(ValueStack stack, HttpServletRequest request, HttpServletResponse response) {
  206           super(stack, request, response);
  207       }
  208   
  209       protected String getDefaultTemplate() {
  210           return TEMPLATE;
  211       }
  212   
  213       public void evaluateParams() {
  214           super.evaluateParams();
  215   
  216           if(displayFormat != null)
  217               addParameter("displayFormat", findString(displayFormat));
  218           if(displayWeeks != null)
  219               addParameter("displayWeeks", findString(displayWeeks));
  220           if(adjustWeeks != null)
  221               addParameter("adjustWeeks", findValue(adjustWeeks, Boolean.class));
  222   
  223           if(disabled != null)
  224               addParameter("disabled", findValue(disabled, Boolean.class));
  225   
  226           if(startDate != null)
  227               addParameter("startDate", format(findValue(startDate)));
  228           if(endDate != null)
  229               addParameter("endDate", format(findValue(endDate)));
  230           if(weekStartsOn != null)
  231               addParameter("weekStartsOn", findString(weekStartsOn));
  232           if(staticDisplay != null)
  233               addParameter("staticDisplay", findValue(staticDisplay, Boolean.class));
  234           if(dayWidth != null)
  235               addParameter("dayWidth", findValue(dayWidth, Integer.class));
  236           if(language != null)
  237               addParameter("language", findString(language));
  238           if(value != null) 
  239               addParameter("value", format(findValue(value)));
  240      
  241           if(iconPath != null)
  242               addParameter("iconPath", findString(iconPath));
  243           if(formatLength != null)
  244               addParameter("formatLength", findString(formatLength));
  245           if(toggleType != null)
  246               addParameter("toggleType", findString(toggleType));
  247           if(toggleDuration != null)
  248               addParameter("toggleDuration", findValue(toggleDuration,
  249                       Integer.class));
  250           if(type != null)
  251               addParameter("type", findString(type));
  252           else
  253               addParameter("type", "date");
  254           if(templateCssPath != null)
  255               addParameter("templateCssPath", findString(templateCssPath));
  256           if(valueNotifyTopics != null)
  257               addParameter("valueNotifyTopics", findString(valueNotifyTopics));
  258           
  259           // format the value to RFC 3399
  260           if(parameters.containsKey("value")) {
  261               addParameter("nameValue", parameters.get("value")); 
  262           } else {
  263               if(parameters.containsKey("name")) {
  264                   addParameter("nameValue", format(findValue((String)parameters.get("name")))); 
  265               }
  266           }
  267           
  268           // generate a random ID if not explicitly set and not parsing the content
  269           Boolean parseContent = (Boolean)stack.getContext().get(Head.PARSE_CONTENT);
  270           boolean generateId = (parseContent != null ? !parseContent : true);
  271           
  272           addParameter("pushId", generateId);
  273           if ((this.id == null || this.id.length() == 0) && generateId) {
  274               // resolves Math.abs(Integer.MIN_VALUE) issue reported by FindBugs 
  275               // http://findbugs.sourceforge.net/bugDescriptions.html#RV_ABSOLUTE_VALUE_OF_RANDOM_INT
  276               int nextInt = RANDOM.nextInt();
  277               nextInt = nextInt == Integer.MIN_VALUE ? Integer.MAX_VALUE : Math.abs(nextInt);  
  278               this.id = "widget_" + String.valueOf(nextInt);
  279               addParameter("id", this.id);
  280           }
  281       }
  282       
  283       @Override
  284       @StrutsTagSkipInheritance
  285       public void setTheme(String theme) {
  286           super.setTheme(theme);
  287       }
  288   
  289       @Override
  290       public String getTheme() {
  291           return "ajax";
  292       }
  293       
  294       @StrutsTagAttribute(description="If true, weekly size of calendar changes to acomodate the month if false," +
  295                   " 42 day format is used", type="Boolean", defaultValue="false")
  296       public void setAdjustWeeks(String adjustWeeks) {
  297           this.adjustWeeks = adjustWeeks;
  298       }
  299   
  300       @StrutsTagAttribute(description="How to render the names of the days in the header(narrow, abbr or wide)", defaultValue="narrow")
  301       public void setDayWidth(String dayWidth) {
  302           this.dayWidth = dayWidth;
  303       }
  304   
  305       @StrutsTagAttribute(description="Total weeks to display", type="Integer", defaultValue="6")
  306       public void setDisplayWeeks(String displayWeeks) {
  307           this.displayWeeks = displayWeeks;
  308       }
  309   
  310       @StrutsTagAttribute(description="Last available date in the calendar set", type="Date", defaultValue="2941-10-12")
  311       public void setEndDate(String endDate) {
  312           this.endDate = endDate;
  313       }
  314   
  315       @StrutsTagAttribute(description="First available date in the calendar set", type="Date", defaultValue="1492-10-12")
  316       public void setStartDate(String startDate) {
  317           this.startDate = startDate;
  318       }
  319   
  320       @StrutsTagAttribute(description="Disable all incremental controls, must pick a date in the current display", type="Boolean", defaultValue="false")
  321       public void setStaticDisplay(String staticDisplay) {
  322           this.staticDisplay = staticDisplay;
  323       }
  324   
  325       @StrutsTagAttribute(description="Adjusts the first day of the week 0==Sunday..6==Saturday", type="Integer", defaultValue="0")
  326       public void setWeekStartsOn(String weekStartsOn) {
  327           this.weekStartsOn = weekStartsOn;
  328       }
  329   
  330       @StrutsTagAttribute(description="Language to display this widget in", defaultValue="brower's specified preferred language")
  331       public void setLanguage(String language) {
  332           this.language = language;
  333       }
  334       
  335       @StrutsTagAttribute(description="A pattern used for the visual display of the formatted date, e.g. dd/MM/yyyy")
  336       public void setDisplayFormat(String displayFormat) {
  337           this.displayFormat = displayFormat;
  338       }
  339   
  340       @StrutsTagAttribute(description="Type of formatting used for visual display. Possible values are " +
  341                   "long, short, medium or full", defaultValue="short")
  342       public void setFormatLength(String formatLength) {
  343           this.formatLength = formatLength;
  344       }
  345   
  346       @StrutsTagAttribute(description="Path to icon used for the dropdown")
  347       public void setIconPath(String iconPath) {
  348           this.iconPath = iconPath;
  349       }
  350   
  351       @StrutsTagAttribute(description="Duration of toggle in milliseconds", type="Integer", defaultValue="100")
  352       public void setToggleDuration(String toggleDuration) {
  353           this.toggleDuration = toggleDuration;
  354       }
  355   
  356       @StrutsTagAttribute(description="Defines the type of the picker on the dropdown. Possible values are 'date'" +
  357                   " for a DateTimePicker, and 'time' for a timePicker", defaultValue="date")
  358       public void setType(String type) {
  359           this.type = type;
  360       }
  361   
  362       @StrutsTagAttribute(description="oggle type of the dropdown. Possible values are plain,wipe,explode,fade", defaultValue="plain")
  363       public void setToggleType(String toggleType) {
  364           this.toggleType = toggleType;
  365       }
  366       
  367       @StrutsTagAttribute(description="Template css path")
  368       public void setTemplateCssPath(String templateCssPath) {
  369           this.templateCssPath = templateCssPath;
  370       }
  371       
  372       @StrutsTagAttribute(description="Preset the value of input element")
  373       public void setValue(String arg0) {
  374           super.setValue(arg0);
  375       }
  376       
  377       @StrutsTagAttribute(description="Comma delimmited list of topics that will published when a value is selected")
  378       public void setValueNotifyTopics(String valueNotifyTopics) {
  379           this.valueNotifyTopics = valueNotifyTopics;
  380       }
  381       
  382       private String format(Object obj) {
  383           if(obj == null)
  384               return null;
  385   
  386           if(obj instanceof Date) {
  387               return MessageFormat.format(RFC3339_PATTERN, (Date) obj);
  388           } else if(obj instanceof Calendar) {
  389               return MessageFormat.format(RFC3339_PATTERN, ((Calendar) obj).getTime());
  390           }
  391           else {
  392               // try to parse a date
  393               String dateStr = obj.toString();
  394               if(dateStr.equalsIgnoreCase("today"))
  395                   return MessageFormat.format(RFC3339_PATTERN, new Date());
  396   
  397               
  398               Date date = null;
  399               //formats used to parse the date
  400               List<DateFormat> formats = new ArrayList<DateFormat>();
  401               formats.add(new SimpleDateFormat(RFC3339_FORMAT));
  402               formats.add(SimpleDateFormat.getTimeInstance(DateFormat.SHORT));
  403               formats.add(SimpleDateFormat.getDateInstance(DateFormat.SHORT));
  404               formats.add(SimpleDateFormat.getDateInstance(DateFormat.MEDIUM));
  405               formats.add(SimpleDateFormat.getDateInstance(DateFormat.FULL));
  406               formats.add(SimpleDateFormat.getDateInstance(DateFormat.LONG));
  407               if (this.displayFormat != null) {
  408                   try {
  409                       SimpleDateFormat displayFormat = new SimpleDateFormat(
  410                           (String) getParameters().get("displayFormat"));
  411                       formats.add(displayFormat);
  412                   } catch (Exception e) {
  413                       // don't use it then (this attribute is used by Dojo, not java code)
  414                       LOG.error("Cannot use attribute", e);
  415                   }
  416               }
  417               
  418               for (DateFormat format : formats) {
  419                   try {
  420                       date = format.parse(dateStr);
  421                       if (date != null)
  422                           return MessageFormat.format(RFC3339_PATTERN, date);
  423                   } catch (Exception e) {
  424                       //keep going
  425                   }
  426               }
  427               
  428              // last resource, assume already in correct/default format
  429              if (LOG.isDebugEnabled())
  430                  LOG.debug("Unable to parse date " + dateStr);
  431              return dateStr;
  432           }
  433       }
  434   
  435   }

Save This Page
Home » struts-2.1.8.1-src » org.apache.struts2.dojo » components » [javadoc | source]