/********************************************************************************** * $URL: $ * $Id: $ *********************************************************************************** * * Copyright (c) 2003, 2004, 2005, 2006 The Sakai Foundation. * * Licensed under the Educational Community License, Version 1.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.opensource.org/licenses/ecl1.php * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * **********************************************************************************/ package uk.ac.cam.caret.sakai.rwiki.component.macros; import java.io.IOException; import java.io.Writer; import java.util.Iterator; import java.util.List; import org.radeox.api.macro.MacroParameter; import org.radeox.macro.BaseMacro; import uk.ac.cam.caret.sakai.rwiki.component.Messages; import uk.ac.cam.caret.sakai.rwiki.component.radeox.service.impl.SpecializedRenderContext; import uk.ac.cam.caret.sakai.rwiki.component.radeox.service.impl.SpecializedRenderEngine; import uk.ac.cam.caret.sakai.rwiki.service.api.PageLinkRenderer; import uk.ac.cam.caret.sakai.rwiki.service.api.RWikiObjectService; import uk.ac.cam.caret.sakai.rwiki.service.api.model.RWikiObject; import uk.ac.cam.caret.sakai.rwiki.utils.NameHelper; /** * @author andrew */ public class IndexMacro extends BaseMacro { private static final String description = ""; //$NON-NLS-1$ public String getDescription() { return description; } public String[] getParamDescription() { return new String[] { Messages.getString("IndexMacro.1"), //$NON-NLS-1$ Messages.getString("IndexMacro.2") }; //$NON-NLS-1$ } /* * (non-Javadoc) * * @see org.radeox.macro.BaseMacro#getName() */ public String getName() { return "index"; //$NON-NLS-1$ } /* * (non-Javadoc) * * @see org.radeox.macro.BaseMacro#execute(java.io.Writer, * org.radeox.macro.parameter.MacroParameter) */ public void execute(Writer writer, MacroParameter params) throws IllegalArgumentException, IOException { SpecializedRenderContext context = (SpecializedRenderContext) params .getContext(); SpecializedRenderEngine spRe = (SpecializedRenderEngine) context .getRenderEngine(); PageLinkRenderer plr = spRe.getPageLinkRenderer(); plr.setCachable(false); String space = params.get("space", 0); //$NON-NLS-1$ if (space == null || "".equals(space.trim())) //$NON-NLS-1$ { space = spRe.getSpace(); } boolean nohead = "nohead".equals(params.get("nohead", 1)); //$NON-NLS-1$ //$NON-NLS-2$ RWikiObjectService objectService = context.getObjectService(); // This may be very inefficient as we don't necessarily want the objects List subpages = objectService.findRWikiSubPages(space + NameHelper.SPACE_SEPARATOR); Iterator it = subpages.iterator(); writer.write("<div class=\"index-list\">\n"); //$NON-NLS-1$ if (!nohead) { writer.write(Messages.getString("IndexMacro.0")); //$NON-NLS-1$ writer.write(space); writer.write("</p>\n"); //$NON-NLS-1$ } { String currentSpace = space; char[] currentNameChars = currentSpace.toCharArray(); int currentSpaceIndex = currentNameChars.length; writer.write(" <ul class=\"tree\">\n"); //$NON-NLS-1$ while (it.hasNext()) { RWikiObject next = (RWikiObject) it.next(); String nextName = next.getName(); char[] nextNameChars = nextName.toCharArray(); int nextSpaceIndex = nextName .lastIndexOf(NameHelper.SPACE_SEPARATOR); /* * OK next's space is either: i) same space as the currentSpace, * ii) some subspace from the currentSpace, or iii) some other * part of the tree. */ boolean isNextLonger = nextSpaceIndex > currentSpaceIndex; char[] longerSpace = isNextLonger ? nextNameChars : currentNameChars; int longerSpaceLength = isNextLonger ? nextSpaceIndex : currentSpaceIndex; int shortSpaceLength = !isNextLonger ? nextSpaceIndex : currentSpaceIndex; int index = 0; // lastSep should always be set to 0 at least (since spaces are // normal) int lastSep = -1; while (index < shortSpaceLength && nextNameChars[index] == currentNameChars[index]) { if (longerSpace[index] == NameHelper.SPACE_SEPARATOR) { lastSep = index; } index++; } if (index == shortSpaceLength && index == longerSpaceLength) { // spaces are the same! No space change required! } else if (index == shortSpaceLength && longerSpace[index] == NameHelper.SPACE_SEPARATOR) { // Shorter space is a prefix of the longer space // we have a change up/down one way emitSpaceChange(writer, longerSpace, index, longerSpaceLength, isNextLonger); } else { // We have a change of space which is both up and down // Go down from the current space to the lastSep emitSpaceChange(writer, currentNameChars, lastSep, currentSpaceIndex, false); // Then go up to the next space emitSpaceChange(writer, nextNameChars, lastSep, nextSpaceIndex, true); } emitListItem(writer, plr, nextNameChars, nextSpaceIndex + 1); currentNameChars = nextNameChars; currentSpaceIndex = nextSpaceIndex; } // now check whether we have to go down to the original space if (currentSpaceIndex > space.length()) { emitSpaceChange(writer, currentNameChars, space.length(), currentSpaceIndex, false); } writer.write(" </ul>\n"); //$NON-NLS-1$ } writer.write("</div>\n"); //$NON-NLS-1$ } private void emitSpaceChange(Writer writer, char[] chars, int index, int end, boolean up) throws IOException { // indexes are at most length left div 2 (we don't even care // about +1 at the end as it can't be!) int[] sepIndexes = new int[((end - index) / 2) + 1]; int spaces = 0; sepIndexes[spaces++] = index; while (++index < end) { if (chars[index] == NameHelper.SPACE_SEPARATOR) { sepIndexes[spaces++] = index; } } sepIndexes[spaces] = end; if (up) { for (int i = 0; i < spaces; i++) { emitGoUp(writer, chars, sepIndexes[i] + 1, sepIndexes[i + 1]); } } else { for (int i = spaces; i > 0; i--) { emitGoDown(writer, chars, sepIndexes[i - 1] + 1, sepIndexes[i]); } } } private void emitGoUp(Writer writer, char[] chars, int start, int end) throws IOException { writer.write("<li><a href=\"#\" class=\"subspace-link\">"); //$NON-NLS-1$ writer.write(chars, start, end - start + 1); writer.write("</a>\n<ul>"); //$NON-NLS-1$ } private void emitGoDown(Writer writer, char[] chars, int start, int end) throws IOException { writer.write("</ul>\n</li>"); //$NON-NLS-1$ } private void emitListItem(Writer writer, PageLinkRenderer plr, char[] chars, int start) throws IOException { writer.write("<li>"); //$NON-NLS-1$ StringBuffer sb = new StringBuffer(chars.length * 3); plr.appendLink(sb, new String(chars), new String(chars, start, chars.length - start), null, true); writer.write(sb.toString()); writer.write("</li>\n"); //$NON-NLS-1$ } }