001: /*
002: JSPWiki - a JSP-based WikiWiki clone.
003:
004: Copyright (C) 2002 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.io.StringWriter;
023: import java.util.*;
024:
025: import org.apache.log4j.Logger;
026: import org.apache.oro.text.GlobCompiler;
027: import org.apache.oro.text.regex.*;
028:
029: import com.ecyrd.jspwiki.*;
030: import com.ecyrd.jspwiki.providers.ProviderException;
031:
032: /**
033: * Builds an index of all pages.
034: * <P>Parameters</P>
035: * <UL>
036: * <LI>itemsPerLine: How many items should be allowed per line before break.
037: * If set to zero (the default), will not write breaks.
038: * <LI>include: Include only these pages.
039: * <LI>exclude: Exclude with this pattern.
040: * </UL>
041: *
042: * @author Alain Ravet
043: * @author Janne Jalkanen
044: * @since 1.9.9
045: */
046: public class IndexPlugin implements WikiPlugin {
047: protected static final Logger log = Logger
048: .getLogger(IndexPlugin.class);
049:
050: public static final String INITIALS_COLOR = "red";
051: private static final int DEFAULT_ITEMS_PER_LINE = 0;
052:
053: private static final String PARAM_ITEMS_PER_LINE = "itemsPerLine";
054: private static final String PARAM_INCLUDE = "include";
055: private static final String PARAM_EXCLUDE = "exclude";
056:
057: private int m_currentNofPagesOnLine = 0;
058: private int m_itemsPerLine;
059: protected String m_previousPageFirstLetter = "";
060: protected StringWriter m_bodyPart = new StringWriter();
061: protected StringWriter m_headerPart = new StringWriter();
062: private Pattern m_includePattern;
063: private Pattern m_excludePattern;
064:
065: public String execute(WikiContext wikiContext, Map params)
066: throws PluginException {
067: //
068: // Parse arguments and create patterns.
069: //
070: PatternCompiler compiler = new GlobCompiler();
071: m_itemsPerLine = TextUtil.parseIntParameter((String) params
072: .get(PARAM_ITEMS_PER_LINE), DEFAULT_ITEMS_PER_LINE);
073: try {
074: String ptrn = (String) params.get(PARAM_INCLUDE);
075: if (ptrn == null)
076: ptrn = "*";
077: m_includePattern = compiler.compile(ptrn);
078:
079: ptrn = (String) params.get(PARAM_EXCLUDE);
080: if (ptrn == null)
081: ptrn = "";
082: m_excludePattern = compiler.compile(ptrn);
083: } catch (MalformedPatternException e) {
084: throw new PluginException("Illegal pattern detected."); // FIXME, make a proper error.
085: }
086:
087: //
088: // Get pages, then sort.
089: //
090:
091: final Collection allPages = getAllPagesSortedByName(wikiContext);
092:
093: //
094: // Build the page.
095: //
096: buildIndexPageHeaderAndBody(wikiContext, allPages);
097:
098: StringBuffer res = new StringBuffer();
099:
100: res.append("<div class=\"index\">\n");
101: res.append("<div class=\"header\">\n");
102: res.append(m_headerPart.toString());
103: res.append("</div>\n");
104: res.append("<div class=\"body\">\n");
105: res.append(m_bodyPart.toString());
106: res.append("</div>\n</div>\n");
107:
108: return res.toString();
109: }
110:
111: private void buildIndexPageHeaderAndBody(WikiContext context,
112: final Collection allPages) {
113: PatternMatcher matcher = new Perl5Matcher();
114:
115: for (Iterator i = allPages.iterator(); i.hasNext();) {
116: WikiPage curPage = (WikiPage) i.next();
117:
118: if (matcher.matches(curPage.getName(), m_includePattern)) {
119: if (!matcher.matches(curPage.getName(),
120: m_excludePattern)) {
121: ++m_currentNofPagesOnLine;
122:
123: String pageNameFirstLetter = curPage.getName()
124: .substring(0, 1).toUpperCase();
125: boolean sameFirstLetterAsPreviousPage = m_previousPageFirstLetter
126: .equals(pageNameFirstLetter);
127:
128: if (!sameFirstLetterAsPreviousPage) {
129: addLetterToIndexHeader(pageNameFirstLetter);
130: addLetterHeaderWithLine(pageNameFirstLetter);
131:
132: m_currentNofPagesOnLine = 1;
133: m_previousPageFirstLetter = pageNameFirstLetter;
134: }
135:
136: addPageToIndex(context, curPage);
137: breakLineIfTooLong();
138: }
139: }
140: } // for
141: }
142:
143: /**
144: * Gets all pages, then sorts them.
145: */
146: static Collection getAllPagesSortedByName(WikiContext wikiContext) {
147: final WikiEngine engine = wikiContext.getEngine();
148:
149: final PageManager pageManager = engine.getPageManager();
150: if (pageManager == null)
151: return null;
152:
153: Collection result = new TreeSet(new Comparator() {
154: public int compare(Object o1, Object o2) {
155: if (o1 == null || o2 == null)
156: return 0;
157:
158: WikiPage page1 = (WikiPage) o1;
159: WikiPage page2 = (WikiPage) o2;
160:
161: return page1.getName().compareTo(page2.getName());
162: }
163: });
164:
165: try {
166: Collection allPages = pageManager.getAllPages();
167: result.addAll(allPages);
168: } catch (ProviderException e) {
169: log.fatal("PageProvider is unable to list pages: ", e);
170: }
171:
172: return result;
173: }
174:
175: private void addLetterToIndexHeader(final String firstLetter) {
176: final boolean noLetterYetInTheIndex = !""
177: .equals(m_previousPageFirstLetter);
178:
179: if (noLetterYetInTheIndex) {
180: m_headerPart.write(" - ");
181: }
182:
183: m_headerPart.write("<a href=\"#" + firstLetter + "\">"
184: + firstLetter + "</a>");
185: }
186:
187: private void addLetterHeaderWithLine(final String firstLetter) {
188: m_bodyPart.write("\n<br /><br />" + "<span class=\"section\">"
189: + "<a name=\"" + firstLetter + "\">" + firstLetter
190: + "</a></span>" + "<hr />\n");
191: }
192:
193: protected void addPageToIndex(WikiContext context, WikiPage curPage) {
194: final boolean notFirstPageOnLine = 2 <= m_currentNofPagesOnLine;
195:
196: if (notFirstPageOnLine) {
197: m_bodyPart.write(", ");
198: }
199:
200: m_bodyPart.write("<a href=\""
201: + context.getURL(WikiContext.VIEW, curPage.getName())
202: + "\">"
203: + context.getEngine().beautifyTitleNoBreak(
204: curPage.getName()) + "</a>");
205: }
206:
207: protected void breakLineIfTooLong() {
208: final boolean limitReached = m_itemsPerLine == m_currentNofPagesOnLine;
209:
210: if (limitReached) {
211: m_bodyPart.write("<br />\n");
212: m_currentNofPagesOnLine = 0;
213: }
214: }
215:
216: }
|