| /* |
| * Copyright 1998-2008 Sun Microsystems, Inc. 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. Sun designates this |
| * particular file as subject to the "Classpath" exception as provided |
| * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, |
| * CA 95054 USA or visit www.sun.com if you need additional information or |
| * have any questions. |
| */ |
| |
| package com.sun.tools.doclets.formats.html; |
| import com.sun.tools.doclets.formats.html.markup.*; |
| |
| import com.sun.tools.doclets.internal.toolkit.*; |
| import com.sun.tools.doclets.internal.toolkit.util.*; |
| import com.sun.tools.doclets.internal.toolkit.taglets.*; |
| |
| import com.sun.javadoc.*; |
| import java.io.*; |
| import java.text.SimpleDateFormat; |
| import java.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. |
| * |
| * @since 1.2 |
| * @author Atul M Dambalkar |
| * @author Robert Field |
| */ |
| 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 relative path string is "../../". |
| * This string can be empty if the file getting generated is in |
| * the destination directory. |
| */ |
| public String relativePath = ""; |
| |
| /** |
| * Same as relativepath, but normalized to never be empty or |
| * end with a slash. |
| */ |
| public String relativepathNoSlash = ""; |
| |
| /** |
| * Platform-dependent directory path from the current or the |
| * destination directory to the file getting generated. |
| * Used when creating the file. |
| * For example, if the file getting generated is |
| * "java/lang/Object.html", then the path string is "java/lang". |
| */ |
| public String path = ""; |
| |
| /** |
| * Name of the file getting generated. If the file getting generated is |
| * "java/lang/Object.html", then the filename is "Object.html". |
| */ |
| public String filename = ""; |
| |
| /** |
| * The display length used for indentation while generating the class page. |
| */ |
| public int displayLength = 0; |
| |
| /** |
| * The global configuration information for this run. |
| */ |
| public ConfigurationImpl configuration; |
| |
| /** |
| * Constructor to construct the HtmlStandardWriter object. |
| * |
| * @param filename File to be generated. |
| */ |
| public HtmlDocletWriter(ConfigurationImpl configuration, |
| String filename) throws IOException { |
| super(configuration, filename); |
| this.configuration = configuration; |
| this.filename = filename; |
| } |
| |
| /** |
| * Constructor to construct the HtmlStandardWriter object. |
| * |
| * @param path Platform-dependent {@link #path} used when |
| * creating file. |
| * @param filename Name of file to be generated. |
| * @param relativePath Value for the variable {@link #relativePath}. |
| */ |
| public HtmlDocletWriter(ConfigurationImpl configuration, |
| String path, String filename, |
| String relativePath) throws IOException { |
| super(configuration, path, filename); |
| this.configuration = configuration; |
| this.path = path; |
| this.relativePath = relativePath; |
| this.relativepathNoSlash = |
| DirectoryManager.getPathNoTrailingSlash(this.relativePath); |
| this.filename = filename; |
| } |
| |
| /** |
| * 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.) |
| * <p> |
| * 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. |
| * <p> |
| * 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). |
| * <p> |
| * Note: This doc comment was written with '&#064;' 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; |
| } |
| StringBuffer buf = new StringBuffer(); |
| int previndex = 0; |
| while (true) { |
| // 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 + 10; // length for {@docroot} string |
| // Insert relative path where {@docRoot} was located |
| buf.append(relativepathNoSlash); |
| // Append slash if next character is not a slash |
| if (relativepathNoSlash.length() > 0 && previndex < htmlstr.length() |
| && htmlstr.charAt(previndex) != '/') { |
| buf.append(DirectoryManager.URL_FILE_SEPERATOR); |
| } |
| } |
| return buf.toString(); |
| } |
| |
| /** |
| * Print Html Hyper Link, with target frame. This |
| * link will only appear if page is not in a frame. |
| * |
| * @param link String name of the file. |
| * @param where Position in the file |
| * @param target Name of the target frame. |
| * @param label Tag for the link. |
| * @param bold Whether the label should be bold or not? |
| */ |
| public void printNoFramesTargetHyperLink(String link, String where, |
| String target, String label, |
| boolean bold) { |
| script(); |
| println(" <!--"); |
| println(" if(window==top) {"); |
| println(" document.writeln('" |
| + getHyperLink(link, where, label, bold, "", "", target) + "');"); |
| println(" }"); |
| println(" //-->"); |
| scriptEnd(); |
| noScript(); |
| println(" " + getHyperLink(link, where, label, bold, "", "", target)); |
| noScriptEnd(); |
| println(DocletConstants.NL); |
| } |
| |
| private void printMethodInfo(MethodDoc method) { |
| ClassDoc[] intfacs = method.containingClass().interfaces(); |
| MethodDoc overriddenMethod = method.overriddenMethod(); |
| if (intfacs.length > 0 || overriddenMethod != null) { |
| dd(); |
| printTagsInfoHeader(); |
| MethodWriterImpl.printImplementsInfo(this, method); |
| if (overriddenMethod != null) { |
| MethodWriterImpl.printOverridden(this, |
| method.overriddenType(), overriddenMethod); |
| } |
| printTagsInfoFooter(); |
| ddEnd(); |
| } |
| dd(); |
| } |
| |
| protected void printTags(Doc doc) { |
| if(configuration.nocomment){ |
| return; |
| } |
| if (doc instanceof MethodDoc) { |
| printMethodInfo((MethodDoc) doc); |
| } |
| TagletOutputImpl output = new TagletOutputImpl(""); |
| TagletWriter.genTagOuput(configuration.tagletManager, doc, |
| configuration.tagletManager.getCustomTags(doc), |
| getTagletWriterInstance(false), output); |
| if (output.toString().trim().length() > 0) { |
| printTagsInfoHeader(); |
| print(output.toString()); |
| printTagsInfoFooter(); |
| } else if (! (doc instanceof ConstructorDoc || |
| doc instanceof RootDoc || doc instanceof ClassDoc)) { |
| //To be consistent with 1.4.2 output. |
| //I hate to do this but we have to pass the diff test to prove |
| //nothing has broken. |
| printTagsInfoHeader(); |
| printTagsInfoFooter(); |
| } |
| } |
| |
| /** |
| * 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); |
| } |
| |
| protected void printTagsInfoHeader() { |
| dl(); |
| } |
| |
| protected void printTagsInfoFooter() { |
| dlEnd(); |
| } |
| |
| /** |
| * Print 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. |
| */ |
| public void printTargetPackageLink(PackageDoc pd, String target, |
| String label) { |
| print(getHyperLink(pathString(pd, "package-summary.html"), "", label, |
| false, "", "", target)); |
| } |
| |
| /** |
| * Print the html file header. Also print Html page title and stylesheet |
| * default properties. |
| * |
| * @param title String window title to go in the <TITLE> tag |
| * @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 boolean true if printing windowtitle script. |
| * False for files that appear in the left-hand frames. |
| */ |
| public void printHtmlHeader(String title, String[] metakeywords, |
| boolean includeScript) { |
| println("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 " + |
| "Transitional//EN\" " + |
| "\"http://www.w3.org/TR/html4/loose.dtd\">"); |
| println("<!--NewPage-->"); |
| html(); |
| head(); |
| if (! configuration.notimestamp) { |
| print("<!-- Generated by javadoc (build " + ConfigurationImpl.BUILD_DATE + ") on "); |
| print(today()); |
| println(" -->"); |
| } |
| if (configuration.charset.length() > 0) { |
| println("<META http-equiv=\"Content-Type\" content=\"text/html; " |
| + "charset=" + configuration.charset + "\">"); |
| } |
| if ( configuration.windowtitle.length() > 0 ) { |
| title += " (" + configuration.windowtitle + ")"; |
| } |
| title(title); |
| println(title); |
| titleEnd(); |
| println(""); |
| if (! configuration.notimestamp) { |
| SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd"); |
| println("<META NAME=\"date\" " |
| + "CONTENT=\"" + dateFormat.format(new Date()) + "\">"); |
| } |
| if ( metakeywords != null ) { |
| for ( int i=0; i < metakeywords.length; i++ ) { |
| println("<META NAME=\"keywords\" " |
| + "CONTENT=\"" + metakeywords[i] + "\">"); |
| } |
| } |
| println(""); |
| printStyleSheetProperties(); |
| println(""); |
| // Don't print windowtitle script for overview-frame, allclasses-frame |
| // and package-frame |
| if (includeScript) { |
| printWinTitleScript(title); |
| } |
| println(""); |
| headEnd(); |
| println(""); |
| body("white", includeScript); |
| } |
| |
| /** |
| * Print user specified header and the footer. |
| * |
| * @param header if true print the user provided header else print the |
| * user provided footer. |
| */ |
| public void printUserHeaderFooter(boolean header) { |
| em(); |
| if (header) { |
| print(replaceDocRootDir(configuration.header)); |
| } else { |
| if (configuration.footer.length() != 0) { |
| print(replaceDocRootDir(configuration.footer)); |
| } else { |
| print(replaceDocRootDir(configuration.header)); |
| } |
| } |
| emEnd(); |
| } |
| |
| /** |
| * Print the user specified top. |
| */ |
| public void printTop() { |
| print(replaceDocRootDir(configuration.top)); |
| hr(); |
| } |
| |
| /** |
| * Print the user specified bottom. |
| */ |
| public void printBottom() { |
| hr(); |
| print(replaceDocRootDir(configuration.bottom)); |
| } |
| |
| /** |
| * Print 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 |
| * print the nevigation bar at the bottom. |
| */ |
| protected void navLinks(boolean header) { |
| println(""); |
| if (!configuration.nonavbar) { |
| if (header) { |
| println(DocletConstants.NL + "<!-- ========= START OF TOP NAVBAR ======= -->"); |
| anchor("navbar_top"); |
| println(); |
| print(getHyperLink("", "skip-navbar_top", "", false, "", |
| configuration.getText("doclet.Skip_navigation_links"), "")); |
| } else { |
| println(DocletConstants.NL + "<!-- ======= START OF BOTTOM NAVBAR ====== -->"); |
| anchor("navbar_bottom"); |
| println(); |
| print(getHyperLink("", "skip-navbar_bottom", "", false, "", |
| configuration.getText("doclet.Skip_navigation_links"), "")); |
| } |
| table(0, "100%", 1, 0); |
| tr(); |
| tdColspanBgcolorStyle(2, "#EEEEFF", "NavBarCell1"); |
| println(""); |
| if (header) { |
| anchor("navbar_top_firstrow"); |
| } else { |
| anchor("navbar_bottom_firstrow"); |
| } |
| table(0, 0, 3); |
| print(" "); |
| trAlignVAlign("center", "top"); |
| |
| if (configuration.createoverview) { |
| navLinkContents(); |
| } |
| |
| if (configuration.packages.length == 1) { |
| navLinkPackage(configuration.packages[0]); |
| } else if (configuration.packages.length > 1) { |
| navLinkPackage(); |
| } |
| |
| navLinkClass(); |
| |
| if(configuration.classuse) { |
| navLinkClassUse(); |
| } |
| if(configuration.createtree) { |
| navLinkTree(); |
| } |
| if(!(configuration.nodeprecated || |
| configuration.nodeprecatedlist)) { |
| navLinkDeprecated(); |
| } |
| if(configuration.createindex) { |
| navLinkIndex(); |
| } |
| if (!configuration.nohelp) { |
| navLinkHelp(); |
| } |
| print(" "); |
| trEnd(); |
| tableEnd(); |
| tdEnd(); |
| |
| tdAlignVAlignRowspan("right", "top", 3); |
| |
| printUserHeaderFooter(header); |
| tdEnd(); |
| trEnd(); |
| println(""); |
| |
| tr(); |
| tdBgcolorStyle("white", "NavBarCell2"); |
| font("-2"); |
| space(); |
| navLinkPrevious(); |
| space(); |
| println(""); |
| space(); |
| navLinkNext(); |
| fontEnd(); |
| tdEnd(); |
| |
| tdBgcolorStyle("white", "NavBarCell2"); |
| font("-2"); |
| print(" "); |
| navShowLists(); |
| print(" "); |
| space(); |
| println(""); |
| space(); |
| navHideLists(filename); |
| print(" "); |
| space(); |
| println(""); |
| space(); |
| navLinkClassIndex(); |
| fontEnd(); |
| tdEnd(); |
| |
| trEnd(); |
| |
| printSummaryDetailLinks(); |
| |
| tableEnd(); |
| if (header) { |
| aName("skip-navbar_top"); |
| aEnd(); |
| println(DocletConstants.NL + "<!-- ========= END OF TOP NAVBAR ========= -->"); |
| } else { |
| aName("skip-navbar_bottom"); |
| aEnd(); |
| println(DocletConstants.NL + "<!-- ======== END OF BOTTOM NAVBAR ======= -->"); |
| } |
| println(""); |
| } |
| } |
| |
| /** |
| * Print the word "NEXT" to indicate that no link is available. Override |
| * this method to customize next link. |
| */ |
| protected void navLinkNext() { |
| navLinkNext(null); |
| } |
| |
| /** |
| * Print the word "PREV" to indicate that no link is available. Override |
| * this method to customize prev link. |
| */ |
| protected void navLinkPrevious() { |
| navLinkPrevious(null); |
| } |
| |
| /** |
| * Do nothing. This is the default method. |
| */ |
| protected void printSummaryDetailLinks() { |
| } |
| |
| /** |
| * Print link to the "overview-summary.html" page. |
| */ |
| protected void navLinkContents() { |
| navCellStart(); |
| printHyperLink(relativePath + "overview-summary.html", "", |
| configuration.getText("doclet.Overview"), true, "NavBarFont1"); |
| navCellEnd(); |
| } |
| |
| /** |
| * Description for a cell in the navigation bar. |
| */ |
| protected void navCellStart() { |
| print(" "); |
| tdBgcolorStyle("#EEEEFF", "NavBarCell1"); |
| print(" "); |
| } |
| |
| /** |
| * Description for a cell in the navigation bar, but with reverse |
| * high-light effect. |
| */ |
| protected void navCellRevStart() { |
| print(" "); |
| tdBgcolorStyle("#FFFFFF", "NavBarCell1Rev"); |
| print(" "); |
| space(); |
| } |
| |
| /** |
| * Closing tag for navigation bar cell. |
| */ |
| protected void navCellEnd() { |
| space(); |
| tdEnd(); |
| } |
| |
| /** |
| * Print link to the "package-summary.html" page for the package passed. |
| * |
| * @param pkg Package to which link will be generated. |
| */ |
| protected void navLinkPackage(PackageDoc pkg) { |
| navCellStart(); |
| printPackageLink(pkg, configuration.getText("doclet.Package"), true, |
| "NavBarFont1"); |
| navCellEnd(); |
| } |
| |
| /** |
| * Print the word "Package" in the navigation bar cell, to indicate that |
| * link is not available here. |
| */ |
| protected void navLinkPackage() { |
| navCellStart(); |
| fontStyle("NavBarFont1"); |
| printText("doclet.Package"); |
| fontEnd(); |
| navCellEnd(); |
| } |
| |
| /** |
| * Print the word "Use" in the navigation bar cell, to indicate that link |
| * is not available. |
| */ |
| protected void navLinkClassUse() { |
| navCellStart(); |
| fontStyle("NavBarFont1"); |
| printText("doclet.navClassUse"); |
| fontEnd(); |
| navCellEnd(); |
| } |
| |
| /** |
| * Print link for previous file. |
| * |
| * @param prev File name for the prev link. |
| */ |
| public void navLinkPrevious(String prev) { |
| String tag = configuration.getText("doclet.Prev"); |
| if (prev != null) { |
| printHyperLink(prev, "", tag, true) ; |
| } else { |
| print(tag); |
| } |
| } |
| |
| /** |
| * Print link for next file. If next is null, just print the label |
| * without linking it anywhere. |
| * |
| * @param next File name for the next link. |
| */ |
| public void navLinkNext(String next) { |
| String tag = configuration.getText("doclet.Next"); |
| if (next != null) { |
| printHyperLink(next, "", tag, true); |
| } else { |
| print(tag); |
| } |
| } |
| |
| /** |
| * Print "FRAMES" link, to switch to the frame version of the output. |
| * |
| * @param link File to be linked, "index.html". |
| */ |
| protected void navShowLists(String link) { |
| print(getHyperLink(link + "?" + path + filename, "", |
| configuration.getText("doclet.FRAMES"), true, "", "", "_top")); |
| } |
| |
| /** |
| * Print "FRAMES" link, to switch to the frame version of the output. |
| */ |
| protected void navShowLists() { |
| navShowLists(relativePath + "index.html"); |
| } |
| |
| /** |
| * Print "NO FRAMES" link, to switch to the non-frame version of the output. |
| * |
| * @param link File to be linked. |
| */ |
| protected void navHideLists(String link) { |
| print(getHyperLink(link, "", configuration.getText("doclet.NO_FRAMES"), |
| true, "", "", "_top")); |
| } |
| |
| /** |
| * Print "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. |
| */ |
| protected void navLinkTree() { |
| navCellStart(); |
| PackageDoc[] packages = configuration.root.specifiedPackages(); |
| if (packages.length == 1 && configuration.root.specifiedClasses().length == 0) { |
| printHyperLink(pathString(packages[0], "package-tree.html"), "", |
| configuration.getText("doclet.Tree"), true, "NavBarFont1"); |
| } else { |
| printHyperLink(relativePath + "overview-tree.html", "", |
| configuration.getText("doclet.Tree"), true, "NavBarFont1"); |
| } |
| navCellEnd(); |
| } |
| |
| /** |
| * Print "Tree" link to the "overview-tree.html" file. |
| */ |
| protected void navLinkMainTree(String label) { |
| printHyperLink(relativePath + "overview-tree.html", label); |
| } |
| |
| /** |
| * Print the word "Class" in the navigation bar cell, to indicate that |
| * class link is not available. |
| */ |
| protected void navLinkClass() { |
| navCellStart(); |
| fontStyle("NavBarFont1"); |
| printText("doclet.Class"); |
| fontEnd(); |
| navCellEnd(); |
| } |
| |
| /** |
| * Print "Deprecated" API link in the navigation bar. |
| */ |
| protected void navLinkDeprecated() { |
| navCellStart(); |
| printHyperLink(relativePath + "deprecated-list.html", "", |
| configuration.getText("doclet.navDeprecated"), true, "NavBarFont1"); |
| navCellEnd(); |
| } |
| |
| /** |
| * Print 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. |
| */ |
| protected void navLinkClassIndex() { |
| printNoFramesTargetHyperLink(relativePath + |
| AllClassesFrameWriter.OUTPUT_FILE_NAME_NOFRAMES, |
| "", "", configuration.getText("doclet.All_Classes"), true); |
| } |
| /** |
| * Print link for generated class index. |
| */ |
| protected void navLinkIndex() { |
| navCellStart(); |
| printHyperLink(relativePath + |
| (configuration.splitindex? |
| DirectoryManager.getPath("index-files") + |
| fileseparator: "") + |
| (configuration.splitindex? |
| "index-1.html" : "index-all.html"), "", |
| configuration.getText("doclet.Index"), true, "NavBarFont1"); |
| navCellEnd(); |
| } |
| |
| /** |
| * Print 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. |
| */ |
| protected void navLinkHelp() { |
| String helpfilenm = configuration.helpfile; |
| if (helpfilenm.equals("")) { |
| helpfilenm = "help-doc.html"; |
| } else { |
| int lastsep; |
| if ((lastsep = helpfilenm.lastIndexOf(File.separatorChar)) != -1) { |
| helpfilenm = helpfilenm.substring(lastsep + 1); |
| } |
| } |
| navCellStart(); |
| printHyperLink(relativePath + helpfilenm, "", |
| configuration.getText("doclet.Help"), true, "NavBarFont1"); |
| navCellEnd(); |
| } |
| |
| /** |
| * Print the word "Detail" in the navigation bar. No link is available. |
| */ |
| protected void navDetail() { |
| printText("doclet.Detail"); |
| } |
| |
| /** |
| * Print the word "Summary" in the navigation bar. No link is available. |
| */ |
| protected void navSummary() { |
| printText("doclet.Summary"); |
| } |
| |
| /** |
| * Print the Html table tag for the index summary tables. The table tag |
| * printed is |
| * <TABLE BORDER="1" CELLPADDING="3" CELLSPACING="0" WIDTH="100%"> |
| */ |
| public void tableIndexSummary() { |
| table(1, "100%", 3, 0); |
| } |
| |
| /** |
| * Same as {@link #tableIndexSummary()}. |
| */ |
| public void tableIndexDetail() { |
| table(1, "100%", 3, 0); |
| } |
| |
| /** |
| * Print Html tag for table elements. The tag printed is |
| * <TD ALIGN="right" VALIGN="top" WIDTH="1%">. |
| */ |
| public void tdIndex() { |
| print("<TD ALIGN=\"right\" VALIGN=\"top\" WIDTH=\"1%\">"); |
| } |
| |
| /** |
| * Prine table header information about color, column span and the font. |
| * |
| * @param color Background color. |
| * @param span Column span. |
| */ |
| public void tableHeaderStart(String color, int span) { |
| trBgcolorStyle(color, "TableHeadingColor"); |
| thAlignColspan("left", span); |
| font("+2"); |
| } |
| |
| /** |
| * Print table header for the inherited members summary tables. Print the |
| * background color information. |
| * |
| * @param color Background color. |
| */ |
| public void tableInheritedHeaderStart(String color) { |
| trBgcolorStyle(color, "TableSubHeadingColor"); |
| thAlign("left"); |
| } |
| |
| /** |
| * Print "Use" table header. Print the background color and the column span. |
| * |
| * @param color Background color. |
| */ |
| public void tableUseInfoHeaderStart(String color) { |
| trBgcolorStyle(color, "TableSubHeadingColor"); |
| thAlignColspan("left", 2); |
| } |
| |
| /** |
| * Print table header with the background color with default column span 2. |
| * |
| * @param color Background color. |
| */ |
| public void tableHeaderStart(String color) { |
| tableHeaderStart(color, 2); |
| } |
| |
| /** |
| * Print table header with the column span, with the default color #CCCCFF. |
| * |
| * @param span Column span. |
| */ |
| public void tableHeaderStart(int span) { |
| tableHeaderStart("#CCCCFF", span); |
| } |
| |
| /** |
| * Print table header with default column span 2 and default color #CCCCFF. |
| */ |
| public void tableHeaderStart() { |
| tableHeaderStart(2); |
| } |
| |
| /** |
| * Print table header end tags for font, column and row. |
| */ |
| public void tableHeaderEnd() { |
| fontEnd(); |
| thEnd(); |
| trEnd(); |
| } |
| |
| /** |
| * Print table header end tags in inherited tables for column and row. |
| */ |
| public void tableInheritedHeaderEnd() { |
| thEnd(); |
| trEnd(); |
| } |
| |
| /** |
| * Print the summary table row cell attribute width. |
| * |
| * @param width Width of the table cell. |
| */ |
| public void summaryRow(int width) { |
| if (width != 0) { |
| tdWidth(width + "%"); |
| } else { |
| td(); |
| } |
| } |
| |
| /** |
| * Print the summary table row cell end tag. |
| */ |
| public void summaryRowEnd() { |
| tdEnd(); |
| } |
| |
| /** |
| * Print the heading in Html <H2> format. |
| * |
| * @param str The Header string. |
| */ |
| public void printIndexHeading(String str) { |
| h2(); |
| print(str); |
| h2End(); |
| } |
| |
| /** |
| * Print Html tag <FRAMESET=arg>. |
| * |
| * @param arg Argument for the tag. |
| */ |
| public void frameSet(String arg) { |
| println("<FRAMESET " + arg + ">"); |
| } |
| |
| /** |
| * Print Html closing tag </FRAMESET>. |
| */ |
| public void frameSetEnd() { |
| println("</FRAMESET>"); |
| } |
| |
| /** |
| * Print Html tag <FRAME=arg>. |
| * |
| * @param arg Argument for the tag. |
| */ |
| public void frame(String arg) { |
| println("<FRAME " + arg + ">"); |
| } |
| |
| /** |
| * Print Html closing tag </FRAME>. |
| */ |
| public void frameEnd() { |
| println("</FRAME>"); |
| } |
| |
| /** |
| * Return path to the class page for a classdoc. For example, the class |
| * name is "java.lang.Object" and if the current file getting generated is |
| * "java/io/File.html", then the path string to the class, returned is |
| * "../../java/lang.Object.html". |
| * |
| * @param cd Class to which the path is requested. |
| */ |
| protected String pathToClass(ClassDoc cd) { |
| return pathString(cd.containingPackage(), cd.name() + ".html"); |
| } |
| |
| /** |
| * Return the path to the class page for a classdoc. Works same as |
| * {@link #pathToClass(ClassDoc)}. |
| * |
| * @param cd Class to which the path is requested. |
| * @param name Name of the file(doesn't include path). |
| */ |
| protected String pathString(ClassDoc cd, String name) { |
| return pathString(cd.containingPackage(), name); |
| } |
| |
| /** |
| * Return path to the given file name in the given package. So if the name |
| * passed is "Object.html" and the name of the package is "java.lang", and |
| * if the relative path is "../.." then returned string will be |
| * "../../java/lang/Object.html" |
| * |
| * @param pd Package in which the file name is assumed to be. |
| * @param name File name, to which path string is. |
| */ |
| protected String pathString(PackageDoc pd, String name) { |
| StringBuffer buf = new StringBuffer(relativePath); |
| buf.append(DirectoryManager.getPathToPackage(pd, name)); |
| return buf.toString(); |
| } |
| |
| /** |
| * Print the link to the given package. |
| * |
| * @param pkg the package to link to. |
| * @param label the label for the link. |
| * @param isBold true if the label should be bold. |
| */ |
| public void printPackageLink(PackageDoc pkg, String label, boolean isBold) { |
| print(getPackageLink(pkg, label, isBold)); |
| } |
| |
| /** |
| * Print the link to the given package. |
| * |
| * @param pkg the package to link to. |
| * @param label the label for the link. |
| * @param isBold true if the label should be bold. |
| * @param style the font of the package link label. |
| */ |
| public void printPackageLink(PackageDoc pkg, String label, boolean isBold, |
| String style) { |
| print(getPackageLink(pkg, label, isBold, style)); |
| } |
| |
| /** |
| * Return the link to the given package. |
| * |
| * @param pkg the package to link to. |
| * @param label the label for the link. |
| * @param isBold true if the label should be bold. |
| * @return the link to the given package. |
| */ |
| public String getPackageLink(PackageDoc pkg, String label, |
| boolean isBold) { |
| return getPackageLink(pkg, label, isBold, ""); |
| } |
| |
| /** |
| * Return the link to the given package. |
| * |
| * @param pkg the package to link to. |
| * @param label the label for the link. |
| * @param isBold true if the label should be bold. |
| * @param style the font of the package link label. |
| * @return the link to the given package. |
| */ |
| public String getPackageLink(PackageDoc pkg, String label, boolean isBold, |
| String style) { |
| boolean included = pkg != null && pkg.isIncluded(); |
| if (! included) { |
| PackageDoc[] packages = configuration.packages; |
| for (int i = 0; i < packages.length; i++) { |
| if (packages[i].equals(pkg)) { |
| included = true; |
| break; |
| } |
| } |
| } |
| if (included || pkg == null) { |
| return getHyperLink(pathString(pkg, "package-summary.html"), |
| "", label, isBold, style); |
| } else { |
| String crossPkgLink = getCrossPackageLink(Util.getPackageName(pkg)); |
| if (crossPkgLink != null) { |
| return getHyperLink(crossPkgLink, "", label, isBold, style); |
| } else { |
| return label; |
| } |
| } |
| } |
| |
| public String italicsClassName(ClassDoc cd, boolean qual) { |
| String name = (qual)? cd.qualifiedName(): cd.name(); |
| return (cd.isInterface())? italicsText(name): name; |
| } |
| |
| public void printSrcLink(ProgramElementDoc d, String label) { |
| if (d == null) { |
| return; |
| } |
| ClassDoc cd = d.containingClass(); |
| if (cd == null) { |
| //d must be a class doc since in has no containing class. |
| cd = (ClassDoc) d; |
| } |
| String href = relativePath + DocletConstants.SOURCE_OUTPUT_DIR_NAME |
| + DirectoryManager.getDirectoryPath(cd.containingPackage()) |
| + cd.name() + ".html#" + SourceToHTMLConverter.getAnchorName(d); |
| printHyperLink(href, "", label, true); |
| } |
| |
| /** |
| * Return the link to the given class. |
| * |
| * @param linkInfo the information about the link. |
| * |
| * @return the link for the given class. |
| */ |
| public String getLink(LinkInfoImpl linkInfo) { |
| LinkFactoryImpl factory = new LinkFactoryImpl(this); |
| String link = ((LinkOutputImpl) factory.getLinkOutput(linkInfo)).toString(); |
| displayLength += linkInfo.displayLength; |
| return link; |
| } |
| |
| /** |
| * Return the type parameters for the given class. |
| * |
| * @param linkInfo the information about the link. |
| * @return the type for the given class. |
| */ |
| public String getTypeParameterLinks(LinkInfoImpl linkInfo) { |
| LinkFactoryImpl factory = new LinkFactoryImpl(this); |
| return ((LinkOutputImpl) |
| factory.getTypeParameterLinks(linkInfo, false)).toString(); |
| } |
| |
| /** |
| * Print the link to the given class. |
| */ |
| public void printLink(LinkInfoImpl linkInfo) { |
| print(getLink(linkInfo)); |
| } |
| |
| /************************************************************* |
| * Return a class cross link to external class documentation. |
| * The name must be fully qualified to determine which package |
| * the class is in. The -link option does not allow users to |
| * link to external classes in the "default" package. |
| * |
| * @param qualifiedClassName the qualified name of the external class. |
| * @param refMemName the name of the member being referenced. This should |
| * be null or empty string if no member is being referenced. |
| * @param label the label for the external link. |
| * @param bold true if the link should be bold. |
| * @param style the style of the link. |
| * @param code true if the label should be code font. |
| */ |
| public String getCrossClassLink(String qualifiedClassName, String refMemName, |
| String label, boolean bold, String style, |
| boolean code) { |
| String className = "", |
| packageName = qualifiedClassName == null ? "" : qualifiedClassName; |
| int periodIndex; |
| while((periodIndex = packageName.lastIndexOf('.')) != -1) { |
| className = packageName.substring(periodIndex + 1, packageName.length()) + |
| (className.length() > 0 ? "." + className : ""); |
| String defaultLabel = code ? getCode() + className + getCodeEnd() : className; |
| packageName = packageName.substring(0, periodIndex); |
| if (getCrossPackageLink(packageName) != null) { |
| //The package exists in external documentation, so link to the external |
| //class (assuming that it exists). This is definitely a limitation of |
| //the -link option. There are ways to determine if an external package |
| //exists, but no way to determine if the external class exists. We just |
| //have to assume that it does. |
| return getHyperLink( |
| configuration.extern.getExternalLink(packageName, relativePath, |
| className + ".html?is-external=true"), |
| refMemName == null ? "" : refMemName, |
| label == null || label.length() == 0 ? defaultLabel : label, |
| bold, style, |
| configuration.getText("doclet.Href_Class_Or_Interface_Title", packageName), |
| ""); |
| } |
| } |
| return null; |
| } |
| |
| public boolean isClassLinkable(ClassDoc cd) { |
| if (cd.isIncluded()) { |
| return configuration.isGeneratedDoc(cd); |
| } |
| return configuration.extern.isExternal(cd); |
| } |
| |
| public String getCrossPackageLink(String pkgName) { |
| return configuration.extern.getExternalLink(pkgName, relativePath, |
| "package-summary.html?is-external=true"); |
| } |
| |
| public void printQualifiedClassLink(int context, ClassDoc cd) { |
| printLink(new LinkInfoImpl(context, cd, |
| configuration.getClassName(cd), "")); |
| } |
| |
| /** |
| * Print Class link, with only class name as the link and prefixing |
| * plain package name. |
| */ |
| public void printPreQualifiedClassLink(int context, ClassDoc cd) { |
| print(getPreQualifiedClassLink(context, cd, false)); |
| } |
| |
| /** |
| * Retrieve the class link with the package portion of the label in |
| * plain text. If the qualifier is excluded, it willnot be included in the |
| * link label. |
| * |
| * @param cd the class to link to. |
| * @param isBold true if the link should be bold. |
| * @return the link with the package portion of the label in plain text. |
| */ |
| public String getPreQualifiedClassLink(int context, |
| ClassDoc cd, boolean isBold) { |
| String classlink = ""; |
| PackageDoc pd = cd.containingPackage(); |
| if(pd != null && ! configuration.shouldExcludeQualifier(pd.name())) { |
| classlink = getPkgName(cd); |
| } |
| classlink += getLink(new LinkInfoImpl(context, cd, cd.name(), isBold)); |
| return classlink; |
| } |
| |
| |
| /** |
| * Print Class link, with only class name as the bold link and prefixing |
| * plain package name. |
| */ |
| public void printPreQualifiedBoldClassLink(int context, ClassDoc cd) { |
| print(getPreQualifiedClassLink(context, cd, true)); |
| } |
| |
| public void printText(String key) { |
| print(configuration.getText(key)); |
| } |
| |
| public void printText(String key, String a1) { |
| print(configuration.getText(key, a1)); |
| } |
| |
| public void printText(String key, String a1, String a2) { |
| print(configuration.getText(key, a1, a2)); |
| } |
| |
| public void boldText(String key) { |
| bold(configuration.getText(key)); |
| } |
| |
| public void boldText(String key, String a1) { |
| bold(configuration.getText(key, a1)); |
| } |
| |
| public void boldText(String key, String a1, String a2) { |
| bold(configuration.getText(key, a1, a2)); |
| } |
| |
| /** |
| * Print the link for the given member. |
| * |
| * @param context the id of the context where the link will be printed. |
| * @param doc the member being linked to. |
| * @param label the label for the link. |
| * @param bold true if the link should be bold. |
| */ |
| public void printDocLink(int context, MemberDoc doc, String label, |
| boolean bold) { |
| print(getDocLink(context, doc, label, bold)); |
| } |
| |
| /** |
| * Print the link for the given member. |
| * |
| * @param context the id of the context where the link will be printed. |
| * @param classDoc the classDoc that we should link to. This is not |
| * necessarily equal to doc.containingClass(). We may be |
| * inheriting comments. |
| * @param doc the member being linked to. |
| * @param label the label for the link. |
| * @param bold true if the link should be bold. |
| */ |
| public void printDocLink(int context, ClassDoc classDoc, MemberDoc doc, |
| String label, boolean bold) { |
| print(getDocLink(context, classDoc, doc, label, bold)); |
| } |
| |
| /** |
| * Return the link for the given member. |
| * |
| * @param context the id of the context where the link will be printed. |
| * @param doc the member being linked to. |
| * @param label the label for the link. |
| * @param bold true if the link should be bold. |
| * @return the link for the given member. |
| */ |
| public String getDocLink(int context, MemberDoc doc, String label, |
| boolean bold) { |
| return getDocLink(context, doc.containingClass(), doc, label, bold); |
| } |
| |
| /** |
| * Return the link for the given member. |
| * |
| * @param context the id of the context where the link will be printed. |
| * @param classDoc the classDoc that we should link to. This is not |
| * necessarily equal to doc.containingClass(). We may be |
| * inheriting comments. |
| * @param doc the member being linked to. |
| * @param label the label for the link. |
| * @param bold true if the link should be bold. |
| * @return the link for the given member. |
| */ |
| public String getDocLink(int context, ClassDoc classDoc, MemberDoc doc, |
| String label, boolean bold) { |
| if (! (doc.isIncluded() || |
| Util.isLinkable(classDoc, configuration()))) { |
| return label; |
| } else if (doc instanceof ExecutableMemberDoc) { |
| ExecutableMemberDoc emd = (ExecutableMemberDoc)doc; |
| return getLink(new LinkInfoImpl(context, classDoc, |
| getAnchor(emd), label, bold)); |
| } else if (doc instanceof MemberDoc) { |
| return getLink(new LinkInfoImpl(context, classDoc, |
| doc.name(), label, bold)); |
| } else { |
| return label; |
| } |
| } |
| |
| public void anchor(ExecutableMemberDoc emd) { |
| anchor(getAnchor(emd)); |
| } |
| |
| public String getAnchor(ExecutableMemberDoc emd) { |
| StringBuilder signature = new StringBuilder(emd.signature()); |
| StringBuilder signatureParsed = new StringBuilder(); |
| int counter = 0; |
| for (int i = 0; i < signature.length(); i++) { |
| char c = signature.charAt(i); |
| if (c == '<') { |
| counter++; |
| } else if (c == '>') { |
| counter--; |
| } else if (counter == 0) { |
| signatureParsed.append(c); |
| } |
| } |
| return emd.name() + signatureParsed.toString(); |
| } |
| |
| public String seeTagToString(SeeTag see) { |
| String tagName = see.name(); |
| if (! (tagName.startsWith("@link") || tagName.equals("@see"))) { |
| return ""; |
| } |
| StringBuffer result = new StringBuffer(); |
| boolean isplaintext = tagName.toLowerCase().equals("@linkplain"); |
| String label = see.label(); |
| label = (label.length() > 0)? |
| ((isplaintext) ? label : |
| getCode() + label + getCodeEnd()):""; |
| String seetext = replaceDocRootDir(see.text()); |
| |
| //Check if @see is an href or "string" |
| if (seetext.startsWith("<") || seetext.startsWith("\"")) { |
| result.append(seetext); |
| return result.toString(); |
| } |
| |
| //The text from the @see tag. We will output this text when a label is not specified. |
| String text = (isplaintext) ? seetext : getCode() + seetext + getCodeEnd(); |
| |
| ClassDoc refClass = see.referencedClass(); |
| String refClassName = see.referencedClassName(); |
| MemberDoc refMem = see.referencedMember(); |
| String refMemName = see.referencedMemberName(); |
| if (refClass == null) { |
| //@see is not referencing an included class |
| PackageDoc refPackage = see.referencedPackage(); |
| if (refPackage != null && refPackage.isIncluded()) { |
| //@see is referencing an included package |
| String packageName = isplaintext ? refPackage.name() : |
| getCode() + refPackage.name() + getCodeEnd(); |
| result.append(getPackageLink(refPackage, |
| label.length() == 0 ? packageName : label, false)); |
| } else { |
| //@see is not referencing an included class or package. Check for cross links. |
| String classCrossLink, packageCrossLink = getCrossPackageLink(refClassName); |
| if (packageCrossLink != null) { |
| //Package cross link found |
| result.append(getHyperLink(packageCrossLink, "", |
| (label.length() == 0)? text : label, false)); |
| } else if ((classCrossLink = getCrossClassLink(refClassName, |
| refMemName, label, false, "", ! isplaintext)) != null) { |
| //Class cross link found (possiblly to a member in the class) |
| result.append(classCrossLink); |
| } else { |
| //No cross link found so print warning |
| configuration.getDocletSpecificMsg().warning(see.position(), "doclet.see.class_or_package_not_found", |
| tagName, seetext); |
| result.append((label.length() == 0)? text: label); |
| } |
| } |
| } else if (refMemName == null) { |
| // Must be a class reference since refClass is not null and refMemName is null. |
| if (label.length() == 0) { |
| label = (isplaintext) ? refClass.name() : getCode() + refClass.name() + getCodeEnd(); |
| result.append(getLink(new LinkInfoImpl(refClass, label))); |
| } else { |
| result.append(getLink(new LinkInfoImpl(refClass, label))); |
| } |
| } else if (refMem == null) { |
| // Must be a member reference since refClass is not null and refMemName is not null. |
| // However, refMem is null, so this referenced member does not exist. |
| result.append((label.length() == 0)? text: label); |
| } else { |
| // Must be a member reference since refClass is not null and refMemName is not null. |
| // refMem is not null, so this @see tag must be referencing a valid member. |
| ClassDoc containing = refMem.containingClass(); |
| if (see.text().trim().startsWith("#") && |
| ! (containing.isPublic() || |
| Util.isLinkable(containing, configuration()))) { |
| // Since the link is relative and the holder is not even being |
| // documented, this must be an inherited link. Redirect it. |
| // The current class either overrides the referenced member or |
| // inherits it automatically. |
| containing = ((ClassWriterImpl) this).getClassDoc(); |
| } |
| if (configuration.currentcd != containing) { |
| refMemName = containing.name() + "." + refMemName; |
| } |
| if (refMem instanceof ExecutableMemberDoc) { |
| if (refMemName.indexOf('(') < 0) { |
| refMemName += ((ExecutableMemberDoc)refMem).signature(); |
| } |
| } |
| text = (isplaintext) ? |
| refMemName : getCode() + refMemName + getCodeEnd(); |
| |
| result.append(getDocLink(LinkInfoImpl.CONTEXT_SEE_TAG, containing, |
| refMem, (label.length() == 0)? text: label, false)); |
| } |
| return result.toString(); |
| } |
| |
| public void printInlineComment(Doc doc, Tag tag) { |
| printCommentTags(doc, tag.inlineTags(), false, false); |
| } |
| |
| public void printInlineDeprecatedComment(Doc doc, Tag tag) { |
| printCommentTags(doc, tag.inlineTags(), true, false); |
| } |
| |
| public void printSummaryComment(Doc doc) { |
| printSummaryComment(doc, doc.firstSentenceTags()); |
| } |
| |
| public void printSummaryComment(Doc doc, Tag[] firstSentenceTags) { |
| printCommentTags(doc, firstSentenceTags, false, true); |
| } |
| |
| public void printSummaryDeprecatedComment(Doc doc) { |
| printCommentTags(doc, doc.firstSentenceTags(), true, true); |
| } |
| |
| public void printSummaryDeprecatedComment(Doc doc, Tag tag) { |
| printCommentTags(doc, tag.firstSentenceTags(), true, true); |
| } |
| |
| public void printInlineComment(Doc doc) { |
| printCommentTags(doc, doc.inlineTags(), false, false); |
| p(); |
| } |
| |
| public void printInlineDeprecatedComment(Doc doc) { |
| printCommentTags(doc, doc.inlineTags(), true, false); |
| } |
| |
| private void printCommentTags(Doc doc, Tag[] tags, boolean depr, boolean first) { |
| if(configuration.nocomment){ |
| return; |
| } |
| if (depr) { |
| italic(); |
| } |
| String result = commentTagsToString(null, doc, tags, first); |
| print(result); |
| if (depr) { |
| italicEnd(); |
| } |
| if (tags.length == 0) { |
| space(); |
| } |
| } |
| |
| /** |
| * Converts inline tags and text to text strings, expanding the |
| * inline tags along the way. Called wherever text can contain |
| * an inline tag, such as in comments or in free-form text arguments |
| * to non-inline tags. |
| * |
| * @param holderTag specific tag where comment resides |
| * @param doc specific doc where comment resides |
| * @param tags array of text tags and inline tags (often alternating) |
| * present in the text of interest for this doc |
| * @param isFirstSentence true if text is first sentence |
| */ |
| public String commentTagsToString(Tag holderTag, Doc doc, Tag[] tags, |
| boolean isFirstSentence) { |
| StringBuffer result = new StringBuffer(); |
| // Array of all possible inline tags for this javadoc run |
| configuration.tagletManager.checkTags(doc, tags, true); |
| for (int i = 0; i < tags.length; i++) { |
| Tag tagelem = tags[i]; |
| String tagName = tagelem.name(); |
| if (tagelem instanceof SeeTag) { |
| result.append(seeTagToString((SeeTag)tagelem)); |
| } else if (! tagName.equals("Text")) { |
| int originalLength = result.length(); |
| TagletOutput output = TagletWriter.getInlineTagOuput( |
| configuration.tagletManager, holderTag, |
| tagelem, getTagletWriterInstance(isFirstSentence)); |
| result.append(output == null ? "" : output.toString()); |
| if (originalLength == 0 && isFirstSentence && tagelem.name().equals("@inheritDoc") && result.length() > 0) { |
| break; |
| } else { |
| continue; |
| } |
| } else { |
| //This is just a regular text tag. The text may contain html links (<a>) |
| //or inline tag {@docRoot}, which will be handled as special cases. |
| String text = redirectRelativeLinks(tagelem.holder(), tagelem.text()); |
| |
| // Replace @docRoot only if not represented by an instance of DocRootTaglet, |
| // that is, only if it was not present in a source file doc comment. |
| // This happens when inserted by the doclet (a few lines |
| // above in this method). [It might also happen when passed in on the command |
| // line as a text argument to an option (like -header).] |
| text = replaceDocRootDir(text); |
| if (isFirstSentence) { |
| text = removeNonInlineHtmlTags(text); |
| } |
| StringTokenizer lines = new StringTokenizer(text, "\r\n", true); |
| StringBuffer textBuff = new StringBuffer(); |
| while (lines.hasMoreTokens()) { |
| StringBuffer line = new StringBuffer(lines.nextToken()); |
| Util.replaceTabs(configuration.sourcetab, line); |
| textBuff.append(line.toString()); |
| } |
| result.append(textBuff); |
| } |
| } |
| return result.toString(); |
| } |
| |
| /** |
| * Return true if relative links should not be redirected. |
| * |
| * @return Return true if a relative link should not be redirected. |
| */ |
| private boolean shouldNotRedirectRelativeLinks() { |
| return this instanceof AnnotationTypeWriter || |
| this instanceof ClassWriter || |
| this instanceof PackageSummaryWriter; |
| } |
| |
| /** |
| * Suppose a piece of documentation has a relative link. When you copy |
| * that documetation to another place such as the index or class-use page, |
| * that relative link will no longer work. We should redirect those links |
| * so that they will work again. |
| * <p> |
| * Here is the algorithm used to fix the link: |
| * <p> |
| * <relative link> => docRoot + <relative path to file> + <relative link> |
| * <p> |
| * For example, suppose com.sun.javadoc.RootDoc has this link: |
| * <a href="package-summary.html">The package Page</a> |
| * <p> |
| * If this link appeared in the index, we would redirect |
| * the link like this: |
| * |
| * <a href="./com/sun/javadoc/package-summary.html">The package Page</a> |
| * |
| * @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; |
| } |
| |
| String redirectPathFromRoot; |
| if (doc instanceof ClassDoc) { |
| redirectPathFromRoot = DirectoryManager.getDirectoryPath(((ClassDoc) doc).containingPackage()); |
| } else if (doc instanceof MemberDoc) { |
| redirectPathFromRoot = DirectoryManager.getDirectoryPath(((MemberDoc) doc).containingPackage()); |
| } else if (doc instanceof PackageDoc) { |
| redirectPathFromRoot = DirectoryManager.getDirectoryPath((PackageDoc) doc); |
| } else { |
| return text; |
| } |
| |
| if (! redirectPathFromRoot.endsWith(DirectoryManager.URL_FILE_SEPERATOR)) { |
| redirectPathFromRoot += DirectoryManager.URL_FILE_SEPERATOR; |
| } |
| |
| //Redirect all relative links. |
| int end, begin = text.toLowerCase().indexOf("<a"); |
| if(begin >= 0){ |
| StringBuffer textBuff = new StringBuffer(text); |
| |
| while(begin >=0){ |
| if (textBuff.length() > begin + 2 && ! Character.isWhitespace(textBuff.charAt(begin+2))) { |
| begin = textBuff.toString().toLowerCase().indexOf("<a", begin + 1); |
| continue; |
| } |
| |
| begin = textBuff.indexOf("=", begin) + 1; |
| end = textBuff.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 <a> 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 |
| + relativeLink; |
| textBuff.replace(begin, end, relativeLink); |
| } |
| begin = textBuff.toString().toLowerCase().indexOf("<a", begin + 1); |
| } |
| return textBuff.toString(); |
| } |
| return text; |
| } |
| |
| public String removeNonInlineHtmlTags(String text) { |
| if (text.indexOf('<') < 0) { |
| return text; |
| } |
| String noninlinetags[] = { "<ul>", "</ul>", "<ol>", "</ol>", |
| "<dl>", "</dl>", "<table>", "</table>", |
| "<tr>", "</tr>", "<td>", "</td>", |
| "<th>", "</th>", "<p>", "</p>", |
| "<li>", "</li>", "<dd>", "</dd>", |
| "<dir>", "</dir>", "<dt>", "</dt>", |
| "<h1>", "</h1>", "<h2>", "</h2>", |
| "<h3>", "</h3>", "<h4>", "</h4>", |
| "<h5>", "</h5>", "<h6>", "</h6>", |
| "<pre>", "</pre>", "<menu>", "</menu>", |
| "<listing>", "</listing>", "<hr>", |
| "<blockquote>", "</blockquote>", |
| "<center>", "</center>", |
| "<UL>", "</UL>", "<OL>", "</OL>", |
| "<DL>", "</DL>", "<TABLE>", "</TABLE>", |
| "<TR>", "</TR>", "<TD>", "</TD>", |
| "<TH>", "</TH>", "<P>", "</P>", |
| "<LI>", "</LI>", "<DD>", "</DD>", |
| "<DIR>", "</DIR>", "<DT>", "</DT>", |
| "<H1>", "</H1>", "<H2>", "</H2>", |
| "<H3>", "</H3>", "<H4>", "</H4>", |
| "<H5>", "</H5>", "<H6>", "</H6>", |
| "<PRE>", "</PRE>", "<MENU>", "</MENU>", |
| "<LISTING>", "</LISTING>", "<HR>", |
| "<BLOCKQUOTE>", "</BLOCKQUOTE>", |
| "<CENTER>", "</CENTER>" |
| }; |
| for (int i = 0; i < noninlinetags.length; i++) { |
| text = replace(text, noninlinetags[i], ""); |
| } |
| return text; |
| } |
| |
| public String replace(String text, String tobe, String by) { |
| while (true) { |
| int startindex = text.indexOf(tobe); |
| if (startindex < 0) { |
| return text; |
| } |
| int endindex = startindex + tobe.length(); |
| StringBuffer replaced = new StringBuffer(); |
| if (startindex > 0) { |
| replaced.append(text.substring(0, startindex)); |
| } |
| replaced.append(by); |
| if (text.length() > endindex) { |
| replaced.append(text.substring(endindex)); |
| } |
| text = replaced.toString(); |
| } |
| } |
| |
| public void printStyleSheetProperties() { |
| String filename = configuration.stylesheetfile; |
| if (filename.length() > 0) { |
| File stylefile = new File(filename); |
| String parent = stylefile.getParent(); |
| filename = (parent == null)? |
| filename: |
| filename.substring(parent.length() + 1); |
| } else { |
| filename = "stylesheet.css"; |
| } |
| filename = relativePath + filename; |
| link("REL =\"stylesheet\" TYPE=\"text/css\" HREF=\"" + |
| filename + "\" " + "TITLE=\"Style\""); |
| } |
| |
| /** |
| * According to the Java Language Specifications, all the outer classes |
| * and static nested classes are core classes. |
| */ |
| public boolean isCoreClass(ClassDoc cd) { |
| return cd.containingClass() == null || cd.isStatic(); |
| } |
| |
| /** |
| * Write the annotatation types for the given packageDoc. |
| * |
| * @param packageDoc the package to write annotations for. |
| */ |
| public void writeAnnotationInfo(PackageDoc packageDoc) { |
| writeAnnotationInfo(packageDoc, packageDoc.annotations()); |
| } |
| |
| /** |
| * Write the annotatation types for the given doc. |
| * |
| * @param doc the doc to write annotations for. |
| */ |
| public void writeAnnotationInfo(ProgramElementDoc doc) { |
| writeAnnotationInfo(doc, doc.annotations()); |
| } |
| |
| /** |
| * Write the annotatation types for the given doc and parameter. |
| * |
| * @param indent the number of spaced to indent the parameters. |
| * @param doc the doc to write annotations for. |
| * @param param the parameter to write annotations for. |
| */ |
| public boolean writeAnnotationInfo(int indent, Doc doc, Parameter param) { |
| return writeAnnotationInfo(indent, doc, param.annotations(), false); |
| } |
| |
| /** |
| * Write the annotatation types for the given doc. |
| * |
| * @param doc the doc to write annotations for. |
| * @param descList the array of {@link AnnotationDesc}. |
| */ |
| private void writeAnnotationInfo(Doc doc, AnnotationDesc[] descList) { |
| writeAnnotationInfo(0, doc, descList, true); |
| } |
| |
| /** |
| * Write the annotatation types for the given doc. |
| * |
| * @param indent the number of extra spaces to indent the annotations. |
| * @param doc the doc to write annotations for. |
| * @param descList the array of {@link AnnotationDesc}. |
| */ |
| private boolean writeAnnotationInfo(int indent, Doc doc, AnnotationDesc[] descList, boolean lineBreak) { |
| List annotations = getAnnotations(indent, descList, lineBreak); |
| if (annotations.size() == 0) { |
| return false; |
| } |
| fontNoNewLine("-1"); |
| for (Iterator iter = annotations.iterator(); iter.hasNext();) { |
| print((String) iter.next()); |
| } |
| fontEnd(); |
| return true; |
| } |
| |
| /** |
| * Return the string representations of the annotation types for |
| * the given doc. |
| * |
| * @param indent the number of extra spaces to indent the annotations. |
| * @param descList the array of {@link AnnotationDesc}. |
| * @param linkBreak if true, add new line between each member value. |
| * @return an array of strings representing the annotations being |
| * documented. |
| */ |
| private List<String> getAnnotations(int indent, AnnotationDesc[] descList, boolean linkBreak) { |
| List<String> results = new ArrayList<String>(); |
| StringBuffer annotation; |
| for (int i = 0; i < descList.length; i++) { |
| AnnotationTypeDoc annotationDoc = descList[i].annotationType(); |
| if (! Util.isDocumentedAnnotation(annotationDoc)){ |
| continue; |
| } |
| annotation = new StringBuffer(); |
| LinkInfoImpl linkInfo = new LinkInfoImpl( |
| LinkInfoImpl.CONTEXT_ANNOTATION, annotationDoc); |
| linkInfo.label = "@" + annotationDoc.name(); |
| annotation.append(getLink(linkInfo)); |
| AnnotationDesc.ElementValuePair[] pairs = descList[i].elementValues(); |
| if (pairs.length > 0) { |
| annotation.append('('); |
| for (int j = 0; j < pairs.length; j++) { |
| if (j > 0) { |
| annotation.append(","); |
| if (linkBreak) { |
| annotation.append(DocletConstants.NL); |
| int spaces = annotationDoc.name().length() + 2; |
| for (int k = 0; k < (spaces + indent); k++) { |
| annotation.append(' '); |
| } |
| } |
| } |
| annotation.append(getDocLink(LinkInfoImpl.CONTEXT_ANNOTATION, |
| pairs[j].element(), pairs[j].element().name(), false)); |
| annotation.append('='); |
| AnnotationValue annotationValue = pairs[j].value(); |
| List<AnnotationValue> annotationTypeValues = new ArrayList<AnnotationValue>(); |
| if (annotationValue.value() instanceof AnnotationValue[]) { |
| AnnotationValue[] annotationArray = |
| (AnnotationValue[]) annotationValue.value(); |
| for (int k = 0; k < annotationArray.length; k++) { |
| annotationTypeValues.add(annotationArray[k]); |
| } |
| } else { |
| annotationTypeValues.add(annotationValue); |
| } |
| annotation.append(annotationTypeValues.size() == 1 ? "" : "{"); |
| for (Iterator iter = annotationTypeValues.iterator(); iter.hasNext(); ) { |
| annotation.append(annotationValueToString((AnnotationValue) iter.next())); |
| annotation.append(iter.hasNext() ? "," : ""); |
| } |
| annotation.append(annotationTypeValues.size() == 1 ? "" : "}"); |
| } |
| annotation.append(")"); |
| } |
| annotation.append(linkBreak ? DocletConstants.NL : ""); |
| results.add(annotation.toString()); |
| } |
| return results; |
| } |
| |
| private String annotationValueToString(AnnotationValue annotationValue) { |
| if (annotationValue.value() instanceof Type) { |
| Type type = (Type) annotationValue.value(); |
| if (type.asClassDoc() != null) { |
| LinkInfoImpl linkInfo = new LinkInfoImpl( |
| LinkInfoImpl.CONTEXT_ANNOTATION, type); |
| linkInfo.label = (type.asClassDoc().isIncluded() ? |
| type.typeName() : |
| type.qualifiedTypeName()) + type.dimension() + ".class"; |
| return getLink(linkInfo); |
| } else { |
| return type.typeName() + type.dimension() + ".class"; |
| } |
| } else if (annotationValue.value() instanceof AnnotationDesc) { |
| List list = getAnnotations(0, |
| new AnnotationDesc[]{(AnnotationDesc) annotationValue.value()}, |
| false); |
| StringBuffer buf = new StringBuffer(); |
| for (Iterator iter = list.iterator(); iter.hasNext(); ) { |
| buf.append(iter.next()); |
| } |
| return buf.toString(); |
| } else if (annotationValue.value() instanceof MemberDoc) { |
| return getDocLink(LinkInfoImpl.CONTEXT_ANNOTATION, |
| (MemberDoc) annotationValue.value(), |
| ((MemberDoc) annotationValue.value()).name(), false); |
| } else { |
| return annotationValue.toString(); |
| } |
| } |
| |
| /** |
| * Return the configuation for this doclet. |
| * |
| * @return the configuration for this doclet. |
| */ |
| public Configuration configuration() { |
| return configuration; |
| } |
| } |