001    package edu.nrao.sss.webapp.faces.component;
002    
003    import javax.faces.component.UIInput;
004    import javax.faces.context.FacesContext;
005    import javax.faces.context.ResponseWriter;
006    import javax.faces.el.ValueBinding;
007    
008    import java.io.IOException;
009    import java.util.Map;
010    import java.util.Date;
011    import java.text.SimpleDateFormat;
012    
013    import edu.nrao.sss.util.DateUtility;
014    import edu.nrao.sss.webapp.faces.converter.DateConverter;
015    
016    import org.apache.log4j.Logger;
017    
018    public class DateTimeUIComponent extends UIInput
019    {
020      private static final Logger log = Logger.getLogger(DateTimeUIComponent.class);
021    
022            private Boolean enabled = null;
023            private Boolean showTime = null;
024            private String dateSeparator = null;
025            private String timeSeparator = null;
026    
027            protected static final SimpleDateFormat getYear   = new SimpleDateFormat("yyyy");
028            protected static final SimpleDateFormat getMonth  = new SimpleDateFormat("MM");
029            protected static final SimpleDateFormat getDay    = new SimpleDateFormat("dd");
030            protected static final SimpleDateFormat getHour   = new SimpleDateFormat("HH");
031            protected static final SimpleDateFormat getMinute = new SimpleDateFormat("mm");
032            protected static final SimpleDateFormat getSecond = new SimpleDateFormat("ss");
033    
034            public void encodeBegin(FacesContext context)
035                    throws IOException
036            {
037                    boolean enabled = isEnabled();
038    
039                    Map attrs = getAttributes();
040                    String disabledDateStyleClass = (String)attrs.get("disabledDateStyleClass");
041                    String disabledTimeStyleClass = (String)attrs.get("disabledTimeStyleClass");
042    
043                    String dateStyleClass = (String)attrs.get("dateStyleClass");
044                    String timeStyleClass = (String)attrs.get("timeStyleClass");
045                    String dateFieldStyleClass = (String)attrs.get("dateFieldStyleClass");
046                    String timeFieldStyleClass = (String)attrs.get("timeFieldStyleClass");
047    
048                    ResponseWriter writer = context.getResponseWriter();
049                    
050                    String id = getClientId(context);
051                    String yearId = id + ":year";
052                    String monthId = id + ":month";
053                    String dayId = id + ":day";
054                    String hourId = id + ":hour";
055                    String minuteId = id + ":minute";
056                    String secondId = id + ":second";
057    
058                    String year = "yyyy";
059                    String month = "MM";
060                    String day = "dd";
061                    String hour = "HH";
062                    String minute = "mm";
063                    String second = "ss";
064    
065                    Date date = (Date)getValue();
066                    
067                    if (date != null && !DateUtility.earlyDateEquals(date) && !DateUtility.lateDateEquals(date))
068        {
069          year   = getYear.format(date);
070          month  = getMonth.format(date);
071          day    = getDay.format(date);
072          hour   = getHour.format(date);
073          minute = getMinute.format(date);
074          second = getSecond.format(date);
075        }
076    
077        // wrapper span with our component id on it
078                    writer.startElement("span", this);
079    
080                    //We render two wrapper spans, one for the date input and one for the time input.
081                    writer.startElement("span", this);
082        writer.writeAttribute("id", id, null);
083                    
084                    //Now 3 input fields with 2 spans for separators.
085                    if (enabled)
086                    {
087                            if (dateStyleClass != null && dateStyleClass.length() > 0)
088                                    writer.writeAttribute("class", dateStyleClass, null);
089                            writer.startElement("input", this);
090                            writer.writeAttribute("type", "text", null);
091                            writer.writeAttribute("id", yearId, null);
092                            writer.writeAttribute("name", yearId, null);
093                            writer.writeAttribute("value", year, null);
094                            writer.writeAttribute("size", 4, null);
095                            writer.writeAttribute("maxlength", 4, null);
096                            writer.writeAttribute("onfocus", "if(this.value == 'yyyy'){this.value='';}", null);
097                            writer.writeAttribute("onblur", "iceSubmitPartial(form, this, event); return false;", null);
098    
099                            if (dateFieldStyleClass != null && dateFieldStyleClass.length() > 0)
100                                    writer.writeAttribute("class", dateFieldStyleClass, null);
101                            writer.endElement("input");
102    
103                            encodeDateSeparator(writer);
104    
105                            writer.startElement("input", this);
106                            writer.writeAttribute("type", "text", null);
107                            writer.writeAttribute("id", monthId, null);
108                            writer.writeAttribute("name", monthId, null);
109                            writer.writeAttribute("value", month, null);
110                            writer.writeAttribute("size", 2, null);
111                            writer.writeAttribute("maxlength", 2, null);
112                            writer.writeAttribute("onfocus", "if(this.value == 'MM'){this.value='';}", null);
113                            writer.writeAttribute("onblur", "iceSubmitPartial(form, this, event); return false;", null);
114    
115                            if (dateFieldStyleClass != null && dateFieldStyleClass.length() > 0)
116                                    writer.writeAttribute("class", dateFieldStyleClass, null);
117    
118                            writer.endElement("input");
119    
120                            encodeDateSeparator(writer);
121    
122                            writer.startElement("input", this);
123                            writer.writeAttribute("type", "text", null);
124                            writer.writeAttribute("id", dayId, null);
125                            writer.writeAttribute("name", dayId, null);
126                            writer.writeAttribute("value", day, null);
127                            writer.writeAttribute("size", 2, null);
128                            writer.writeAttribute("maxlength", 2, null);
129                            writer.writeAttribute("onfocus", "if(this.value == 'dd'){this.value='';}", null);
130                            writer.writeAttribute("onblur", "iceSubmitPartial(form, this, event); return false;", null);
131    
132                            if (dateFieldStyleClass != null && dateFieldStyleClass.length() > 0)
133                                    writer.writeAttribute("class", dateFieldStyleClass, null);
134                            writer.endElement("input");
135                    }
136    
137                    else
138                    {
139                            if (disabledDateStyleClass != null && disabledDateStyleClass.length() > 0)
140                                    writer.writeAttribute("class", disabledDateStyleClass, null);
141                            writer.startElement("span", this);
142                            if (dateFieldStyleClass != null && dateFieldStyleClass.length() > 0)
143                                    writer.writeAttribute("class", dateFieldStyleClass, null);
144                            writer.write(year);
145                            writer.endElement("span");
146    
147                            encodeDateSeparator(writer);
148    
149                            writer.startElement("span", this);
150                            if (dateFieldStyleClass != null && dateFieldStyleClass.length() > 0)
151                                    writer.writeAttribute("class", dateFieldStyleClass, null);
152                            writer.write(month);
153                            writer.endElement("span");
154    
155                            encodeDateSeparator(writer);
156    
157                            writer.startElement("span", this);
158                            if (dateFieldStyleClass != null && dateFieldStyleClass.length() > 0)
159                                    writer.writeAttribute("class", dateFieldStyleClass, null);
160                            writer.write(day);
161                            writer.endElement("span");
162                    }
163    
164    
165                    //End the date input element
166                    writer.endElement("span");
167    
168        if (getShowTime())
169        {
170          writer.startElement("span", this);
171    
172          //Now 3 input fields with 2 spans for separators.
173          if (enabled)
174          {
175            if (timeStyleClass != null && timeStyleClass.length() > 0)
176              writer.writeAttribute("class", timeStyleClass, null);
177            writer.startElement("input", this);
178            writer.writeAttribute("type", "text", null);
179            writer.writeAttribute("id", hourId, null);
180            writer.writeAttribute("name", hourId, null);
181            writer.writeAttribute("value", hour, null);
182            writer.writeAttribute("size", 2, null);
183            writer.writeAttribute("maxlength", 2, null);
184            writer.writeAttribute("onfocus", "if(this.value == 'HH'){this.value='';}", null);
185            writer.writeAttribute("onblur", "iceSubmitPartial(form, this, event); return false;", null);
186    
187            if (timeFieldStyleClass != null && timeFieldStyleClass.length() > 0)
188              writer.writeAttribute("class", timeFieldStyleClass, null);
189            writer.endElement("input");
190    
191            encodeTimeSeparator(writer);
192    
193            writer.startElement("input", this);
194            writer.writeAttribute("type", "text", null);
195            writer.writeAttribute("id", minuteId, null);
196            writer.writeAttribute("name", minuteId, null);
197            writer.writeAttribute("value", minute, null);
198            writer.writeAttribute("size", 2, null);
199            writer.writeAttribute("maxlength", 2, null);
200            writer.writeAttribute("onfocus", "if(this.value == 'mm'){this.value='';}", null);
201            writer.writeAttribute("onblur", "iceSubmitPartial(form, this, event); return false;", null);
202    
203            if (timeFieldStyleClass != null && timeFieldStyleClass.length() > 0)
204              writer.writeAttribute("class", timeFieldStyleClass, null);
205    
206            writer.endElement("input");
207    
208            encodeTimeSeparator(writer);
209    
210            writer.startElement("input", this);
211            writer.writeAttribute("type", "text", null);
212            writer.writeAttribute("id", secondId, null);
213            writer.writeAttribute("name", secondId, null);
214            writer.writeAttribute("value", second, null);
215            writer.writeAttribute("size", 2, null);
216            writer.writeAttribute("maxlength", 2, null);
217            writer.writeAttribute("onfocus", "if(this.value == 'ss'){this.value='';}", null);
218            writer.writeAttribute("onblur", "iceSubmitPartial(form, this, event); return false;", null);
219    
220            if (timeFieldStyleClass != null && timeFieldStyleClass.length() > 0)
221              writer.writeAttribute("class", timeFieldStyleClass, null);
222    
223            writer.endElement("input");
224          }
225    
226          else
227          {
228            if (disabledTimeStyleClass != null && disabledTimeStyleClass.length() > 0)
229              writer.writeAttribute("class", disabledTimeStyleClass, null);
230            writer.startElement("span", this);
231            if (timeFieldStyleClass != null && timeFieldStyleClass.length() > 0)
232              writer.writeAttribute("class", timeFieldStyleClass, null);
233            writer.write(hour);
234            writer.endElement("span");
235    
236            encodeTimeSeparator(writer);
237    
238            writer.startElement("span", this);
239            if (timeFieldStyleClass != null && timeFieldStyleClass.length() > 0)
240              writer.writeAttribute("class", timeFieldStyleClass, null);
241            writer.write(minute);
242            writer.endElement("span");
243    
244            encodeTimeSeparator(writer);
245    
246            writer.startElement("span", this);
247            if (timeFieldStyleClass != null && timeFieldStyleClass.length() > 0)
248              writer.writeAttribute("class", timeFieldStyleClass, null);
249            writer.write(second);
250            writer.endElement("span");
251          }
252    
253          //End the time input element
254          writer.endElement("span");
255        }
256    
257        // end main wrapper
258        writer.endElement("span");
259            }
260    
261            private void encodeDateSeparator(ResponseWriter writer)
262                    throws IOException
263            {
264                    writer.write(getDateSeparator());
265            }
266            
267            private void encodeTimeSeparator(ResponseWriter writer)
268                    throws IOException
269            {
270                    writer.write(getTimeSeparator());
271            }
272            
273            public void decode(FacesContext context)
274            {
275                    String id       = getClientId(context);
276                    String yearId   = id + ":year";
277                    String monthId  = id + ":month";
278                    String dayId    = id + ":day";
279                    String hourId   = id + ":hour";
280                    String minuteId = id + ":minute";
281                    String secondId = id + ":second";
282    
283                    Map parms = context.getExternalContext().getRequestParameterMap();
284    
285                    String year   = (String)parms.get(yearId);
286                    String month  = (String)parms.get(monthId);
287                    String day    = (String)parms.get(dayId);
288                    String hour   = (String)parms.get(hourId);
289                    String minute = (String)parms.get(minuteId);
290                    String second = (String)parms.get(secondId);
291    
292                    
293        boolean showTime = getShowTime();
294    
295                    if (year == null || month == null || day == null)
296                            setSubmittedValue(null);
297    
298        else if (showTime && (hour == null || minute == null || second == null))
299                            setSubmittedValue(null);
300    
301                    else
302                    {
303          boolean atLeastOneSet = false;
304          if (year.equals("yyyy"))
305            year = "2000";
306          else 
307            atLeastOneSet = true;
308    
309          if (month.equals("MM"))
310            month = "01";
311          else
312            atLeastOneSet = true;
313    
314          if (day.equals("dd"))
315            day = "01";
316          else
317            atLeastOneSet = true;
318    
319          if (showTime)
320          {
321            if (hour.equals("HH"))
322              hour = "00";
323            else
324              atLeastOneSet = true;
325    
326            if (minute.equals("mm"))
327              minute = "00";
328            else
329              atLeastOneSet = true;
330    
331            if (second.equals("ss"))
332              second = "00";
333            else
334              atLeastOneSet = true;
335          }
336    
337          if (!atLeastOneSet)
338            setSubmittedValue(null);
339    
340          else
341          {
342            //Regardless of the separators the user sees, here we need to use the
343            //separators that the DateConverter is expecting.
344    
345            StringBuilder date = new StringBuilder(year);
346            date.append(DateConverter.dateFieldSeparator);
347            date.append(month);
348            date.append(DateConverter.dateFieldSeparator);
349            date.append(day);
350    
351            date.append(DateConverter.dateTimeSeparator);
352    
353            if (showTime)
354            {
355              date.append(hour);
356              date.append(DateConverter.timeFieldSeparator);
357              date.append(minute);
358              date.append(DateConverter.timeFieldSeparator);
359              date.append(second);
360            }
361    
362            else
363            {
364              date.append("00");
365              date.append(DateConverter.timeFieldSeparator);
366              date.append("00");
367              date.append(DateConverter.timeFieldSeparator);
368              date.append("00");
369            }
370    
371            setValid(true);
372    
373            setSubmittedValue(date.toString());
374          }
375                    }
376            }
377    
378            public Object saveState(FacesContext context)
379            {
380                    Object[] state = new Object[4];
381                    state[0] = super.saveState(context);
382                    state[1] = this.enabled;
383                    state[2] = this.dateSeparator;
384                    state[3] = this.timeSeparator;
385                    state[4] = this.showTime;
386                    
387                    return state;
388            }
389            
390            public void restoreState(FacesContext context, Object state)
391            {
392                    Object[] myState = (Object[])state;
393                    super.restoreState(context, myState[0]);
394                    setEnabled((Boolean)myState[1]);
395                    setDateSeparator((String)myState[2]);
396                    setTimeSeparator((String)myState[3]);
397                    setShowTime((Boolean)myState[4]);
398            }
399            
400            public String getDateSeparator()
401            {
402                    if (this.dateSeparator != null)
403                            return this.dateSeparator;
404                    
405                    ValueBinding vb = getValueBinding("dateSeparator");
406                    if (vb != null)
407                    {
408                            Object val = vb.getValue(getFacesContext());
409                            
410                            if (val instanceof String && val != null)
411                                    return (String)val;
412                    }
413                    
414                    //else
415                    return "-";
416            }
417            
418            public void setDateSeparator(String s)
419            {
420                    this.dateSeparator = s;
421            }
422            
423            public String getTimeSeparator()
424            {
425                    if (this.timeSeparator != null)
426                            return this.timeSeparator;
427                    
428                    ValueBinding vb = getValueBinding("timeSeparator");
429                    if (vb != null)
430                    {
431                            Object val = vb.getValue(getFacesContext());
432                            
433                            if (val instanceof String && val != null)
434                                    return (String)val;
435                    }
436                    
437                    //else
438                    return ":";
439            }
440            
441            public void setTimeSeparator(String s)
442            {
443                    this.timeSeparator = s;
444            }
445            
446            public Boolean isEnabled()
447            {
448                    if (this.enabled != null)
449                            return this.enabled;
450                    
451                    ValueBinding vb = getValueBinding("enabled");
452                    if (vb != null)
453                    {
454                            Object val = vb.getValue(getFacesContext());
455                            
456                            if (val instanceof Boolean && val != null)
457                                    return (Boolean)val;
458                    }
459                    
460                    //else
461                    return Boolean.TRUE;
462            }
463            
464            public void setEnabled(Boolean e)
465            {
466                    this.enabled = e;
467            }
468            
469            public Boolean getShowTime()
470            {
471                    if (this.showTime != null)
472                            return this.showTime;
473                    
474                    ValueBinding vb = getValueBinding("showTime");
475                    if (vb != null)
476                    {
477                            Object val = vb.getValue(getFacesContext());
478                            
479                            if (val instanceof Boolean && val != null)
480                                    return (Boolean)val;
481                    }
482                    
483                    //else
484                    return Boolean.TRUE;
485            }
486            
487            public void setShowTime(Boolean s)
488            {
489                    this.showTime = s;
490            }
491            
492    
493            /** Overridden to be empty. */
494            public void encodeEnd(FacesContext context) throws IOException {}
495            
496            /** Overridden to be empty. */
497            public void encodeChildren(FacesContext context) throws IOException {}
498    }