001: /*
002: JSPWiki - a JSP-based WikiWiki clone.
003:
004: Copyright (C) 2001 Janne Jalkanen (Janne.Jalkanen@iki.fi)
005:
006: This program is free software; you can redistribute it and/or modify
007: it under the terms of the GNU Lesser General Public License as published by
008: the Free Software Foundation; either version 2.1 of the License, or
009: (at your option) any later version.
010:
011: This program is distributed in the hope that it will be useful,
012: but WITHOUT ANY WARRANTY; without even the implied warranty of
013: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
014: GNU Lesser General Public License for more details.
015:
016: You should have received a copy of the GNU Lesser General Public License
017: along with this program; if not, write to the Free Software
018: Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
019: */
020: package com.ecyrd.jspwiki.plugin;
021:
022: import java.text.DateFormat;
023: import java.text.SimpleDateFormat;
024: import java.util.*;
025:
026: import org.apache.ecs.xhtml.*;
027: import org.apache.log4j.Logger;
028:
029: import com.ecyrd.jspwiki.TextUtil;
030: import com.ecyrd.jspwiki.WikiContext;
031: import com.ecyrd.jspwiki.WikiEngine;
032: import com.ecyrd.jspwiki.WikiPage;
033: import com.ecyrd.jspwiki.attachment.Attachment;
034:
035: /**
036: * Returns the Recent Changes.
037: *
038: * Parameters: since=number of days,
039: * format=(compact|full)
040: *
041: * @author Janne Jalkanen
042: */
043: public class RecentChangesPlugin implements WikiPlugin {
044: private static final String PARAM_FORMAT = "format";
045: private static final String PARAM_TIME_FORMAT = "timeFormat";
046: private static final String PARAM_DATE_FORMAT = "dateFormat";
047:
048: /** How many days we show by default. */
049: private static final int DEFAULT_DAYS = 100 * 365;
050:
051: private static Logger log = Logger
052: .getLogger(RecentChangesPlugin.class);
053:
054: private boolean isSameDay(Date a, Date b) {
055: Calendar aa = Calendar.getInstance();
056: aa.setTime(a);
057: Calendar bb = Calendar.getInstance();
058: bb.setTime(b);
059:
060: return aa.get(Calendar.YEAR) == bb.get(Calendar.YEAR)
061: && aa.get(Calendar.DAY_OF_YEAR) == bb
062: .get(Calendar.DAY_OF_YEAR);
063: }
064:
065: /**
066: * {@inheritDoc}
067: */
068: public String execute(WikiContext context, Map params)
069: throws PluginException {
070: int since = TextUtil.parseIntParameter((String) params
071: .get("since"), DEFAULT_DAYS);
072: int spacing = 4;
073: boolean showAuthor = true;
074: boolean showChangenote = true;
075: int tablewidth = 4;
076:
077: WikiEngine engine = context.getEngine();
078:
079: //
080: // Which format we want to see?
081: //
082: if ("compact".equals(params.get(PARAM_FORMAT))) {
083: spacing = 0;
084: showAuthor = false;
085: showChangenote = false;
086: tablewidth = 2;
087: }
088:
089: Calendar sincedate = new GregorianCalendar();
090: sincedate.add(Calendar.DAY_OF_MONTH, -since);
091:
092: log.debug("Calculating recent changes from "
093: + sincedate.getTime());
094:
095: // FIXME: Should really have a since date on the getRecentChanges
096: // method.
097: Collection changes = engine.getRecentChanges();
098:
099: if (changes != null) {
100: Date olddate = new Date(0);
101:
102: DateFormat fmt = getDateFormat(params);
103: DateFormat tfmt = getTimeFormat(params);
104:
105: table rt = new table();
106: rt.setCellPadding(spacing).setClass("recentchanges");
107:
108: for (Iterator i = changes.iterator(); i.hasNext();) {
109: WikiPage pageref = (WikiPage) i.next();
110:
111: Date lastmod = pageref.getLastModified();
112:
113: if (lastmod.before(sincedate.getTime())) {
114: break;
115: }
116:
117: if (!isSameDay(lastmod, olddate)) {
118: tr row = new tr();
119: td col = new td();
120:
121: col.setColSpan(tablewidth).setClass("date");
122: col.addElement(new b().addElement(fmt
123: .format(lastmod)));
124:
125: rt.addElement(row);
126: row.addElement(col);
127: olddate = lastmod;
128: }
129:
130: String link = context
131: .getURL(
132: pageref instanceof Attachment ? WikiContext.ATTACH
133: : WikiContext.VIEW, pageref
134: .getName());
135:
136: a linkel = new a(link, engine.beautifyTitle(pageref
137: .getName()));
138:
139: tr row = new tr();
140:
141: td col = new td().setWidth("30%").addElement(linkel);
142:
143: //
144: // Add the direct link to the attachment info.
145: //
146: if (pageref instanceof Attachment) {
147: linkel = new a().setHref(context.getURL(
148: WikiContext.INFO, pageref.getName()));
149: linkel.addElement(new img().setSrc(context.getURL(
150: WikiContext.NONE,
151: "images/attachment_small.png")));
152:
153: col.addElement(linkel);
154: }
155:
156: row.addElement(col);
157: rt.addElement(row);
158:
159: if (pageref instanceof Attachment) {
160: row.addElement(new td(tfmt.format(lastmod))
161: .setClass("lastchange"));
162: } else {
163: td infocol = (td) new td().setClass("lastchange");
164: infocol.addElement(new a(context.getURL(
165: WikiContext.DIFF, pageref.getName(),
166: "r1=-1"), tfmt.format(lastmod)));
167: row.addElement(infocol);
168: }
169:
170: //
171: // Display author information.
172: //
173:
174: if (showAuthor) {
175: String author = pageref.getAuthor();
176:
177: td authorinfo = new td();
178: authorinfo.setClass("author");
179:
180: if (author != null) {
181: if (engine.pageExists(author)) {
182: authorinfo.addElement(new a(context.getURL(
183: WikiContext.VIEW, author), author));
184: } else {
185: authorinfo.addElement(author);
186: }
187: } else {
188: authorinfo.addElement("unknown");
189: }
190:
191: row.addElement(authorinfo);
192: }
193:
194: // Change note
195: if (showChangenote) {
196: String changenote = (String) pageref
197: .getAttribute(WikiPage.CHANGENOTE);
198:
199: row.addElement(new td(changenote != null ? TextUtil
200: .replaceEntities(changenote) : "")
201: .setClass("changenote"));
202: }
203:
204: // Revert note
205: /*
206: if( context.hasAdminPermissions() )
207: {
208: row.addElement( new td("Revert") );
209: }
210: */
211: }
212:
213: rt.setPrettyPrint(true);
214: return rt.toString();
215: }
216:
217: return "";
218: }
219:
220: // TODO: Ideally the default behavior should be to return the default format for the default
221: // locale, but that is at odds with the 1st version of this plugin. We seek to preserve the
222: // behaviour of that first version, so to get the default format, the user must explicitly do
223: // something like: dateFormat='' timeformat='' which is a odd, but probably okay.
224: private DateFormat getTimeFormat(Map params) {
225: String formatString = get(params, "HH:mm:ss", PARAM_TIME_FORMAT);
226:
227: if ("".equals(formatString.trim()))
228: return SimpleDateFormat.getTimeInstance();
229:
230: return new SimpleDateFormat(formatString);
231: }
232:
233: private DateFormat getDateFormat(Map params) {
234: String formatString = get(params, "dd.MM.yyyy",
235: PARAM_DATE_FORMAT);
236:
237: if ("".equals(formatString.trim()))
238: return SimpleDateFormat.getDateInstance();
239:
240: return new SimpleDateFormat(formatString);
241:
242: }
243:
244: private String get(Map params, String defaultValue, String paramName) {
245: String value = (String) params.get(paramName);
246: return null == value ? defaultValue : value;
247: }
248:
249: }
|