blob: 2ab235081c1671e3ce7c7fa46639a3a587a35431 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2000, 2015 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* IBM Corporation - initial API and implementation
*******************************************************************************/
package org.eclipse.help.internal.webapp.data;
import java.io.IOException;
import java.io.Writer;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.eclipse.help.IToc;
import org.eclipse.help.ITopic;
import org.eclipse.help.UAContentFilter;
import org.eclipse.help.base.AbstractHelpScope;
import org.eclipse.help.internal.HelpPlugin;
import org.eclipse.help.internal.base.HelpBasePlugin;
import org.eclipse.help.internal.base.HelpEvaluationContext;
import org.eclipse.help.internal.base.remote.RemoteHelp;
import org.eclipse.help.internal.base.scope.ScopeUtils;
import org.eclipse.help.internal.webapp.servlet.TocFragmentServlet;
/**
* Helper class for tocView.jsp initialization
*/
public class TocData extends ActivitiesData {
public static final String COMPLETE_PATH_PARAM = "cp"; //$NON-NLS-1$
// Request parameters
private String tocParameter;
private String topicHref;
private String expandPathParam;
private String completePath;
// help form of selected topic href
private String topicHelpHref;
// Selected TOC
private int selectedToc = -1;
// path from TOC to the root topic of the TOC fragment
private int[] rootPath = null;
// path from TOC to the selected topic, excluding TOC;
private ITopic[] topicPath = null;
// String representing the topic path as numbers separated by underscores e.g. 2_4_3
private String numericPath;
// List of TOC's, unfiltered
private IToc[] tocs;
// images directory
private String imagesDirectory;
// Scope
private AbstractHelpScope scope;
/**
* Constructs the xml data for the contents page.
*
* @param context
* @param request
*/
public TocData(ServletContext context, HttpServletRequest request,
HttpServletResponse response) {
super(context, request, response);
this.tocParameter = request.getParameter("toc"); //$NON-NLS-1$
this.topicHref = request.getParameter("topic"); //$NON-NLS-1$
this.completePath = request.getParameter(COMPLETE_PATH_PARAM);
this.expandPathParam = request.getParameter("expandPath"); //$NON-NLS-1$
this.scope = RequestScope.getScope(request, response, false);
if (tocParameter != null && tocParameter.length() == 0)
tocParameter = null;
if (topicHref != null && topicHref.length() == 0)
topicHref = null;
if (expandPathParam != null && expandPathParam.length() == 0)
expandPathParam = null;
if (completePath != null && completePath.length() == 0)
completePath = null;
String anchor = request.getParameter("anchor"); //$NON-NLS-1$
if (topicHref != null && anchor != null) {
topicHref = topicHref + '#' + anchor;
}
// initialize rootPath
String pathStr = request.getParameter("path"); //$NON-NLS-1$
if (pathStr != null && pathStr.length() > 0) {
String[] paths = pathStr.split("_", -1); //$NON-NLS-1$
int[] indexes = new int[paths.length];
boolean indexesOK = true;
for (int i = 0; i < paths.length; i++) {
try {
indexes[i] = Integer.parseInt(paths[i]);
} catch (NumberFormatException nfe) {
indexesOK = false;
break;
}
if (indexesOK) {
rootPath = indexes;
}
}
}
imagesDirectory = preferences.getImagesDirectory();
loadTocs();
}
public boolean isRemoteHelpError() {
boolean isError = (RemoteHelp.getError() != null);
if (isError) {
RemoteHelp.clearError();
}
return isError;
}
// Accessor methods to avoid exposing help classes directly to JSP.
// Note: this seems ok for now, but maybe we need to reconsider this
// and allow help classes in JSP's.
public int getTocCount() {
return tocs.length;
}
public String getTocLabel(int i) {
return tocs[i].getLabel();
}
public String getTocHref(int i) {
return tocs[i].getHref();
}
public String getTocDescriptionTopic(int i) {
return UrlUtil.getHelpURL(tocs[i].getTopic(null).getHref());
}
/**
* Returns the selected TOC
*
* @return int
*/
public int getSelectedToc() {
return selectedToc;
}
/**
* Returns the topic to display. If there is a TOC, return its topic
* description. Return null if no topic is specified and there is no toc
* description.
*
* @return String
*/
public String getSelectedTopic() {
if (topicHref != null && topicHref.length() > 0)
return UrlUtil.getHelpURL(topicHref);
else
if (selectedToc == -1)
return null;
IToc toc = tocs[selectedToc];
ITopic tocDescription = toc.getTopic(null);
if (tocDescription != null)
return UrlUtil.getHelpURL(tocDescription.getHref());
return UrlUtil.getHelpURL(null);
}
/**
* Returns the topic to display. If there is a TOC, return its topic
* description. Return null if no topic is specified and there is no toc
* description.
*
* @return String
*/
public String getSelectedTopicWithPath() {
String href = getSelectedTopic();
if ( completePath != null ) {
href = TocFragmentServlet.fixupHref(href, completePath);
}
return href;
}
/**
* Returns a list of all the TOC's as xml elements. Individual TOC's are not
* loaded yet.
*
* @return IToc[]
*/
public IToc[] getTocs() {
return tocs;
}
/**
* Check if given TOC is visible
*
* @param toc
* @return true if TOC should be visible
*/
public boolean isEnabled(int toc) {
return ScopeUtils.showInTree(tocs[toc], scope);
}
/**
* Check if given TOC is visible
*
* @param toc
* @return true if TOC should be visible
*/
private boolean isEnabled(IToc toc) {
if(!isAdvancedUI()){
// activities never filtered for basic browsers
return true;
}
return HelpBasePlugin.getActivitySupport().isEnabled(toc.getHref()) &&
!UAContentFilter.isFiltered(toc, HelpEvaluationContext.getContext());
}
private void loadTocs() {
tocs = HelpPlugin.getTocManager().getTocs(getLocale());
// Find the requested TOC
selectedToc = -1;
if (isExpandPath()) {
getEnabledTopicPath();
} else if (tocParameter != null && tocParameter.length() > 0) {
for (int i = 0; selectedToc == -1 && i < tocs.length; i++) {
if (tocParameter.equals(tocs[i].getHref())) {
selectedToc = i;
}
}
} else if ( completePath != null ) {
// obtain the TOC from the complete path
TopicFinder finder = new TopicFinder("/nav/" + completePath, tocs, scope); //$NON-NLS-1$
topicPath = finder.getTopicPath();
selectedToc = finder.getSelectedToc();
numericPath = finder.getNumericPath();
} else {
// toc not specified as parameter
// try obtaining the TOC from the topic
TopicFinder finder = new TopicFinder(topicHref, tocs, scope);
topicPath = finder.getTopicPath();
selectedToc = finder.getSelectedToc();
numericPath = finder.getNumericPath();
}
}
private void getEnabledTopicPath() {
int[] path = UrlUtil.splitPath(expandPathParam);
if (path != null) {
// path[0] is the index of enabled TOCS, convert to an index into all TOCS
int enabled = path[0] + 1;
for (int i = 0; enabled > 0 && i < tocs.length; i++) {
if (ScopeUtils.showInTree(tocs[i], scope)) {
enabled--;
if (enabled == 0) {
selectedToc = i;
}
}
}
if (selectedToc != -1) {
topicPath = decodePath(path, tocs[selectedToc], scope);
}
} else {
selectedToc = -1;
}
}
public static ITopic[] decodePath(int[] path, IToc toc, AbstractHelpScope scope) {
ITopic[] topicPath = new ITopic[path.length - 1];
try {
if (path.length > 1) {
ITopic[] topics = toc.getTopics();
ITopic[] enabledTopics = ScopeUtils.inScopeTopics(topics, scope);
topicPath[0] = enabledTopics[path[1]];
}
for (int i = 1; i < topicPath.length; i++) {
ITopic[] topics = topicPath[i-1].getSubtopics();
ITopic[] enabledTopics = ScopeUtils.inScopeTopics(topics, scope);
topicPath[i] = enabledTopics[path[i+1]];
}
} catch (RuntimeException e) {
return null;
}
return topicPath;
}
/**
* Generates the HTML code (a tree) for a TOC.
*
* @param toc
* @param out
* @throws IOException
*/
public void generateBasicToc(int toc, Writer out) throws IOException {
ITopic[] topics = getEnabledSubtopics(tocs[toc]);
for (ITopic topic : topics) {
generateBasicTopic(topic, out);
}
}
private void generateBasicTopic(ITopic topic, Writer out)
throws IOException {
out.write("<li>"); //$NON-NLS-1$
ITopic[] topics = getEnabledSubtopics(topic);
boolean hasNodes = topics.length > 0;
if (hasNodes) {
out.write("<nobr>"); //$NON-NLS-1$
out.write("<a "); //$NON-NLS-1$
if (getSelectedTopicHelpHref().equals(topic.getHref())) {
out.write("name=\"selectedItem\" "); //$NON-NLS-1$
}
out.write("href="+"\"" + UrlUtil.getHelpURL(topic.getHref())+"\"" + ">"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
out.write("<img src='"); //$NON-NLS-1$
out.write(imagesDirectory);
out.write("/container_obj.gif' alt=\"\" border=0>&nbsp;"); //$NON-NLS-1$
out.write(UrlUtil.htmlEncode(topic.getLabel()));
out.write("</a>"); //$NON-NLS-1$
out.write("</nobr>"); //$NON-NLS-1$
out.write("<ul>\n"); //$NON-NLS-1$
for (ITopic topic2 : topics) {
generateBasicTopic(topic2, out);
}
out.write("</ul>\n"); //$NON-NLS-1$
} else {
out.write("<nobr>"); //$NON-NLS-1$
out.write("<a "); //$NON-NLS-1$
if (getSelectedTopicHelpHref().equals(topic.getHref())) {
out.write("name=\"selectedItem\" "); //$NON-NLS-1$
}
out.write("href="+"\"" + UrlUtil.getHelpURL(topic.getHref()) +"\""+ ">"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
out.write("<img src='"); //$NON-NLS-1$
out.write(imagesDirectory);
out.write("/topic.gif' alt=\"\" border=0>&nbsp;"); //$NON-NLS-1$
out.write(UrlUtil.htmlEncode(topic.getLabel()));
out.write("</a>"); //$NON-NLS-1$
out.write("</nobr>"); //$NON-NLS-1$
}
out.write("</li>\n"); //$NON-NLS-1$
}
/**
* @return String - help form of selected topic URL, or ""
*/
private String getSelectedTopicHelpHref() {
if (topicHelpHref == null) {
String topic = getSelectedTopic();
if (topic == null || topic.length() == 0) {
topicHelpHref = ""; //$NON-NLS-1$
return topicHelpHref;
}
int index = topic.indexOf("/topic/"); //$NON-NLS-1$
if (index != -1)
topic = topic.substring(index + 6);
index = topic.indexOf('?');
if (index != -1)
topic = topic.substring(0, index);
topicHelpHref = topic;
if (topic == null) {
topicHelpHref = ""; //$NON-NLS-1$
}
}
return topicHelpHref;
}
/**
* Obtains children topics for a given navigation element. Topics from TOCs
* not matching enabled activities are filtered out.
*
* @param element ITopic or IToc
* @return ITopic[]
*/
public ITopic[] getEnabledSubtopics(Object element) {
List<ITopic> topics = getEnabledSubtopicList(element);
return topics.toArray(new ITopic[topics.size()]);
}
/**
* Obtains children topics for a given navigation element. Topics from TOCs
* not matching enabled activities are filtered out.
*
* @param navigationElement
* @return List of ITopic
*/
private List<ITopic> getEnabledSubtopicList(Object element) {
if (element instanceof IToc && !isEnabled((IToc) element))
return Collections.emptyList();
List<ITopic> children;
if (element instanceof IToc) {
children = Arrays.asList(((IToc)element).getTopics());
}
else if (element instanceof ITopic) {
children = Arrays.asList(((ITopic)element).getSubtopics());
}
else {
// unknown element type
return Collections.emptyList();
}
List<ITopic> childTopics = new ArrayList<ITopic>(children.size());
for (ITopic iTopic : children) {
Object c = iTopic;
if ((c instanceof ITopic)) {
// add topic only if it will not end up being an empty
// container
if (((((ITopic) c).getHref() != null && ((ITopic) c)
.getHref().length() > 0) || getEnabledSubtopicList(c).size() > 0) &&
!UAContentFilter.isFiltered(c, HelpEvaluationContext.getContext())) {
childTopics.add((ITopic) c);
}
} else {
// it is a Toc, Anchor or Link,
// which may have children attached to it.
childTopics.addAll(getEnabledSubtopicList(c));
}
}
return childTopics;
}
private void generateTopicLinks(ITopic topic, Writer w, int indent) {
String topicHref = topic.getHref();
try {
if (indent == 0)
w.write("<b>"); //$NON-NLS-1$
for (int tab = 0; tab < indent; tab++) {
w.write("&nbsp;&nbsp;"); //$NON-NLS-1$
}
if (topicHref != null && topicHref.length() > 0) {
w.write("<a href=\""); //$NON-NLS-1$
if ('/' == topicHref.charAt(0)) {
w.write("topic"); //$NON-NLS-1$
}
w.write(topicHref);
w.write("\">"); //$NON-NLS-1$
w.write(UrlUtil.htmlEncode(topic.getLabel()));
w.write("</a>"); //$NON-NLS-1$
} else {
w.write(UrlUtil.htmlEncode(topic.getLabel()));
}
w.write("<br>\n"); //$NON-NLS-1$
if (indent == 0)
w.write("</b>"); //$NON-NLS-1$
} catch (IOException ioe) {
}
ITopic[] topics = topic.getSubtopics();
for (ITopic topic2 : topics) {
generateTopicLinks(topic2, w, indent + 1);
}
}
public void generateLinks(Writer out) {
for (IToc toc : tocs) {
ITopic tocTopic = toc.getTopic(null);
generateTopicLinks(tocTopic, out, 0);
ITopic[] topics = toc.getTopics();
for (ITopic topic : topics) {
generateTopicLinks(topic, out, 1);
}
}
}
public ITopic[] getTopicPathFromRootPath(IToc toc) {
ITopic[] topicPath;
// Determine the topicPath from the path passed in as a parameter
int[] rootPath = getRootPath();
if (rootPath == null) {
return null;
}
int pathLength = rootPath.length;
topicPath = new ITopic[pathLength];
ITopic[] children = toc.getTopics();
for (int i = 0; i < pathLength; i++) {
int index = rootPath[i];
if (index < children.length) {
topicPath[i] = children[index];
children = topicPath[i].getSubtopics();
} else {
return null; // Mismatch between expected and actual children
}
}
return topicPath;
}
public ITopic[] getTopicPath() {
return topicPath;
}
public int[] getRootPath() {
return rootPath;
}
public String getTopicHref() {
return topicHref;
}
public String getNumericPath() {
return numericPath;
}
public boolean isExpandPath() {
return expandPathParam != null;
}
}