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