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