001/* 002 Licensed to the Apache Software Foundation (ASF) under one 003 or more contributor license agreements. See the NOTICE file 004 distributed with this work for additional information 005 regarding copyright ownership. The ASF licenses this file 006 to you under the Apache License, Version 2.0 (the 007 "License"); you may not use this file except in compliance 008 with the License. You may obtain a copy of the License at 009 010 http://www.apache.org/licenses/LICENSE-2.0 011 012 Unless required by applicable law or agreed to in writing, 013 software distributed under the License is distributed on an 014 "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 015 KIND, either express or implied. See the License for the 016 specific language governing permissions and limitations 017 under the License. 018 */ 019package org.apache.wiki.tags; 020 021import org.apache.log4j.Logger; 022import org.apache.wiki.WikiContext; 023import org.apache.wiki.WikiEngine; 024import org.apache.wiki.WikiPage; 025import org.apache.wiki.util.HttpUtil; 026import org.apache.wiki.util.TextUtil; 027 028import javax.servlet.http.HttpServletRequest; 029import javax.servlet.jsp.JspWriter; 030import java.io.IOException; 031import java.text.ParseException; 032import java.text.SimpleDateFormat; 033import java.util.Calendar; 034import java.util.Date; 035 036 037/** 038 * Provides a nice calendar. Responds to the following HTTP parameters: 039 * <ul> 040 * <li>calendar.date - If this parameter exists, then the calendar 041 * date is taken from the month and year. The date must be in ddMMyy 042 * format. 043 * <li>weblog.startDate - If calendar.date parameter does not exist, 044 * we then check this date. 045 * </ul> 046 * 047 * If neither calendar.date nor weblog.startDate parameters exist, 048 * then the calendar will default to the current month. 049 * 050 * @since 2.0 051 */ 052 053// FIXME: This class is extraordinarily lacking. 054public class CalendarTag extends WikiTagBase { 055 056 private static final long serialVersionUID = 0L; 057 private static final Logger log = Logger.getLogger( CalendarTag.class ); 058 059 private SimpleDateFormat m_pageFormat = null; 060 private SimpleDateFormat m_urlFormat = null; 061 private SimpleDateFormat m_monthUrlFormat = null; 062 private SimpleDateFormat m_dateFormat = new SimpleDateFormat( "ddMMyy" ); 063 064 /** 065 * {@inheritDoc} 066 */ 067 @Override 068 public void initTag() 069 { 070 super.initTag(); 071 m_pageFormat = m_urlFormat = m_monthUrlFormat = null; 072 m_dateFormat = new SimpleDateFormat( "ddMMyy" ); 073 } 074 075 /* 076 public void setYear( String year ) 077 { 078 m_year = year; 079 } 080 081 public void setMonth( String month ) 082 { 083 m_month = month; 084 } 085 */ 086 087 /** 088 * Sets the page format. If a page corresponding to the format is found when 089 * the calendar is being rendered, a link to that page is created. E.g. if the 090 * format is set to <tt>'Main_blogentry_'ddMMyy</tt>, it works nicely in 091 * conjuction to the WeblogPlugin. 092 * 093 * @param format The format in the SimpleDateFormat fashion. 094 * 095 * @see SimpleDateFormat 096 * @see org.apache.wiki.plugin.WeblogPlugin 097 */ 098 public void setPageformat( final String format ) 099 { 100 m_pageFormat = new SimpleDateFormat( format ); 101 } 102 103 /** 104 * Set the URL format. If the pageformat is not set, all dates are 105 * links to pages according to this format. The pageformat 106 * takes precedence. 107 * 108 * @param format The URL format in the SimpleDateFormat fashion. 109 * @see SimpleDateFormat 110 */ 111 public void setUrlformat( final String format ) 112 { 113 m_urlFormat = new SimpleDateFormat( format ); 114 } 115 116 /** 117 * Set the format to be used for links for the months. 118 * 119 * @param format The format to set in the SimpleDateFormat fashion. 120 * 121 * @see SimpleDateFormat 122 */ 123 public void setMonthurlformat( final String format ) 124 { 125 m_monthUrlFormat = new SimpleDateFormat( format ); 126 } 127 128 private String format( final String txt ) { 129 final WikiPage p = m_wikiContext.getPage(); 130 if( p != null ) { 131 return TextUtil.replaceString( txt, "%p", p.getName() ); 132 } 133 134 return txt; 135 } 136 137 /** 138 * Returns a link to the given day. 139 */ 140 private String getDayLink( final Calendar day ) { 141 final WikiEngine engine = m_wikiContext.getEngine(); 142 final String result; 143 144 if( m_pageFormat != null ) { 145 final String pagename = m_pageFormat.format( day.getTime() ); 146 147 if( engine.pageExists( pagename ) ) { 148 if( m_urlFormat != null ) { 149 final String url = m_urlFormat.format( day.getTime() ); 150 result = "<td class=\"link\"><a href=\""+url+"\">"+day.get( Calendar.DATE )+"</a></td>"; 151 } else { 152 result = "<td class=\"link\"><a href=\""+m_wikiContext.getViewURL( pagename )+"\">"+ 153 day.get( Calendar.DATE )+"</a></td>"; 154 } 155 } else { 156 result = "<td class=\"days\">"+day.get(Calendar.DATE)+"</td>"; 157 } 158 } else if( m_urlFormat != null ) { 159 final String url = m_urlFormat.format( day.getTime() ); 160 result = "<td><a href=\""+url+"\">"+day.get( Calendar.DATE )+"</a></td>"; 161 } else { 162 result = "<td class=\"days\">"+day.get(Calendar.DATE)+"</td>"; 163 } 164 165 return format( result ); 166 } 167 168 private String getMonthLink( final Calendar day ) { 169 final SimpleDateFormat monthfmt = new SimpleDateFormat( "MMMM yyyy" ); 170 final String result; 171 172 if( m_monthUrlFormat == null ) { 173 result = monthfmt.format( day.getTime() ); 174 } else { 175 final Calendar cal = (Calendar)day.clone(); 176 final int firstDay = cal.getActualMinimum( Calendar.DATE ); 177 final int lastDay = cal.getActualMaximum( Calendar.DATE ); 178 179 cal.set( Calendar.DATE, lastDay ); 180 String url = m_monthUrlFormat.format( cal.getTime() ); 181 182 url = TextUtil.replaceString( url, "%d", Integer.toString( lastDay - firstDay + 1 ) ); 183 184 result = "<a href=\""+url+"\">"+monthfmt.format(cal.getTime())+"</a>"; 185 } 186 187 return format( result ); 188 } 189 190 private String getMonthNaviLink( final Calendar day, final String txt, String queryString ) { 191 final String result; 192 queryString = TextUtil.replaceEntities( queryString ); 193 final Calendar nextMonth = Calendar.getInstance(); 194 nextMonth.set( Calendar.DATE, 1 ); 195 nextMonth.add( Calendar.DATE, -1); 196 nextMonth.add( Calendar.MONTH, 1 ); // Now move to 1st day of next month 197 198 if ( day.before( nextMonth ) ) { 199 final WikiPage thePage = m_wikiContext.getPage(); 200 final String pageName = thePage.getName(); 201 202 final String calendarDate = m_dateFormat.format( day.getTime() ); 203 String url = m_wikiContext.getURL( WikiContext.VIEW, pageName,"calendar.date="+calendarDate ); 204 205 if( queryString != null && queryString.length() > 0 ) { 206 // 207 // Ensure that the 'calendar.date=ddMMyy' has been removed from the queryString 208 // 209 210 // FIXME: Might be useful to have an entire library of 211 // routines for this. Will fail if it's not calendar.date 212 // but something else. 213 214 final int pos1 = queryString.indexOf("calendar.date="); 215 if( pos1 >= 0 ) { 216 String tmp = queryString.substring( 0, pos1 ); 217 // FIXME: Will this fail when we use & instead of &? 218 // FIXME: should use some parsing routine 219 final int pos2 = queryString.indexOf("&", pos1 ) + 1; 220 if ( ( pos2 > 0 ) && ( pos2 < queryString.length() ) ) { 221 tmp = tmp + queryString.substring(pos2); 222 } 223 queryString = tmp; 224 } 225 226 if( queryString.length() > 0 ) { 227 url = url + "&" + queryString; 228 } 229 } 230 result = "<td><a href=\""+url+"\">"+txt+"</a></td>"; 231 } else { 232 result="<td> </td>"; 233 } 234 235 return format( result ); 236 } 237 238 /** 239 * {@inheritDoc} 240 */ 241 @Override 242 public final int doWikiStartTag() throws IOException { 243 final WikiEngine engine = m_wikiContext.getEngine(); 244 final JspWriter out = pageContext.getOut(); 245 final Calendar cal = Calendar.getInstance(); 246 final Calendar prevCal = Calendar.getInstance(); 247 final Calendar nextCal = Calendar.getInstance(); 248 249 // 250 // Check if there is a parameter in the request to set the date. 251 // 252 String calendarDate = pageContext.getRequest().getParameter( "calendar.date" ); 253 if( calendarDate == null ) { 254 calendarDate = pageContext.getRequest().getParameter( "weblog.startDate" ); 255 } 256 257 if( calendarDate != null ) { 258 try { 259 final Date d = m_dateFormat.parse( calendarDate ); 260 cal.setTime( d ); 261 prevCal.setTime( d ); 262 nextCal.setTime( d ); 263 } catch( final ParseException e ) { 264 log.warn( "date format wrong: " + calendarDate ); 265 } 266 } 267 268 cal.set( Calendar.DATE, 1 ); // First, set to first day of month 269 prevCal.set( Calendar.DATE, 1 ); 270 nextCal.set( Calendar.DATE, 1 ); 271 272 prevCal.add(Calendar.MONTH, -1); // Now move to first day of previous month 273 nextCal.add(Calendar.MONTH, 1); // Now move to first day of next month 274 275 out.write( "<table class=\"calendar\">\n" ); 276 277 final HttpServletRequest httpServletRequest = m_wikiContext.getHttpRequest(); 278 final String queryString = HttpUtil.safeGetQueryString( httpServletRequest, engine.getContentEncoding() ); 279 out.write( "<tr>"+ 280 getMonthNaviLink(prevCal,"<<", queryString)+ 281 "<td colspan=5 class=\"month\">"+ 282 getMonthLink( cal )+ 283 "</td>"+ 284 getMonthNaviLink(nextCal,">>", queryString)+ 285 "</tr>\n" 286 ); 287 288 final int month = cal.get( Calendar.MONTH ); 289 cal.set( Calendar.DAY_OF_WEEK, Calendar.MONDAY ); // Then, find the first day of the week. 290 291 out.write( "<tr><td class=\"weekdays\">Mon</td>"+ 292 "<td class=\"weekdays\">Tue</td>"+ 293 "<td class=\"weekdays\">Wed</td>"+ 294 "<td class=\"weekdays\">Thu</td>"+ 295 "<td class=\"weekdays\">Fri</td>"+ 296 "<td class=\"weekdays\">Sat</td>"+ 297 "<td class=\"weekdays\">Sun</td></tr>\n" ); 298 299 boolean noMoreDates = false; 300 while( !noMoreDates ) { 301 out.write( "<tr>" ); 302 303 for( int i = 0; i < 7; i++ ) { 304 final int mth = cal.get( Calendar.MONTH ); 305 306 if( mth != month ) { 307 out.write("<td class=\"othermonth\">"+cal.get(Calendar.DATE)+"</td>"); 308 } else { 309 out.write( getDayLink(cal) ); 310 } 311 312 cal.add( Calendar.DATE, 1 ); 313 } 314 315 if( cal.get( Calendar.MONTH ) != month ) { 316 noMoreDates = true; 317 } 318 319 out.write( "</tr>\n" ); 320 } 321 322 out.write( "</table>\n" ); 323 324 return EVAL_BODY_INCLUDE; 325 } 326 327}