View Javadoc

1   /***
2    * Calendar Tag Library
3    * Copyright (C) 2005 James Smith
4    * 
5    * This library is free software; you can redistribute it and/or
6    * modify it under the terms of the GNU Lesser General Public
7    * License as published by the Free Software Foundation; either
8    * version 2.1 of the License, or (at your option) any later version.
9    *
10   * This library is distributed in the hope that it will be useful,
11   * but WITHOUT ANY WARRANTY; without even the implied warranty of
12   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13   * Lesser General Public License for more details.
14   * 
15   * You should have received a copy of the GNU Lesser General Public
16   * License along with this library; if not, write to the Free Software
17   * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18   * You should be able to download a copy of the LGPL from
19   * www.opensource.org/licenses/lgpl-license.php
20   */
21  package org.calendartag.tags;
22  
23  import java.util.Date;
24  import java.util.Calendar;
25  import java.util.GregorianCalendar;
26  import java.util.Enumeration;
27  import java.text.SimpleDateFormat;
28  import javax.servlet.jsp.tagext.Tag;
29  import javax.servlet.jsp.PageContext;
30  import javax.servlet.jsp.JspException;
31  
32  import org.apache.taglibs.standard.tag.el.core.ExpressionUtil;
33  import org.calendartag.decorator.DefaultCalendarDecorator;
34  import org.calendartag.decorator.CalendarDecorator;
35  import org.calendartag.util.CalendarTagUtil;
36  
37  import javax.servlet.http.HttpServletRequest;
38  
39  /***
40   * Author: James Smith
41   * Date: Aug 23, 2004
42   * Time: 8:22:03 PM
43   */
44  public class CalendarTag implements Tag {
45  
46      private final static String EMPTY_DAY_STYLE = "calendarEmptyDayStyle";
47      private final static String TABLE_STYLE = "calendarTableStyle";
48      private final static String TITLE_STYLE = "calendarTitleStyle";
49      private final static String WEEKDAY_STYLE = "calendarWeekdayStyle";
50      private final static String PREVIOUS_LINK_STYLE = "calendarPreviousLinkStyle";
51      private final static String NEXT_LINK_STYLE = "calendarNextLinkStyle";
52  
53      private final static boolean INTERACTIVE_DEFAULT = true;
54      private final static String WEEK_START_DEFAULT = "Sunday";
55      private final static int DAY_HEIGHT_DEFAULT = 85;
56      private final static int DAY_WIDTH_DEFAULT = 85;
57  
58      private SimpleDateFormat DATE_FORMAT = new SimpleDateFormat("MM-dd-yyyy");
59  
60      private PageContext pageContext;
61      private Tag parent;
62  
63      private String decorator;
64      private String requestURI;
65      private int dayHeight;
66      private int dayWidth;
67  
68      private String id;
69      private String cssPrefix;
70      private String weekStart;
71      private String showPreviousNextLinks;
72  
73      private String startDate;
74      private String endDate;
75  
76      private String date;
77  
78      private int day = 0;
79      private int month = 0;
80      private int year = 0;
81  
82      private Calendar startCalendar;
83      private Calendar endCalendar;
84      private Calendar calendar;
85      private Boolean showPreviousNextLinksBoolean;
86  
87      private CalendarDecorator decoratorObject;
88  
89      private Calendar todayCalendar = new GregorianCalendar();
90  
91      private boolean singleMonth = false;
92      
93      public void setPageContext(PageContext pageContext) {
94          this.pageContext = pageContext;
95      }
96  
97      public void setParent(Tag parent) {
98          this.parent = parent;
99      }
100 
101     public Tag getParent() {
102         return parent;
103     }
104 
105     public int doStartTag() throws JspException {
106         return Tag.EVAL_BODY_INCLUDE;
107     }
108 
109     private void initializeAttributes() throws JspException {
110 
111         CalendarTagUtil.trimCalendar(todayCalendar);
112 
113         if (id == null) {
114             id = "";
115         }
116 
117         if (cssPrefix == null) {
118             cssPrefix = "";
119         }
120 
121         // prepare the calendar decorator
122         if (!"".equals(decorator) && decorator != null) {
123             // see if what the user specified works
124             try {
125                 Class decoratorClass = Class.forName(decorator);
126                 decoratorObject = (CalendarDecorator) decoratorClass.newInstance();
127             } catch (Exception e) {
128                 throw new JspException("Cannot resolve decorator: " + decorator);
129             }
130         } else {
131             // use the default decorator
132             decoratorObject = new DefaultCalendarDecorator();
133         }
134 
135         // try to evaluate the showPreviousNextLink expression
136         if ("true".equalsIgnoreCase(showPreviousNextLinks)) {
137             showPreviousNextLinksBoolean = new Boolean(true);
138         } else if ("false".equalsIgnoreCase(showPreviousNextLinks)) {
139             showPreviousNextLinksBoolean = new Boolean(false);
140         } else {
141             try {
142                 showPreviousNextLinksBoolean = (Boolean) ExpressionUtil.evalNotNull("calendartag", "calendar", showPreviousNextLinks, Boolean.class, this, pageContext);
143             } catch (Exception e) {
144                 showPreviousNextLinksBoolean = null;
145             }
146         }
147 
148         if (showPreviousNextLinksBoolean == null) {
149             showPreviousNextLinksBoolean = new Boolean(INTERACTIVE_DEFAULT);
150         }
151 
152         if (day == 0 && month == 0 && year == 0) {
153 
154             // try to evaluate the date expression
155             try {
156                 Date tempDate = (Date) ExpressionUtil.evalNotNull("calendartag", "calendar", date, Date.class, this, pageContext);
157                 if (tempDate != null) {
158                     calendar = new GregorianCalendar();
159                     calendar.setTime(tempDate);
160                     CalendarTagUtil.trimCalendar(calendar);
161                 }
162             } catch (Exception e) {
163                 calendar = null;
164             }
165 
166             // try to evaluate the startDate expression
167             try {
168                 Date tempDate = (Date) ExpressionUtil.evalNotNull("calendartag", "calendar", startDate, Date.class, this, pageContext);
169                 if (tempDate != null) {
170                     startCalendar = new GregorianCalendar();
171                     startCalendar.setTime(tempDate);
172                     CalendarTagUtil.trimCalendar(startCalendar);
173                 }
174             } catch (Exception e) {
175                 startCalendar = null;
176             }
177 
178             // try to evaluate the endDate expression
179             try {
180                 Date tempDate = (Date) ExpressionUtil.evalNotNull("calendartag", "calendar", endDate, Date.class, this, pageContext);
181                 if (tempDate != null) {
182                     endCalendar = new GregorianCalendar();
183                     endCalendar.setTime(tempDate);
184                     CalendarTagUtil.trimCalendar(endCalendar);
185                 }
186             } catch (Exception e) {
187                 endCalendar = null;
188             }
189             if (startCalendar == null && endCalendar != null) {
190                 throw new JspException("You specified an endDate but not a startDate");
191             }
192 
193             if (endCalendar == null && startCalendar != null) {
194                 throw new JspException("You specified a startDate but not an endDate");
195             }
196 
197             if (startCalendar != null && endCalendar != null) {
198 
199                 // make sure they don't contain hours, minutes or seconds
200                 CalendarTagUtil.trimCalendar(startCalendar);
201                 CalendarTagUtil.trimCalendar(endCalendar);
202 
203                 // make sure they are in order
204                 if (startCalendar.after(endCalendar)) {
205                     throw new JspException("You startDate is after your endDate.");
206                 }
207                 System.out.println("startCalendar and endCalendar were not null");
208                 if (calendar == null) {
209                     // set the current date to the first date overall, this will be overridden by the request
210                     // parameters if neccessary
211                 	System.out.println("calendar is null");
212                     calendar = (Calendar) startCalendar.clone();
213                     System.out.println("calendar is " + calendar.getTime());
214                 }
215 
216             }
217 
218         }
219 
220         // check to see if the calendar is null, if it is we should try to use the specified attributes
221         if (calendar == null) {
222             calendar = (Calendar) todayCalendar.clone();
223             // if they do equal 0 then they will default to the current date
224             if (day != 0) {
225                 calendar.set(Calendar.DATE, day);
226             }
227             if (month != 0) {
228                 calendar.set(Calendar.MONTH, month);
229             }
230             if (year != 0) {
231                 calendar.set(Calendar.YEAR, year);
232             }
233         }
234 
235         // if they are both null we will use a normal month calendar
236         if (startCalendar == null && endCalendar == null) {
237 
238             endCalendar = (Calendar) todayCalendar.clone();
239             startCalendar = (Calendar) todayCalendar.clone();
240 
241             // set it to the first day of evaluatedDates month
242             startCalendar.set(Calendar.YEAR, calendar.get(Calendar.YEAR));
243             startCalendar.set(Calendar.MONTH, calendar.get(Calendar.MONTH));
244             startCalendar.set(Calendar.DATE, startCalendar.getActualMinimum(Calendar.DATE));
245 
246             // set it to the last day of evaluatedDates month
247             endCalendar.set(Calendar.YEAR, calendar.get(Calendar.YEAR));
248             endCalendar.set(Calendar.MONTH, calendar.get(Calendar.MONTH));
249             endCalendar.set(Calendar.DATE, startCalendar.getActualMaximum(Calendar.DATE));
250 
251             singleMonth = true;
252 
253         }
254 
255         // check the parameter for a changed selected date
256         try {
257             // even if a tempDate is already specified this takes precidence
258             Date tempDate = DATE_FORMAT.parse(pageContext.getRequest().getParameter(id + "date"));
259             Calendar parameterCalendar = new GregorianCalendar();
260             parameterCalendar.setTime(tempDate);
261             if (parameterCalendar != null && !singleMonth) {
262 
263                 calendar = parameterCalendar;
264 
265                 // if the tempDate isn't inside the valid range because it was overridden by the parameter
266                 // we need to calculate the new range
267                 if (endCalendar != null && startCalendar != null
268                         && CalendarTagUtil.dayCompare(calendar, endCalendar) > 0) {
269 
270                     int dayDifference = CalendarTagUtil.differenceInDays(startCalendar, endCalendar) + 1;
271 
272                     // continue until the tempDate is no longer after the end tempDate
273                     while (CalendarTagUtil.dayCompare(calendar, endCalendar) > 0) {
274 
275                         // increment both calendars by the dayDifference
276                         endCalendar.set(Calendar.DATE, endCalendar.get(Calendar.DATE) + dayDifference);
277                         startCalendar.set(Calendar.DATE, startCalendar.get(Calendar.DATE) + dayDifference);
278 
279                     }
280 
281                 } else if (endCalendar != null && startCalendar != null
282                         && CalendarTagUtil.dayCompare(calendar, startCalendar) < 0) {
283 
284                     int dayDifference = CalendarTagUtil.differenceInDays(startCalendar, endCalendar) + 1;
285 
286                     // continue until the tempDate is no longer before the start tempDate
287                     while (CalendarTagUtil.dayCompare(calendar, startCalendar) < 0) {
288 
289                         // increment both calendars by the dayDifference
290                         endCalendar.set(Calendar.DATE, endCalendar.get(Calendar.DATE) - dayDifference);
291                         startCalendar.set(Calendar.DATE, startCalendar.get(Calendar.DATE) - dayDifference);
292 
293                     }
294 
295                 }
296 
297             } else {
298 
299                 calendar = parameterCalendar;
300 
301                 // set it to the first day of evaluatedDates month
302                 startCalendar.set(Calendar.YEAR, calendar.get(Calendar.YEAR));
303                 startCalendar.set(Calendar.MONTH, calendar.get(Calendar.MONTH));
304                 startCalendar.set(Calendar.DATE, startCalendar.getActualMinimum(Calendar.DATE));
305 
306                 // set it to the last day of evaluatedDates month
307                 endCalendar.set(Calendar.YEAR, calendar.get(Calendar.YEAR));
308                 endCalendar.set(Calendar.MONTH, calendar.get(Calendar.MONTH));
309                 endCalendar.set(Calendar.DATE, startCalendar.getActualMaximum(Calendar.DATE));
310 
311             }
312         } catch (Exception e) {
313             // otherwise it will use what evauluatedDate came out to be in the first place
314         }
315 
316 
317         // check the height and widths
318         if (dayHeight == 0) {
319             dayHeight = DAY_HEIGHT_DEFAULT;
320         }
321 
322         if (dayWidth == 0) {
323             dayWidth = DAY_WIDTH_DEFAULT;
324         }
325 
326     }
327 
328     public int doEndTag() throws JspException {
329 
330         StringBuffer link = new StringBuffer();
331 
332         // evaluate all expressions
333         initializeAttributes();
334 
335         // figure the week start
336         if ("".equals(weekStart) || weekStart == null) {
337             weekStart = WEEK_START_DEFAULT;
338         }
339         if (weekStart.toLowerCase().equals("sunday")) {
340             calendar.setFirstDayOfWeek(Calendar.SUNDAY);
341         } else if (weekStart.toLowerCase().equals("monday")) {
342             calendar.setFirstDayOfWeek(Calendar.MONDAY);
343         } else if (weekStart.toLowerCase().equals("tuesday")) {
344             calendar.setFirstDayOfWeek(Calendar.TUESDAY);
345         } else if (weekStart.toLowerCase().equals("wednesday")) {
346             calendar.setFirstDayOfWeek(Calendar.WEDNESDAY);
347         } else if (weekStart.toLowerCase().equals("thursday")) {
348             calendar.setFirstDayOfWeek(Calendar.THURSDAY);
349         } else if (weekStart.toLowerCase().equals("friday")) {
350             calendar.setFirstDayOfWeek(Calendar.FRIDAY);
351         } else if (weekStart.toLowerCase().equals("saturday")) {
352             calendar.setFirstDayOfWeek(Calendar.SATURDAY);
353         }
354 
355         decoratorObject.setCalendar(calendar);
356         decoratorObject.setPageContext(pageContext);
357         decoratorObject.setCalendar(startCalendar);
358         decoratorObject.setStart(startCalendar);
359         decoratorObject.setEnd(endCalendar);
360         decoratorObject.initializeCalendar();
361 
362         // check the requestURI
363         if ("".equals(requestURI) || requestURI == null) {
364             // if the user didn't specify one, this might work
365             requestURI = ((HttpServletRequest) pageContext.getRequest()).getRequestURI();
366         }
367 
368         link.append(requestURI);
369 
370         Enumeration parameterEnumeration = pageContext.getRequest().getParameterNames();
371         while (parameterEnumeration.hasMoreElements()) {
372             String name = (String) parameterEnumeration.nextElement();
373             String value = pageContext.getRequest().getParameter(name);
374 
375             if (!(id + "date").equals(name)) {
376                 link.append("&" + name + "=" + value);
377             }
378         }
379         link.append("&" + id + "date=");
380         // change the first & with ?
381         int firstDelim = link.indexOf("&");
382         link.replace(firstDelim, firstDelim + 1, "?");
383 
384         StringBuffer endTag = new StringBuffer();
385 
386         // start the table
387         endTag.append("<table border=\"0\" class=\"" + cssPrefix + TABLE_STYLE + "\"");
388         if (!"".equals(id) && id != null) {
389             endTag.append(" id=\"" + id + "\"");
390         }
391         endTag.append(">\r\n  <tr>\r\n");
392 
393 
394         // draw the header stuff
395         if (showPreviousNextLinksBoolean.booleanValue()) {
396 
397             // used determine the day that that previousl link should direct to
398             int dateDiff = 0;
399             if (!singleMonth) {
400                 // calculate the date difference only if neccessary
401                 dateDiff = CalendarTagUtil.differenceInDays(startCalendar, endCalendar) + 1;
402             }
403 
404             Calendar newCalendar = (Calendar) calendar.clone();
405 
406             if (!singleMonth) {
407                 newCalendar.set(Calendar.DATE, newCalendar.get(Calendar.DATE) - dateDiff);
408             } else {
409                 newCalendar.add(Calendar.MONTH, -1);
410             }
411 
412             endTag.append("    <td colspan=\"1\" class=\"" + cssPrefix + PREVIOUS_LINK_STYLE + "\" >");
413             endTag.append(decoratorObject.getPreviousLink(link + DATE_FORMAT.format(newCalendar.getTime())));
414             endTag.append("</td>\r\n");
415 
416             endTag.append("    <td colspan=\"5\" class=\"" + cssPrefix + TITLE_STYLE + "\" >");
417             endTag.append(decoratorObject.getCalendarTitle());
418             endTag.append("</td>\r\n");
419 
420             newCalendar = (Calendar) calendar.clone();
421             if (!singleMonth) {
422                 newCalendar.set(Calendar.DATE, newCalendar.get(Calendar.DATE) + dateDiff);
423             } else {
424                 newCalendar.add(Calendar.MONTH, 1);
425             }
426 
427             endTag.append("    <td colspan=\"1\" class=\"" + cssPrefix + NEXT_LINK_STYLE + "\" >");
428             endTag.append(decoratorObject.getNextLink(link + DATE_FORMAT.format(newCalendar.getTime())));
429             endTag.append("</td>\r\n");
430 
431         } else {
432             // just draw the header, with 7 colspan
433             endTag.append("    <td colspan=\"7\" class=\"" + cssPrefix + TITLE_STYLE + "\" >");
434             endTag.append(decoratorObject.getCalendarTitle());
435             endTag.append("</td>\r\n");
436         }
437 
438         endTag.append("  </tr>\r\n");
439 
440         endTag.append("  <tr>\r\n");
441         // draw each weekday abbreviation with the decorator
442         for (int i = 0; i < Calendar.DAY_OF_WEEK; i++) {
443             int day = i + calendar.getFirstDayOfWeek();
444             if (day > 7) {
445                 day = day - 7;
446             }
447             endTag.append("    <td class=\"" + cssPrefix + WEEKDAY_STYLE + "\">" + decoratorObject.getWeekdayTitle(day) + "</td>\r\n");
448         }
449         endTag.append("  </tr>\r\n");
450 
451         endTag.append("  <tr>\r\n");
452 
453         // start drawing the days
454 
455         int emptyDays;
456         int column = 0;
457 
458         // count the number of empty days
459         int firstDayOfWeek = startCalendar.get(Calendar.DAY_OF_WEEK);
460         if (calendar.getFirstDayOfWeek() > firstDayOfWeek) {
461             emptyDays = firstDayOfWeek - calendar.getFirstDayOfWeek() + 7;
462         } else {
463             emptyDays = firstDayOfWeek - calendar.getFirstDayOfWeek();
464         }
465 
466         // draw each empty day
467         for (int i = 0; i < emptyDays; i++) {
468             endTag.append("    <td class=\"" + cssPrefix + EMPTY_DAY_STYLE + "\" height=\"" + dayHeight + "\" width=\"" + dayWidth + "\">" + decoratorObject.getEmptyDay() + "</td>\r\n");
469             column++;
470         }
471 
472         Calendar iteratingDate = (Calendar) startCalendar.clone();
473         boolean isOddMonth = true;
474         while (!iteratingDate.after(endCalendar)) {
475 
476             decoratorObject.setCalendar(iteratingDate);
477 
478             if (column == 0) {
479                 endTag.append("  <tr>\r\n");
480             }
481 
482             endTag.append("    <td class=\"" + cssPrefix + decoratorObject.getDayStyleClass(isOddMonth, CalendarTagUtil.isSameDay(calendar, iteratingDate))
483                     + "\" height=\"" + dayHeight + "\" width=\"" + dayWidth + "\">");
484             
485             endTag.append(decoratorObject.getDay(link + DATE_FORMAT.format(iteratingDate.getTime())));
486             endTag.append("</td>\r\n");
487 
488             // increment the column and end it if neccessary
489             column++;
490 
491             if (column == Calendar.DAY_OF_WEEK) {
492                 endTag.append("  </tr>\r\n");
493                 column = 0;
494             }
495 
496             // check to see if we're changing months & or years
497             if (iteratingDate.getActualMaximum(Calendar.DATE) == iteratingDate.get(Calendar.DATE)) {
498                 if (isOddMonth) {
499                     isOddMonth = false;
500                 } else {
501                     isOddMonth = true;
502                 }
503             }
504 
505             // increment the date, Calendar wraps it month and/or year if needed
506             iteratingDate.set(Calendar.DATE, iteratingDate.get(Calendar.DATE) + 1);
507 
508         }
509 
510         while (column < Calendar.DAY_OF_WEEK && column > 0) {
511             endTag.append("    <td class=\"" + cssPrefix + EMPTY_DAY_STYLE + "\" height=\"" + dayHeight + "\" width=\"" + dayWidth + "\">" + decoratorObject.getEmptyDay() + "</td>\r\n");
512             column++;
513         }
514 
515         endTag.append("  </tr>\r\n");
516         endTag.append("</table>\r\n");
517 
518         try {
519             this.pageContext.getOut().print(endTag.toString());
520         } catch (Exception e) {
521             System.out.println(e.getMessage());
522             e.printStackTrace();
523             throw new JspException(e);
524         }
525 
526         // clean up
527         release();
528         
529         return Tag.EVAL_PAGE;
530     }
531 
532     public String getId() {
533         return id;
534     }
535 
536     public void setId(String id) {
537         this.id = id;
538     }
539 
540     public int getDayHeight() {
541         return dayHeight;
542     }
543 
544     public void setDayHeight(int dayHeight) {
545         this.dayHeight = dayHeight;
546     }
547 
548     public int getDayWidth() {
549         return dayWidth;
550     }
551 
552     public void setDayWidth(int dayWidth) {
553         this.dayWidth = dayWidth;
554     }
555 
556     public String getStartDate() {
557         return startDate;
558     }
559 
560     public void setStartDate(String startDate) {
561         this.startDate = startDate;
562     }
563 
564     public String getEndDate() {
565         return endDate;
566     }
567 
568     public void setEndDate(String endDate) {
569         this.endDate = endDate;
570     }
571 
572     public String getShowPreviousNextLinks() {
573         return showPreviousNextLinks;
574     }
575 
576     public void setShowPreviousNextLink(String showPreviousNextLinks) {
577         this.showPreviousNextLinks = showPreviousNextLinks;
578     }
579 
580     public String getDecorator() {
581         return decorator;
582     }
583 
584     public void setDecorator(String decorator) {
585         this.decorator = decorator;
586     }
587 
588     public String getRequestURI() {
589         return requestURI;
590     }
591 
592     public void setRequestURI(String requestURI) {
593         this.requestURI = requestURI;
594     }
595 
596     public String getWeekStart() {
597         return weekStart;
598     }
599 
600     public void setWeekStart(String weekStart) {
601         this.weekStart = weekStart;
602     }
603 
604     public String getDate() {
605         return date;
606     }
607 
608     public void setDate(String date) {
609         this.date = date;
610     }
611 
612     public int getDay() {
613         return day;
614     }
615 
616     public void setDay(int day) {
617         this.day = day;
618     }
619 
620     public int getMonth() {
621         return month;
622     }
623 
624     public void setMonth(int month) {
625         this.month = month;
626     }
627 
628     public int getYear() {
629         return year;
630     }
631 
632     public void setYear(int year) {
633         this.year = year;
634     }
635 
636     public String getCssPrefix() {
637         return cssPrefix;
638     }
639 
640     public void setCssPrefix(String cssPrefix) {
641         this.cssPrefix = cssPrefix;
642     }
643 
644     /***
645      * Ensures everything is reset
646      */
647 	public void release() {
648 		day = 0;
649 		month = 0;
650 		year = 0;
651 		startCalendar = null;
652 		endCalendar = null;
653 		calendar = null;
654 		showPreviousNextLinks = null;
655 		decoratorObject = null;
656 		todayCalendar = new GregorianCalendar();
657 		date = null;
658 		endDate = null;
659 		startDate = null;
660 		decorator = null;
661 		requestURI = "";
662 		dayHeight = 0;
663 		dayWidth = 0;
664 		id = null;
665 		cssPrefix = null;
666 		weekStart = null;
667 		singleMonth = false;
668 	}
669 }