/* * Copyright (c) 1998, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */ package com.sun.tools.doclets.formats.html; import java.io.*; import java.text.SimpleDateFormat; import java.util.*; import com.sun.javadoc.*; import com.sun.tools.doclets.formats.html.markup.*; import com.sun.tools.doclets.internal.toolkit.*; import com.sun.tools.doclets.internal.toolkit.taglets.*; import com.sun.tools.doclets.internal.toolkit.util.*; /** * Class for the Html Format Code Generation specific to JavaDoc. * This Class contains methods related to the Html Code Generation which * are used extensively while generating the entire documentation. * *
This is NOT part of any supported API. * If you write code that depends on this, you do so at your own risk. * This code and its internal interfaces are subject to change or * deletion without notice. * * @since 1.2 * @author Atul M Dambalkar * @author Robert Field * @author Bhavesh Patel (Modified) */ public class HtmlDocletWriter extends HtmlDocWriter { /** * Relative path from the file getting generated to the destination * directory. For example, if the file getting generated is * "java/lang/Object.html", then the path to the root is "../..". * This string can be empty if the file getting generated is in * the destination directory. */ public final DocPath pathToRoot; /** * Platform-independent path from the current or the * destination directory to the file getting generated. * Used when creating the file. */ public final DocPath path; /** * Name of the file getting generated. If the file getting generated is * "java/lang/Object.html", then the filename is "Object.html". */ public final DocPath filename; /** * The display length used for indentation while generating the class page. */ public int displayLength = 0; /** * The global configuration information for this run. */ public final ConfigurationImpl configuration; /** * To check whether annotation heading is printed or not. */ protected boolean printedAnnotationHeading = false; /** * To check whether the repeated annotations is documented or not. */ private boolean isAnnotationDocumented = false; /** * To check whether the container annotations is documented or not. */ private boolean isContainerDocumented = false; /** * Constructor to construct the HtmlStandardWriter object. * * @param path File to be generated. */ public HtmlDocletWriter(ConfigurationImpl configuration, DocPath path) throws IOException { super(configuration, path); this.configuration = configuration; this.path = path; this.pathToRoot = path.parent().invert(); this.filename = path.basename(); } /** * Replace {@docRoot} tag used in options that accept HTML text, such * as -header, -footer, -top and -bottom, and when converting a relative * HREF where commentTagsToString inserts a {@docRoot} where one was * missing. (Also see DocRootTaglet for {@docRoot} tags in doc * comments.) *
* Replace {@docRoot} tag in htmlstr with the relative path to the * destination directory from the directory where the file is being * written, looping to handle all such tags in htmlstr. *
* For example, for "-d docs" and -header containing {@docRoot}, when * the HTML page for source file p/C1.java is being generated, the * {@docRoot} tag would be inserted into the header as "../", * the relative path from docs/p/ to docs/ (the document root). *
* Note: This doc comment was written with '@' representing '@'
* to prevent the inline tag from being interpreted.
*/
public String replaceDocRootDir(String htmlstr) {
// Return if no inline tags exist
int index = htmlstr.indexOf("{@");
if (index < 0) {
return htmlstr;
}
String lowerHtml = htmlstr.toLowerCase();
// Return index of first occurrence of {@docroot}
// Note: {@docRoot} is not case sensitive when passed in w/command line option
index = lowerHtml.indexOf("{@docroot}", index);
if (index < 0) {
return htmlstr;
}
StringBuilder buf = new StringBuilder();
int previndex = 0;
while (true) {
if (configuration.docrootparent.length() > 0) {
final String docroot_parent = "{@docroot}/..";
// Search for lowercase version of {@docRoot}/..
index = lowerHtml.indexOf(docroot_parent, previndex);
// If next {@docRoot}/.. pattern not found, append rest of htmlstr and exit loop
if (index < 0) {
buf.append(htmlstr.substring(previndex));
break;
}
// If next {@docroot}/.. pattern found, append htmlstr up to start of tag
buf.append(htmlstr.substring(previndex, index));
previndex = index + docroot_parent.length();
// Insert docrootparent absolute path where {@docRoot}/.. was located
buf.append(configuration.docrootparent);
// Append slash if next character is not a slash
if (previndex < htmlstr.length() && htmlstr.charAt(previndex) != '/') {
buf.append('/');
}
} else {
final String docroot = "{@docroot}";
// Search for lowercase version of {@docRoot}
index = lowerHtml.indexOf(docroot, previndex);
// If next {@docRoot} tag not found, append rest of htmlstr and exit loop
if (index < 0) {
buf.append(htmlstr.substring(previndex));
break;
}
// If next {@docroot} tag found, append htmlstr up to start of tag
buf.append(htmlstr.substring(previndex, index));
previndex = index + docroot.length();
// Insert relative path where {@docRoot} was located
buf.append(pathToRoot.isEmpty() ? "." : pathToRoot.getPath());
// Append slash if next character is not a slash
if (previndex < htmlstr.length() && htmlstr.charAt(previndex) != '/') {
buf.append('/');
}
}
}
return buf.toString();
}
/**
* Get the script to show or hide the All classes link.
*
* @param id id of the element to show or hide
* @return a content tree for the script
*/
public Content getAllClassesLinkScript(String id) {
HtmlTree script = new HtmlTree(HtmlTag.SCRIPT);
script.addAttr(HtmlAttr.TYPE, "text/javascript");
String scriptCode = "" + DocletConstants.NL;
Content scriptContent = new RawHtml(scriptCode);
script.addContent(scriptContent);
Content div = HtmlTree.DIV(script);
return div;
}
/**
* Add method information.
*
* @param method the method to be documented
* @param dl the content tree to which the method information will be added
*/
private void addMethodInfo(MethodDoc method, Content dl) {
ClassDoc[] intfacs = method.containingClass().interfaces();
MethodDoc overriddenMethod = method.overriddenMethod();
// Check whether there is any implementation or overridden info to be
// printed. If no overridden or implementation info needs to be
// printed, do not print this section.
if ((intfacs.length > 0 &&
new ImplementedMethods(method, this.configuration).build().length > 0) ||
overriddenMethod != null) {
MethodWriterImpl.addImplementsInfo(this, method, dl);
if (overriddenMethod != null) {
MethodWriterImpl.addOverridden(this,
method.overriddenType(), overriddenMethod, dl);
}
}
}
/**
* Adds the tags information.
*
* @param doc the doc for which the tags will be generated
* @param htmltree the documentation tree to which the tags will be added
*/
protected void addTagsInfo(Doc doc, Content htmltree) {
if (configuration.nocomment) {
return;
}
Content dl = new HtmlTree(HtmlTag.DL);
if (doc instanceof MethodDoc) {
addMethodInfo((MethodDoc) doc, dl);
}
TagletOutputImpl output = new TagletOutputImpl("");
TagletWriter.genTagOuput(configuration.tagletManager, doc,
configuration.tagletManager.getCustomTags(doc),
getTagletWriterInstance(false), output);
String outputString = output.toString().trim();
if (!outputString.isEmpty()) {
Content resultString = new RawHtml(outputString);
dl.addContent(resultString);
}
htmltree.addContent(dl);
}
/**
* Check whether there are any tags for Serialization Overview
* section to be printed.
*
* @param field the FieldDoc object to check for tags.
* @return true if there are tags to be printed else return false.
*/
protected boolean hasSerializationOverviewTags(FieldDoc field) {
TagletOutputImpl output = new TagletOutputImpl("");
TagletWriter.genTagOuput(configuration.tagletManager, field,
configuration.tagletManager.getCustomTags(field),
getTagletWriterInstance(false), output);
return (!output.toString().trim().isEmpty());
}
/**
* Returns a TagletWriter that knows how to write HTML.
*
* @return a TagletWriter that knows how to write HTML.
*/
public TagletWriter getTagletWriterInstance(boolean isFirstSentence) {
return new TagletWriterImpl(this, isFirstSentence);
}
/**
* Get Package link, with target frame.
*
* @param pd The link will be to the "package-summary.html" page for this package
* @param target name of the target frame
* @param label tag for the link
* @return a content for the target package link
*/
public Content getTargetPackageLink(PackageDoc pd, String target,
Content label) {
return getHyperLink(pathString(pd, DocPaths.PACKAGE_SUMMARY), label, "", target);
}
/**
* Get Profile Package link, with target frame.
*
* @param pd the packageDoc object
* @param target name of the target frame
* @param label tag for the link
* @param profileName the name of the profile being documented
* @return a content for the target profile packages link
*/
public Content getTargetProfilePackageLink(PackageDoc pd, String target,
Content label, String profileName) {
return getHyperLink(pathString(pd, DocPaths.profilePackageSummary(profileName)),
label, "", target);
}
/**
* Get Profile link, with target frame.
*
* @param target name of the target frame
* @param label tag for the link
* @param profileName the name of the profile being documented
* @return a content for the target profile link
*/
public Content getTargetProfileLink(String target, Content label,
String profileName) {
return getHyperLink(pathToRoot.resolve(
DocPaths.profileSummary(profileName)), label, "", target);
}
/**
* Get the type name for profile search.
*
* @param cd the classDoc object for which the type name conversion is needed
* @return a type name string for the type
*/
public String getTypeNameForProfile(ClassDoc cd) {
StringBuilder typeName =
new StringBuilder((cd.containingPackage()).name().replace(".", "/"));
typeName.append("/")
.append(cd.name().replace(".", "$"));
return typeName.toString();
}
/**
* Check if a type belongs to a profile.
*
* @param cd the classDoc object that needs to be checked
* @param profileValue the profile in which the type needs to be checked
* @return true if the type is in the profile
*/
public boolean isTypeInProfile(ClassDoc cd, int profileValue) {
return (configuration.profiles.getProfile(getTypeNameForProfile(cd)) <= profileValue);
}
public void addClassesSummary(ClassDoc[] classes, String label,
String tableSummary, String[] tableHeader, Content summaryContentTree,
int profileValue) {
if(classes.length > 0) {
Arrays.sort(classes);
Content caption = getTableCaption(label);
Content table = HtmlTree.TABLE(HtmlStyle.packageSummary, 0, 3, 0,
tableSummary, caption);
table.addContent(getSummaryTableHeader(tableHeader, "col"));
Content tbody = new HtmlTree(HtmlTag.TBODY);
for (int i = 0; i < classes.length; i++) {
if (!isTypeInProfile(classes[i], profileValue)) {
continue;
}
if (!Util.isCoreClass(classes[i]) ||
!configuration.isGeneratedDoc(classes[i])) {
continue;
}
Content classContent = new RawHtml(getLink(new LinkInfoImpl(
configuration, LinkInfoImpl.CONTEXT_PACKAGE, classes[i],
false)));
Content tdClass = HtmlTree.TD(HtmlStyle.colFirst, classContent);
HtmlTree tr = HtmlTree.TR(tdClass);
if (i%2 == 0)
tr.addStyle(HtmlStyle.altColor);
else
tr.addStyle(HtmlStyle.rowColor);
HtmlTree tdClassDescription = new HtmlTree(HtmlTag.TD);
tdClassDescription.addStyle(HtmlStyle.colLast);
if (Util.isDeprecated(classes[i])) {
tdClassDescription.addContent(deprecatedLabel);
if (classes[i].tags("deprecated").length > 0) {
addSummaryDeprecatedComment(classes[i],
classes[i].tags("deprecated")[0], tdClassDescription);
}
}
else
addSummaryComment(classes[i], tdClassDescription);
tr.addContent(tdClassDescription);
tbody.addContent(tr);
}
table.addContent(tbody);
Content li = HtmlTree.LI(HtmlStyle.blockList, table);
summaryContentTree.addContent(li);
}
}
/**
* Generates the HTML document tree and prints it out.
*
* @param metakeywords Array of String keywords for META tag. Each element
* of the array is assigned to a separate META tag.
* Pass in null for no array
* @param includeScript true if printing windowtitle script
* false for files that appear in the left-hand frames
* @param body the body htmltree to be included in the document
*/
public void printHtmlDocument(String[] metakeywords, boolean includeScript,
Content body) throws IOException {
Content htmlDocType = DocType.TRANSITIONAL;
Content htmlComment = new Comment(configuration.getText("doclet.New_Page"));
Content head = new HtmlTree(HtmlTag.HEAD);
if (!configuration.notimestamp) {
Content headComment = new Comment(getGeneratedByString());
head.addContent(headComment);
}
if (configuration.charset.length() > 0) {
Content meta = HtmlTree.META("Content-Type", "text/html",
configuration.charset);
head.addContent(meta);
}
head.addContent(getTitle());
if (!configuration.notimestamp) {
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
Content meta = HtmlTree.META("date", dateFormat.format(new Date()));
head.addContent(meta);
}
if (metakeywords != null) {
for (int i=0; i < metakeywords.length; i++) {
Content meta = HtmlTree.META("keywords", metakeywords[i]);
head.addContent(meta);
}
}
head.addContent(getStyleSheetProperties());
head.addContent(getScriptProperties());
Content htmlTree = HtmlTree.HTML(configuration.getLocale().getLanguage(),
head, body);
Content htmlDocument = new HtmlDocument(htmlDocType,
htmlComment, htmlTree);
write(htmlDocument);
}
/**
* Get the window title.
*
* @param title the title string to construct the complete window title
* @return the window title string
*/
public String getWindowTitle(String title) {
if (configuration.windowtitle.length() > 0) {
title += " (" + configuration.windowtitle + ")";
}
return title;
}
/**
* Get user specified header and the footer.
*
* @param header if true print the user provided header else print the
* user provided footer.
*/
public Content getUserHeaderFooter(boolean header) {
String content;
if (header) {
content = replaceDocRootDir(configuration.header);
} else {
if (configuration.footer.length() != 0) {
content = replaceDocRootDir(configuration.footer);
} else {
content = replaceDocRootDir(configuration.header);
}
}
Content rawContent = new RawHtml(content);
Content em = HtmlTree.EM(rawContent);
return em;
}
/**
* Adds the user specified top.
*
* @param body the content tree to which user specified top will be added
*/
public void addTop(Content body) {
Content top = new RawHtml(replaceDocRootDir(configuration.top));
body.addContent(top);
}
/**
* Adds the user specified bottom.
*
* @param body the content tree to which user specified bottom will be added
*/
public void addBottom(Content body) {
Content bottom = new RawHtml(replaceDocRootDir(configuration.bottom));
Content small = HtmlTree.SMALL(bottom);
Content p = HtmlTree.P(HtmlStyle.legalCopy, small);
body.addContent(p);
}
/**
* Adds the navigation bar for the Html page at the top and and the bottom.
*
* @param header If true print navigation bar at the top of the page else
* @param body the HtmlTree to which the nav links will be added
*/
protected void addNavLinks(boolean header, Content body) {
if (!configuration.nonavbar) {
String allClassesId = "allclasses_";
HtmlTree navDiv = new HtmlTree(HtmlTag.DIV);
if (header) {
body.addContent(HtmlConstants.START_OF_TOP_NAVBAR);
navDiv.addStyle(HtmlStyle.topNav);
allClassesId += "navbar_top";
Content a = getMarkerAnchor("navbar_top");
navDiv.addContent(a);
Content skipLinkContent = getHyperLink(DocLink.fragment("skip-navbar_top"),
HtmlTree.EMPTY,
configuration.getText("doclet.Skip_navigation_links"),
"");
navDiv.addContent(skipLinkContent);
} else {
body.addContent(HtmlConstants.START_OF_BOTTOM_NAVBAR);
navDiv.addStyle(HtmlStyle.bottomNav);
allClassesId += "navbar_bottom";
Content a = getMarkerAnchor("navbar_bottom");
navDiv.addContent(a);
Content skipLinkContent = getHyperLink(DocLink.fragment("skip-navbar_bottom"),
HtmlTree.EMPTY,
configuration.getText("doclet.Skip_navigation_links"),
"");
navDiv.addContent(skipLinkContent);
}
if (header) {
navDiv.addContent(getMarkerAnchor("navbar_top_firstrow"));
} else {
navDiv.addContent(getMarkerAnchor("navbar_bottom_firstrow"));
}
HtmlTree navList = new HtmlTree(HtmlTag.UL);
navList.addStyle(HtmlStyle.navList);
navList.addAttr(HtmlAttr.TITLE, "Navigation");
if (configuration.createoverview) {
navList.addContent(getNavLinkContents());
}
if (configuration.packages.length == 1) {
navList.addContent(getNavLinkPackage(configuration.packages[0]));
} else if (configuration.packages.length > 1) {
navList.addContent(getNavLinkPackage());
}
navList.addContent(getNavLinkClass());
if(configuration.classuse) {
navList.addContent(getNavLinkClassUse());
}
if(configuration.createtree) {
navList.addContent(getNavLinkTree());
}
if(!(configuration.nodeprecated ||
configuration.nodeprecatedlist)) {
navList.addContent(getNavLinkDeprecated());
}
if(configuration.createindex) {
navList.addContent(getNavLinkIndex());
}
if (!configuration.nohelp) {
navList.addContent(getNavLinkHelp());
}
navDiv.addContent(navList);
Content aboutDiv = HtmlTree.DIV(HtmlStyle.aboutLanguage, getUserHeaderFooter(header));
navDiv.addContent(aboutDiv);
body.addContent(navDiv);
Content ulNav = HtmlTree.UL(HtmlStyle.navList, getNavLinkPrevious());
ulNav.addContent(getNavLinkNext());
Content subDiv = HtmlTree.DIV(HtmlStyle.subNav, ulNav);
Content ulFrames = HtmlTree.UL(HtmlStyle.navList, getNavShowLists());
ulFrames.addContent(getNavHideLists(filename));
subDiv.addContent(ulFrames);
HtmlTree ulAllClasses = HtmlTree.UL(HtmlStyle.navList, getNavLinkClassIndex());
ulAllClasses.addAttr(HtmlAttr.ID, allClassesId.toString());
subDiv.addContent(ulAllClasses);
subDiv.addContent(getAllClassesLinkScript(allClassesId.toString()));
addSummaryDetailLinks(subDiv);
if (header) {
subDiv.addContent(getMarkerAnchor("skip-navbar_top"));
body.addContent(subDiv);
body.addContent(HtmlConstants.END_OF_TOP_NAVBAR);
} else {
subDiv.addContent(getMarkerAnchor("skip-navbar_bottom"));
body.addContent(subDiv);
body.addContent(HtmlConstants.END_OF_BOTTOM_NAVBAR);
}
}
}
/**
* Get the word "NEXT" to indicate that no link is available. Override
* this method to customize next link.
*
* @return a content tree for the link
*/
protected Content getNavLinkNext() {
return getNavLinkNext(null);
}
/**
* Get the word "PREV" to indicate that no link is available. Override
* this method to customize prev link.
*
* @return a content tree for the link
*/
protected Content getNavLinkPrevious() {
return getNavLinkPrevious(null);
}
/**
* Do nothing. This is the default method.
*/
protected void addSummaryDetailLinks(Content navDiv) {
}
/**
* Get link to the "overview-summary.html" page.
*
* @return a content tree for the link
*/
protected Content getNavLinkContents() {
Content linkContent = getHyperLink(pathToRoot.resolve(DocPaths.OVERVIEW_SUMMARY),
overviewLabel, "", "");
Content li = HtmlTree.LI(linkContent);
return li;
}
/**
* Get link to the "package-summary.html" page for the package passed.
*
* @param pkg Package to which link will be generated
* @return a content tree for the link
*/
protected Content getNavLinkPackage(PackageDoc pkg) {
Content linkContent = getPackageLink(pkg,
packageLabel);
Content li = HtmlTree.LI(linkContent);
return li;
}
/**
* Get the word "Package" , to indicate that link is not available here.
*
* @return a content tree for the link
*/
protected Content getNavLinkPackage() {
Content li = HtmlTree.LI(packageLabel);
return li;
}
/**
* Get the word "Use", to indicate that link is not available.
*
* @return a content tree for the link
*/
protected Content getNavLinkClassUse() {
Content li = HtmlTree.LI(useLabel);
return li;
}
/**
* Get link for previous file.
*
* @param prev File name for the prev link
* @return a content tree for the link
*/
public Content getNavLinkPrevious(DocPath prev) {
Content li;
if (prev != null) {
li = HtmlTree.LI(getHyperLink(prev, prevLabel, "", ""));
}
else
li = HtmlTree.LI(prevLabel);
return li;
}
/**
* Get link for next file. If next is null, just print the label
* without linking it anywhere.
*
* @param next File name for the next link
* @return a content tree for the link
*/
public Content getNavLinkNext(DocPath next) {
Content li;
if (next != null) {
li = HtmlTree.LI(getHyperLink(next, nextLabel, "", ""));
}
else
li = HtmlTree.LI(nextLabel);
return li;
}
/**
* Get "FRAMES" link, to switch to the frame version of the output.
*
* @param link File to be linked, "index.html"
* @return a content tree for the link
*/
protected Content getNavShowLists(DocPath link) {
DocLink dl = new DocLink(link, path.getPath(), null);
Content framesContent = getHyperLink(dl, framesLabel, "", "_top");
Content li = HtmlTree.LI(framesContent);
return li;
}
/**
* Get "FRAMES" link, to switch to the frame version of the output.
*
* @return a content tree for the link
*/
protected Content getNavShowLists() {
return getNavShowLists(pathToRoot.resolve(DocPaths.INDEX));
}
/**
* Get "NO FRAMES" link, to switch to the non-frame version of the output.
*
* @param link File to be linked
* @return a content tree for the link
*/
protected Content getNavHideLists(DocPath link) {
Content noFramesContent = getHyperLink(link, noframesLabel, "", "_top");
Content li = HtmlTree.LI(noFramesContent);
return li;
}
/**
* Get "Tree" link in the navigation bar. If there is only one package
* specified on the command line, then the "Tree" link will be to the
* only "package-tree.html" file otherwise it will be to the
* "overview-tree.html" file.
*
* @return a content tree for the link
*/
protected Content getNavLinkTree() {
Content treeLinkContent;
PackageDoc[] packages = configuration.root.specifiedPackages();
if (packages.length == 1 && configuration.root.specifiedClasses().length == 0) {
treeLinkContent = getHyperLink(pathString(packages[0],
DocPaths.PACKAGE_TREE), treeLabel,
"", "");
} else {
treeLinkContent = getHyperLink(pathToRoot.resolve(DocPaths.OVERVIEW_TREE),
treeLabel, "", "");
}
Content li = HtmlTree.LI(treeLinkContent);
return li;
}
/**
* Get the overview tree link for the main tree.
*
* @param label the label for the link
* @return a content tree for the link
*/
protected Content getNavLinkMainTree(String label) {
Content mainTreeContent = getHyperLink(pathToRoot.resolve(DocPaths.OVERVIEW_TREE),
new StringContent(label));
Content li = HtmlTree.LI(mainTreeContent);
return li;
}
/**
* Get the word "Class", to indicate that class link is not available.
*
* @return a content tree for the link
*/
protected Content getNavLinkClass() {
Content li = HtmlTree.LI(classLabel);
return li;
}
/**
* Get "Deprecated" API link in the navigation bar.
*
* @return a content tree for the link
*/
protected Content getNavLinkDeprecated() {
Content linkContent = getHyperLink(pathToRoot.resolve(DocPaths.DEPRECATED_LIST),
deprecatedLabel, "", "");
Content li = HtmlTree.LI(linkContent);
return li;
}
/**
* Get link for generated index. If the user has used "-splitindex"
* command line option, then link to file "index-files/index-1.html" is
* generated otherwise link to file "index-all.html" is generated.
*
* @return a content tree for the link
*/
protected Content getNavLinkClassIndex() {
Content allClassesContent = getHyperLink(pathToRoot.resolve(
DocPaths.ALLCLASSES_NOFRAME),
allclassesLabel, "", "");
Content li = HtmlTree.LI(allClassesContent);
return li;
}
/**
* Get link for generated class index.
*
* @return a content tree for the link
*/
protected Content getNavLinkIndex() {
Content linkContent = getHyperLink(pathToRoot.resolve(
(configuration.splitindex
? DocPaths.INDEX_FILES.resolve(DocPaths.indexN(1))
: DocPaths.INDEX_ALL)),
indexLabel, "", "");
Content li = HtmlTree.LI(linkContent);
return li;
}
/**
* Get help file link. If user has provided a help file, then generate a
* link to the user given file, which is already copied to current or
* destination directory.
*
* @return a content tree for the link
*/
protected Content getNavLinkHelp() {
String helpfile = configuration.helpfile;
DocPath helpfilenm;
if (helpfile.isEmpty()) {
helpfilenm = DocPaths.HELP_DOC;
} else {
DocFile file = DocFile.createFileForInput(configuration, helpfile);
helpfilenm = DocPath.create(file.getName());
}
Content linkContent = getHyperLink(pathToRoot.resolve(helpfilenm),
helpLabel, "", "");
Content li = HtmlTree.LI(linkContent);
return li;
}
/**
* Get summary table header.
*
* @param header the header for the table
* @param scope the scope of the headers
* @return a content tree for the header
*/
public Content getSummaryTableHeader(String[] header, String scope) {
Content tr = new HtmlTree(HtmlTag.TR);
int size = header.length;
Content tableHeader;
if (size == 1) {
tableHeader = new StringContent(header[0]);
tr.addContent(HtmlTree.TH(HtmlStyle.colOne, scope, tableHeader));
return tr;
}
for (int i = 0; i < size; i++) {
tableHeader = new StringContent(header[i]);
if(i == 0)
tr.addContent(HtmlTree.TH(HtmlStyle.colFirst, scope, tableHeader));
else if(i == (size - 1))
tr.addContent(HtmlTree.TH(HtmlStyle.colLast, scope, tableHeader));
else
tr.addContent(HtmlTree.TH(scope, tableHeader));
}
return tr;
}
/**
* Get table caption.
*
* @param rawText the caption for the table which could be raw Html
* @return a content tree for the caption
*/
public Content getTableCaption(String rawText) {
Content title = new RawHtml(rawText);
Content captionSpan = HtmlTree.SPAN(title);
Content space = getSpace();
Content tabSpan = HtmlTree.SPAN(HtmlStyle.tabEnd, space);
Content caption = HtmlTree.CAPTION(captionSpan);
caption.addContent(tabSpan);
return caption;
}
/**
* Get the marker anchor which will be added to the documentation tree.
*
* @param anchorName the anchor name attribute
* @return a content tree for the marker anchor
*/
public Content getMarkerAnchor(String anchorName) {
return getMarkerAnchor(anchorName, null);
}
/**
* Get the marker anchor which will be added to the documentation tree.
*
* @param anchorName the anchor name attribute
* @param anchorContent the content that should be added to the anchor
* @return a content tree for the marker anchor
*/
public Content getMarkerAnchor(String anchorName, Content anchorContent) {
if (anchorContent == null)
anchorContent = new Comment(" ");
Content markerAnchor = HtmlTree.A_NAME(anchorName, anchorContent);
return markerAnchor;
}
/**
* Returns a packagename content.
*
* @param packageDoc the package to check
* @return package name content
*/
public Content getPackageName(PackageDoc packageDoc) {
return packageDoc == null || packageDoc.name().length() == 0 ?
defaultPackageLabel :
getPackageLabel(packageDoc.name());
}
/**
* Returns a package name label.
*
* @param packageName the package name
* @return the package name content
*/
public Content getPackageLabel(String packageName) {
return new StringContent(packageName);
}
/**
* Add package deprecation information to the documentation tree
*
* @param deprPkgs list of deprecated packages
* @param headingKey the caption for the deprecated package table
* @param tableSummary the summary for the deprecated package table
* @param tableHeader table headers for the deprecated package table
* @param contentTree the content tree to which the deprecated package table will be added
*/
protected void addPackageDeprecatedAPI(List
* Here is the algorithm used to fix the link:
*
* {@literal
* For example, suppose com.sun.javadoc.RootDoc has this link:
* {@literal The package Page }
*
* If this link appeared in the index, we would redirect
* the link like this:
*
* {@literal The package Page}
*
* @param doc the Doc object whose documentation is being written.
* @param text the text being written.
*
* @return the text, with all the relative links redirected to work.
*/
private String redirectRelativeLinks(Doc doc, String text) {
if (doc == null || shouldNotRedirectRelativeLinks()) {
return text;
}
DocPath redirectPathFromRoot;
if (doc instanceof ClassDoc) {
redirectPathFromRoot = DocPath.forPackage(((ClassDoc) doc).containingPackage());
} else if (doc instanceof MemberDoc) {
redirectPathFromRoot = DocPath.forPackage(((MemberDoc) doc).containingPackage());
} else if (doc instanceof PackageDoc) {
redirectPathFromRoot = DocPath.forPackage((PackageDoc) doc);
} else {
return text;
}
//Redirect all relative links.
int end, begin = text.toLowerCase().indexOf("= 0){
StringBuilder textBuff = new StringBuilder(text);
while(begin >=0){
if (textBuff.length() > begin + 2 && ! Character.isWhitespace(textBuff.charAt(begin+2))) {
begin = textBuff.toString().toLowerCase().indexOf("", begin +1);
if(begin == 0){
//Link has no equal symbol.
configuration.root.printWarning(
doc.position(),
configuration.getText("doclet.malformed_html_link_tag", text));
break;
}
if (end == -1) {
//Break without warning. This tag is not necessarily malformed. The text
//might be missing '>' character because the href has an inline tag.
break;
}
if (textBuff.substring(begin, end).indexOf("\"") != -1){
begin = textBuff.indexOf("\"", begin) + 1;
end = textBuff.indexOf("\"", begin +1);
if (begin == 0 || end == -1){
//Link is missing a quote.
break;
}
}
String relativeLink = textBuff.substring(begin, end);
if (!(relativeLink.toLowerCase().startsWith("mailto:") ||
relativeLink.toLowerCase().startsWith("http:") ||
relativeLink.toLowerCase().startsWith("https:") ||
relativeLink.toLowerCase().startsWith("file:"))) {
relativeLink = "{@"+(new DocRootTaglet()).getName() + "}/"
+ redirectPathFromRoot.resolve(relativeLink).getPath();
textBuff.replace(begin, end, relativeLink);
}
begin = textBuff.toString().toLowerCase().indexOf("", "", " ", " ", "", "
",
"", "
", "", "
",
"", " ", "", " ",
"", " ", "", "
", "", "
",
"", "
", "", "
",
"", "
", "", "
",
"", "
", "",
"
",
"", "
",
"", "
", "", "
",
"", "
", "", "
",
"", " ", "", " ",
"", " ", "", "
", "", "
",
"", "
", "", "
",
"", "
", "", "
",
"", "
", "",
"
",
"", "
",
"