0001: /*
0002: * Copyright 1998-2006 Sun Microsystems, Inc. All Rights Reserved.
0003: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
0004: *
0005: * This code is free software; you can redistribute it and/or modify it
0006: * under the terms of the GNU General Public License version 2 only, as
0007: * published by the Free Software Foundation. Sun designates this
0008: * particular file as subject to the "Classpath" exception as provided
0009: * by Sun in the LICENSE file that accompanied this code.
0010: *
0011: * This code is distributed in the hope that it will be useful, but WITHOUT
0012: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
0013: * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
0014: * version 2 for more details (a copy is included in the LICENSE file that
0015: * accompanied this code).
0016: *
0017: * You should have received a copy of the GNU General Public License version
0018: * 2 along with this work; if not, write to the Free Software Foundation,
0019: * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
0020: *
0021: * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
0022: * CA 95054 USA or visit www.sun.com if you need additional information or
0023: * have any questions.
0024: */
0025:
0026: package com.sun.tools.doclets.formats.html;
0027:
0028: import com.sun.tools.doclets.formats.html.markup.*;
0029:
0030: import com.sun.tools.doclets.internal.toolkit.*;
0031: import com.sun.tools.doclets.internal.toolkit.util.*;
0032: import com.sun.tools.doclets.internal.toolkit.taglets.*;
0033:
0034: import com.sun.javadoc.*;
0035: import java.io.*;
0036: import java.text.SimpleDateFormat;
0037: import java.util.*;
0038:
0039: /**
0040: * Class for the Html Format Code Generation specific to JavaDoc.
0041: * This Class contains methods related to the Html Code Generation which
0042: * are used extensively while generating the entire documentation.
0043: *
0044: * @since 1.2
0045: * @author Atul M Dambalkar
0046: * @author Robert Field
0047: */
0048: public class HtmlDocletWriter extends HtmlDocWriter {
0049:
0050: /**
0051: * Relative path from the file getting generated to the destination
0052: * directory. For example, if the file getting generated is
0053: * "java/lang/Object.html", then the relative path string is "../../".
0054: * This string can be empty if the file getting generated is in
0055: * the destination directory.
0056: */
0057: public String relativePath = "";
0058:
0059: /**
0060: * Same as relativepath, but normalized to never be empty or
0061: * end with a slash.
0062: */
0063: public String relativepathNoSlash = "";
0064:
0065: /**
0066: * Platform-dependent directory path from the current or the
0067: * destination directory to the file getting generated.
0068: * Used when creating the file.
0069: * For example, if the file getting generated is
0070: * "java/lang/Object.html", then the path string is "java/lang".
0071: */
0072: public String path = "";
0073:
0074: /**
0075: * Name of the file getting generated. If the file getting generated is
0076: * "java/lang/Object.html", then the filename is "Object.html".
0077: */
0078: public String filename = "";
0079:
0080: /**
0081: * The display length used for indentation while generating the class page.
0082: */
0083: public int displayLength = 0;
0084:
0085: /**
0086: * The global configuration information for this run.
0087: */
0088: public ConfigurationImpl configuration;
0089:
0090: /**
0091: * Constructor to construct the HtmlStandardWriter object.
0092: *
0093: * @param filename File to be generated.
0094: */
0095: public HtmlDocletWriter(ConfigurationImpl configuration,
0096: String filename) throws IOException {
0097: super (configuration, filename);
0098: this .configuration = configuration;
0099: this .filename = filename;
0100: }
0101:
0102: /**
0103: * Constructor to construct the HtmlStandardWriter object.
0104: *
0105: * @param path Platform-dependent {@link #path} used when
0106: * creating file.
0107: * @param filename Name of file to be generated.
0108: * @param relativePath Value for the variable {@link #relativePath}.
0109: */
0110: public HtmlDocletWriter(ConfigurationImpl configuration,
0111: String path, String filename, String relativePath)
0112: throws IOException {
0113: super (configuration, path, filename);
0114: this .configuration = configuration;
0115: this .path = path;
0116: this .relativePath = relativePath;
0117: this .relativepathNoSlash = DirectoryManager
0118: .getPathNoTrailingSlash(this .relativePath);
0119: this .filename = filename;
0120: }
0121:
0122: /**
0123: * Replace {@docRoot} tag used in options that accept HTML text, such
0124: * as -header, -footer, -top and -bottom, and when converting a relative
0125: * HREF where commentTagsToString inserts a {@docRoot} where one was
0126: * missing. (Also see DocRootTaglet for {@docRoot} tags in doc
0127: * comments.)
0128: * <p>
0129: * Replace {@docRoot} tag in htmlstr with the relative path to the
0130: * destination directory from the directory where the file is being
0131: * written, looping to handle all such tags in htmlstr.
0132: * <p>
0133: * For example, for "-d docs" and -header containing {@docRoot}, when
0134: * the HTML page for source file p/C1.java is being generated, the
0135: * {@docRoot} tag would be inserted into the header as "../",
0136: * the relative path from docs/p/ to docs/ (the document root).
0137: * <p>
0138: * Note: This doc comment was written with '&#064;' representing '@'
0139: * to prevent the inline tag from being interpreted.
0140: */
0141: public String replaceDocRootDir(String htmlstr) {
0142: // Return if no inline tags exist
0143: int index = htmlstr.indexOf("{@");
0144: if (index < 0) {
0145: return htmlstr;
0146: }
0147: String lowerHtml = htmlstr.toLowerCase();
0148: // Return index of first occurrence of {@docroot}
0149: // Note: {@docRoot} is not case sensitive when passed in w/command line option
0150: index = lowerHtml.indexOf("{@docroot}", index);
0151: if (index < 0) {
0152: return htmlstr;
0153: }
0154: StringBuffer buf = new StringBuffer();
0155: int previndex = 0;
0156: while (true) {
0157: // Search for lowercase version of {@docRoot}
0158: index = lowerHtml.indexOf("{@docroot}", previndex);
0159: // If next {@docRoot} tag not found, append rest of htmlstr and exit loop
0160: if (index < 0) {
0161: buf.append(htmlstr.substring(previndex));
0162: break;
0163: }
0164: // If next {@docroot} tag found, append htmlstr up to start of tag
0165: buf.append(htmlstr.substring(previndex, index));
0166: previndex = index + 10; // length for {@docroot} string
0167: // Insert relative path where {@docRoot} was located
0168: buf.append(relativepathNoSlash);
0169: // Append slash if next character is not a slash
0170: if (relativepathNoSlash.length() > 0
0171: && previndex < htmlstr.length()
0172: && htmlstr.charAt(previndex) != '/') {
0173: buf.append(DirectoryManager.URL_FILE_SEPERATOR);
0174: }
0175: }
0176: return buf.toString();
0177: }
0178:
0179: /**
0180: * Print Html Hyper Link, with target frame. This
0181: * link will only appear if page is not in a frame.
0182: *
0183: * @param link String name of the file.
0184: * @param where Position in the file
0185: * @param target Name of the target frame.
0186: * @param label Tag for the link.
0187: * @param bold Whether the label should be bold or not?
0188: */
0189: public void printNoFramesTargetHyperLink(String link, String where,
0190: String target, String label, boolean bold) {
0191: script();
0192: println(" <!--");
0193: println(" if(window==top) {");
0194: println(" document.writeln('"
0195: + getHyperLink(link, where, label, bold, "", "", target)
0196: + "');");
0197: println(" }");
0198: println(" //-->");
0199: scriptEnd();
0200: noScript();
0201: println(" "
0202: + getHyperLink(link, where, label, bold, "", "", target));
0203: noScriptEnd();
0204: println(DocletConstants.NL);
0205: }
0206:
0207: private void printMethodInfo(MethodDoc method) {
0208: ClassDoc[] intfacs = method.containingClass().interfaces();
0209: MethodDoc overriddenMethod = method.overriddenMethod();
0210: if (intfacs.length > 0 || overriddenMethod != null) {
0211: dd();
0212: printTagsInfoHeader();
0213: MethodWriterImpl.printImplementsInfo(this , method);
0214: if (overriddenMethod != null) {
0215: MethodWriterImpl.printOverridden(this , method
0216: .overriddenType(), overriddenMethod);
0217: }
0218: printTagsInfoFooter();
0219: ddEnd();
0220: }
0221: dd();
0222: }
0223:
0224: protected void printTags(Doc doc) {
0225: if (configuration.nocomment) {
0226: return;
0227: }
0228: if (doc instanceof MethodDoc) {
0229: printMethodInfo((MethodDoc) doc);
0230: }
0231: TagletOutputImpl output = new TagletOutputImpl("");
0232: TagletWriter.genTagOuput(configuration.tagletManager, doc,
0233: configuration.tagletManager.getCustomTags(doc),
0234: getTagletWriterInstance(false), output);
0235: if (output.toString().trim().length() > 0) {
0236: printTagsInfoHeader();
0237: print(output.toString());
0238: printTagsInfoFooter();
0239: } else if (!(doc instanceof ConstructorDoc
0240: || doc instanceof RootDoc || doc instanceof ClassDoc)) {
0241: //To be consistent with 1.4.2 output.
0242: //I hate to do this but we have to pass the diff test to prove
0243: //nothing has broken.
0244: printTagsInfoHeader();
0245: printTagsInfoFooter();
0246: }
0247: }
0248:
0249: /**
0250: * Returns a TagletWriter that knows how to write HTML.
0251: *
0252: * @return a TagletWriter that knows how to write HTML.
0253: */
0254: public TagletWriter getTagletWriterInstance(boolean isFirstSentence) {
0255: return new TagletWriterImpl(this , isFirstSentence);
0256: }
0257:
0258: protected void printTagsInfoHeader() {
0259: dl();
0260: }
0261:
0262: protected void printTagsInfoFooter() {
0263: dlEnd();
0264: }
0265:
0266: /**
0267: * Print Package link, with target frame.
0268: *
0269: * @param pd The link will be to the "package-summary.html" page for this
0270: * package.
0271: * @param target Name of the target frame.
0272: * @param label Tag for the link.
0273: */
0274: public void printTargetPackageLink(PackageDoc pd, String target,
0275: String label) {
0276: print(getHyperLink(pathString(pd, "package-summary.html"), "",
0277: label, false, "", "", target));
0278: }
0279:
0280: /**
0281: * Print the html file header. Also print Html page title and stylesheet
0282: * default properties.
0283: *
0284: * @param title String window title to go in the <TITLE> tag
0285: * @param metakeywords Array of String keywords for META tag. Each element
0286: * of the array is assigned to a separate META tag.
0287: * Pass in null for no array.
0288: * @param includeScript boolean true if printing windowtitle script.
0289: * False for files that appear in the left-hand frames.
0290: */
0291: public void printHtmlHeader(String title, String[] metakeywords,
0292: boolean includeScript) {
0293: println("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 "
0294: + "Transitional//EN\" "
0295: + "\"http://www.w3.org/TR/html4/loose.dtd\">");
0296: println("<!--NewPage-->");
0297: html();
0298: head();
0299: if (!configuration.notimestamp) {
0300: print("<!-- Generated by javadoc (build "
0301: + ConfigurationImpl.BUILD_DATE + ") on ");
0302: print(today());
0303: println(" -->");
0304: }
0305: if (configuration.charset.length() > 0) {
0306: println("<META http-equiv=\"Content-Type\" content=\"text/html; "
0307: + "charset=" + configuration.charset + "\">");
0308: }
0309: if (configuration.windowtitle.length() > 0) {
0310: title += " (" + configuration.windowtitle + ")";
0311: }
0312: title(title);
0313: println(title);
0314: titleEnd();
0315: println("");
0316: if (!configuration.notimestamp) {
0317: SimpleDateFormat dateFormat = new SimpleDateFormat(
0318: "yyyy-MM-dd");
0319: println("<META NAME=\"date\" " + "CONTENT=\""
0320: + dateFormat.format(new Date()) + "\">");
0321: }
0322: if (metakeywords != null) {
0323: for (int i = 0; i < metakeywords.length; i++) {
0324: println("<META NAME=\"keywords\" " + "CONTENT=\""
0325: + metakeywords[i] + "\">");
0326: }
0327: }
0328: println("");
0329: printStyleSheetProperties();
0330: println("");
0331: // Don't print windowtitle script for overview-frame, allclasses-frame
0332: // and package-frame
0333: if (includeScript) {
0334: printWinTitleScript(title);
0335: }
0336: println("");
0337: headEnd();
0338: println("");
0339: body("white", includeScript);
0340: }
0341:
0342: /**
0343: * Print user specified header and the footer.
0344: *
0345: * @param header if true print the user provided header else print the
0346: * user provided footer.
0347: */
0348: public void printUserHeaderFooter(boolean header) {
0349: em();
0350: if (header) {
0351: print(replaceDocRootDir(configuration.header));
0352: } else {
0353: if (configuration.footer.length() != 0) {
0354: print(replaceDocRootDir(configuration.footer));
0355: } else {
0356: print(replaceDocRootDir(configuration.header));
0357: }
0358: }
0359: emEnd();
0360: }
0361:
0362: /**
0363: * Print the user specified top.
0364: */
0365: public void printTop() {
0366: print(replaceDocRootDir(configuration.top));
0367: hr();
0368: }
0369:
0370: /**
0371: * Print the user specified bottom.
0372: */
0373: public void printBottom() {
0374: hr();
0375: print(replaceDocRootDir(configuration.bottom));
0376: }
0377:
0378: /**
0379: * Print the navigation bar for the Html page at the top and and the bottom.
0380: *
0381: * @param header If true print navigation bar at the top of the page else
0382: * print the nevigation bar at the bottom.
0383: */
0384: protected void navLinks(boolean header) {
0385: println("");
0386: if (!configuration.nonavbar) {
0387: if (header) {
0388: println(DocletConstants.NL
0389: + "<!-- ========= START OF TOP NAVBAR ======= -->");
0390: anchor("navbar_top");
0391: println();
0392: print(getHyperLink(
0393: "",
0394: "skip-navbar_top",
0395: "",
0396: false,
0397: "",
0398: configuration
0399: .getText("doclet.Skip_navigation_links"),
0400: ""));
0401: } else {
0402: println(DocletConstants.NL
0403: + "<!-- ======= START OF BOTTOM NAVBAR ====== -->");
0404: anchor("navbar_bottom");
0405: println();
0406: print(getHyperLink(
0407: "",
0408: "skip-navbar_bottom",
0409: "",
0410: false,
0411: "",
0412: configuration
0413: .getText("doclet.Skip_navigation_links"),
0414: ""));
0415: }
0416: table(0, "100%", 1, 0);
0417: tr();
0418: tdColspanBgcolorStyle(2, "#EEEEFF", "NavBarCell1");
0419: println("");
0420: if (header) {
0421: anchor("navbar_top_firstrow");
0422: } else {
0423: anchor("navbar_bottom_firstrow");
0424: }
0425: table(0, 0, 3);
0426: print(" ");
0427: trAlignVAlign("center", "top");
0428:
0429: if (configuration.createoverview) {
0430: navLinkContents();
0431: }
0432:
0433: if (configuration.packages.length == 1) {
0434: navLinkPackage(configuration.packages[0]);
0435: } else if (configuration.packages.length > 1) {
0436: navLinkPackage();
0437: }
0438:
0439: navLinkClass();
0440:
0441: if (configuration.classuse) {
0442: navLinkClassUse();
0443: }
0444: if (configuration.createtree) {
0445: navLinkTree();
0446: }
0447: if (!(configuration.nodeprecated || configuration.nodeprecatedlist)) {
0448: navLinkDeprecated();
0449: }
0450: if (configuration.createindex) {
0451: navLinkIndex();
0452: }
0453: if (!configuration.nohelp) {
0454: navLinkHelp();
0455: }
0456: print(" ");
0457: trEnd();
0458: tableEnd();
0459: tdEnd();
0460:
0461: tdAlignVAlignRowspan("right", "top", 3);
0462:
0463: printUserHeaderFooter(header);
0464: tdEnd();
0465: trEnd();
0466: println("");
0467:
0468: tr();
0469: tdBgcolorStyle("white", "NavBarCell2");
0470: font("-2");
0471: space();
0472: navLinkPrevious();
0473: space();
0474: println("");
0475: space();
0476: navLinkNext();
0477: fontEnd();
0478: tdEnd();
0479:
0480: tdBgcolorStyle("white", "NavBarCell2");
0481: font("-2");
0482: print(" ");
0483: navShowLists();
0484: print(" ");
0485: space();
0486: println("");
0487: space();
0488: navHideLists(filename);
0489: print(" ");
0490: space();
0491: println("");
0492: space();
0493: navLinkClassIndex();
0494: fontEnd();
0495: tdEnd();
0496:
0497: trEnd();
0498:
0499: printSummaryDetailLinks();
0500:
0501: tableEnd();
0502: if (header) {
0503: aName("skip-navbar_top");
0504: aEnd();
0505: println(DocletConstants.NL
0506: + "<!-- ========= END OF TOP NAVBAR ========= -->");
0507: } else {
0508: aName("skip-navbar_bottom");
0509: aEnd();
0510: println(DocletConstants.NL
0511: + "<!-- ======== END OF BOTTOM NAVBAR ======= -->");
0512: }
0513: println("");
0514: }
0515: }
0516:
0517: /**
0518: * Print the word "NEXT" to indicate that no link is available. Override
0519: * this method to customize next link.
0520: */
0521: protected void navLinkNext() {
0522: navLinkNext(null);
0523: }
0524:
0525: /**
0526: * Print the word "PREV" to indicate that no link is available. Override
0527: * this method to customize prev link.
0528: */
0529: protected void navLinkPrevious() {
0530: navLinkPrevious(null);
0531: }
0532:
0533: /**
0534: * Do nothing. This is the default method.
0535: */
0536: protected void printSummaryDetailLinks() {
0537: }
0538:
0539: /**
0540: * Print link to the "overview-summary.html" page.
0541: */
0542: protected void navLinkContents() {
0543: navCellStart();
0544: printHyperLink(relativePath + "overview-summary.html", "",
0545: configuration.getText("doclet.Overview"), true,
0546: "NavBarFont1");
0547: navCellEnd();
0548: }
0549:
0550: /**
0551: * Description for a cell in the navigation bar.
0552: */
0553: protected void navCellStart() {
0554: print(" ");
0555: tdBgcolorStyle("#EEEEFF", "NavBarCell1");
0556: print(" ");
0557: }
0558:
0559: /**
0560: * Description for a cell in the navigation bar, but with reverse
0561: * high-light effect.
0562: */
0563: protected void navCellRevStart() {
0564: print(" ");
0565: tdBgcolorStyle("#FFFFFF", "NavBarCell1Rev");
0566: print(" ");
0567: space();
0568: }
0569:
0570: /**
0571: * Closing tag for navigation bar cell.
0572: */
0573: protected void navCellEnd() {
0574: space();
0575: tdEnd();
0576: }
0577:
0578: /**
0579: * Print link to the "package-summary.html" page for the package passed.
0580: *
0581: * @param pkg Package to which link will be generated.
0582: */
0583: protected void navLinkPackage(PackageDoc pkg) {
0584: navCellStart();
0585: printPackageLink(pkg, configuration.getText("doclet.Package"),
0586: true, "NavBarFont1");
0587: navCellEnd();
0588: }
0589:
0590: /**
0591: * Print the word "Package" in the navigation bar cell, to indicate that
0592: * link is not available here.
0593: */
0594: protected void navLinkPackage() {
0595: navCellStart();
0596: fontStyle("NavBarFont1");
0597: printText("doclet.Package");
0598: fontEnd();
0599: navCellEnd();
0600: }
0601:
0602: /**
0603: * Print the word "Use" in the navigation bar cell, to indicate that link
0604: * is not available.
0605: */
0606: protected void navLinkClassUse() {
0607: navCellStart();
0608: fontStyle("NavBarFont1");
0609: printText("doclet.navClassUse");
0610: fontEnd();
0611: navCellEnd();
0612: }
0613:
0614: /**
0615: * Print link for previous file.
0616: *
0617: * @param prev File name for the prev link.
0618: */
0619: public void navLinkPrevious(String prev) {
0620: String tag = configuration.getText("doclet.Prev");
0621: if (prev != null) {
0622: printHyperLink(prev, "", tag, true);
0623: } else {
0624: print(tag);
0625: }
0626: }
0627:
0628: /**
0629: * Print link for next file. If next is null, just print the label
0630: * without linking it anywhere.
0631: *
0632: * @param next File name for the next link.
0633: */
0634: public void navLinkNext(String next) {
0635: String tag = configuration.getText("doclet.Next");
0636: if (next != null) {
0637: printHyperLink(next, "", tag, true);
0638: } else {
0639: print(tag);
0640: }
0641: }
0642:
0643: /**
0644: * Print "FRAMES" link, to switch to the frame version of the output.
0645: *
0646: * @param link File to be linked, "index.html".
0647: */
0648: protected void navShowLists(String link) {
0649: print(getHyperLink(link + "?" + path + filename, "",
0650: configuration.getText("doclet.FRAMES"), true, "", "",
0651: "_top"));
0652: }
0653:
0654: /**
0655: * Print "FRAMES" link, to switch to the frame version of the output.
0656: */
0657: protected void navShowLists() {
0658: navShowLists(relativePath + "index.html");
0659: }
0660:
0661: /**
0662: * Print "NO FRAMES" link, to switch to the non-frame version of the output.
0663: *
0664: * @param link File to be linked.
0665: */
0666: protected void navHideLists(String link) {
0667: print(getHyperLink(link, "", configuration
0668: .getText("doclet.NO_FRAMES"), true, "", "", "_top"));
0669: }
0670:
0671: /**
0672: * Print "Tree" link in the navigation bar. If there is only one package
0673: * specified on the command line, then the "Tree" link will be to the
0674: * only "package-tree.html" file otherwise it will be to the
0675: * "overview-tree.html" file.
0676: */
0677: protected void navLinkTree() {
0678: navCellStart();
0679: PackageDoc[] packages = configuration.root.specifiedPackages();
0680: if (packages.length == 1
0681: && configuration.root.specifiedClasses().length == 0) {
0682: printHyperLink(
0683: pathString(packages[0], "package-tree.html"), "",
0684: configuration.getText("doclet.Tree"), true,
0685: "NavBarFont1");
0686: } else {
0687: printHyperLink(relativePath + "overview-tree.html", "",
0688: configuration.getText("doclet.Tree"), true,
0689: "NavBarFont1");
0690: }
0691: navCellEnd();
0692: }
0693:
0694: /**
0695: * Print "Tree" link to the "overview-tree.html" file.
0696: */
0697: protected void navLinkMainTree(String label) {
0698: printHyperLink(relativePath + "overview-tree.html", label);
0699: }
0700:
0701: /**
0702: * Print the word "Class" in the navigation bar cell, to indicate that
0703: * class link is not available.
0704: */
0705: protected void navLinkClass() {
0706: navCellStart();
0707: fontStyle("NavBarFont1");
0708: printText("doclet.Class");
0709: fontEnd();
0710: navCellEnd();
0711: }
0712:
0713: /**
0714: * Print "Deprecated" API link in the navigation bar.
0715: */
0716: protected void navLinkDeprecated() {
0717: navCellStart();
0718: printHyperLink(relativePath + "deprecated-list.html", "",
0719: configuration.getText("doclet.navDeprecated"), true,
0720: "NavBarFont1");
0721: navCellEnd();
0722: }
0723:
0724: /**
0725: * Print link for generated index. If the user has used "-splitindex"
0726: * command line option, then link to file "index-files/index-1.html" is
0727: * generated otherwise link to file "index-all.html" is generated.
0728: */
0729: protected void navLinkClassIndex() {
0730: printNoFramesTargetHyperLink(relativePath
0731: + AllClassesFrameWriter.OUTPUT_FILE_NAME_NOFRAMES, "",
0732: "", configuration.getText("doclet.All_Classes"), true);
0733: }
0734:
0735: /**
0736: * Print link for generated class index.
0737: */
0738: protected void navLinkIndex() {
0739: navCellStart();
0740: printHyperLink(relativePath
0741: + (configuration.splitindex ? DirectoryManager
0742: .getPath("index-files")
0743: + fileseparator : "")
0744: + (configuration.splitindex ? "index-1.html"
0745: : "index-all.html"), "", configuration
0746: .getText("doclet.Index"), true, "NavBarFont1");
0747: navCellEnd();
0748: }
0749:
0750: /**
0751: * Print help file link. If user has provided a help file, then generate a
0752: * link to the user given file, which is already copied to current or
0753: * destination directory.
0754: */
0755: protected void navLinkHelp() {
0756: String helpfilenm = configuration.helpfile;
0757: if (helpfilenm.equals("")) {
0758: helpfilenm = "help-doc.html";
0759: } else {
0760: int lastsep;
0761: if ((lastsep = helpfilenm.lastIndexOf(File.separatorChar)) != -1) {
0762: helpfilenm = helpfilenm.substring(lastsep + 1);
0763: }
0764: }
0765: navCellStart();
0766: printHyperLink(relativePath + helpfilenm, "", configuration
0767: .getText("doclet.Help"), true, "NavBarFont1");
0768: navCellEnd();
0769: }
0770:
0771: /**
0772: * Print the word "Detail" in the navigation bar. No link is available.
0773: */
0774: protected void navDetail() {
0775: printText("doclet.Detail");
0776: }
0777:
0778: /**
0779: * Print the word "Summary" in the navigation bar. No link is available.
0780: */
0781: protected void navSummary() {
0782: printText("doclet.Summary");
0783: }
0784:
0785: /**
0786: * Print the Html table tag for the index summary tables. The table tag
0787: * printed is
0788: * <TABLE BORDER="1" CELLPADDING="3" CELLSPACING="0" WIDTH="100%">
0789: */
0790: public void tableIndexSummary() {
0791: table(1, "100%", 3, 0);
0792: }
0793:
0794: /**
0795: * Same as {@link #tableIndexSummary()}.
0796: */
0797: public void tableIndexDetail() {
0798: table(1, "100%", 3, 0);
0799: }
0800:
0801: /**
0802: * Print Html tag for table elements. The tag printed is
0803: * <TD ALIGN="right" VALIGN="top" WIDTH="1%">.
0804: */
0805: public void tdIndex() {
0806: print("<TD ALIGN=\"right\" VALIGN=\"top\" WIDTH=\"1%\">");
0807: }
0808:
0809: /**
0810: * Prine table header information about color, column span and the font.
0811: *
0812: * @param color Background color.
0813: * @param span Column span.
0814: */
0815: public void tableHeaderStart(String color, int span) {
0816: trBgcolorStyle(color, "TableHeadingColor");
0817: thAlignColspan("left", span);
0818: font("+2");
0819: }
0820:
0821: /**
0822: * Print table header for the inherited members summary tables. Print the
0823: * background color information.
0824: *
0825: * @param color Background color.
0826: */
0827: public void tableInheritedHeaderStart(String color) {
0828: trBgcolorStyle(color, "TableSubHeadingColor");
0829: thAlign("left");
0830: }
0831:
0832: /**
0833: * Print "Use" table header. Print the background color and the column span.
0834: *
0835: * @param color Background color.
0836: */
0837: public void tableUseInfoHeaderStart(String color) {
0838: trBgcolorStyle(color, "TableSubHeadingColor");
0839: thAlignColspan("left", 2);
0840: }
0841:
0842: /**
0843: * Print table header with the background color with default column span 2.
0844: *
0845: * @param color Background color.
0846: */
0847: public void tableHeaderStart(String color) {
0848: tableHeaderStart(color, 2);
0849: }
0850:
0851: /**
0852: * Print table header with the column span, with the default color #CCCCFF.
0853: *
0854: * @param span Column span.
0855: */
0856: public void tableHeaderStart(int span) {
0857: tableHeaderStart("#CCCCFF", span);
0858: }
0859:
0860: /**
0861: * Print table header with default column span 2 and default color #CCCCFF.
0862: */
0863: public void tableHeaderStart() {
0864: tableHeaderStart(2);
0865: }
0866:
0867: /**
0868: * Print table header end tags for font, column and row.
0869: */
0870: public void tableHeaderEnd() {
0871: fontEnd();
0872: thEnd();
0873: trEnd();
0874: }
0875:
0876: /**
0877: * Print table header end tags in inherited tables for column and row.
0878: */
0879: public void tableInheritedHeaderEnd() {
0880: thEnd();
0881: trEnd();
0882: }
0883:
0884: /**
0885: * Print the summary table row cell attribute width.
0886: *
0887: * @param width Width of the table cell.
0888: */
0889: public void summaryRow(int width) {
0890: if (width != 0) {
0891: tdWidth(width + "%");
0892: } else {
0893: td();
0894: }
0895: }
0896:
0897: /**
0898: * Print the summary table row cell end tag.
0899: */
0900: public void summaryRowEnd() {
0901: tdEnd();
0902: }
0903:
0904: /**
0905: * Print the heading in Html <H2> format.
0906: *
0907: * @param str The Header string.
0908: */
0909: public void printIndexHeading(String str) {
0910: h2();
0911: print(str);
0912: h2End();
0913: }
0914:
0915: /**
0916: * Print Html tag <FRAMESET=arg>.
0917: *
0918: * @param arg Argument for the tag.
0919: */
0920: public void frameSet(String arg) {
0921: println("<FRAMESET " + arg + ">");
0922: }
0923:
0924: /**
0925: * Print Html closing tag </FRAMESET>.
0926: */
0927: public void frameSetEnd() {
0928: println("</FRAMESET>");
0929: }
0930:
0931: /**
0932: * Print Html tag <FRAME=arg>.
0933: *
0934: * @param arg Argument for the tag.
0935: */
0936: public void frame(String arg) {
0937: println("<FRAME " + arg + ">");
0938: }
0939:
0940: /**
0941: * Print Html closing tag </FRAME>.
0942: */
0943: public void frameEnd() {
0944: println("</FRAME>");
0945: }
0946:
0947: /**
0948: * Return path to the class page for a classdoc. For example, the class
0949: * name is "java.lang.Object" and if the current file getting generated is
0950: * "java/io/File.html", then the path string to the class, returned is
0951: * "../../java/lang.Object.html".
0952: *
0953: * @param cd Class to which the path is requested.
0954: */
0955: protected String pathToClass(ClassDoc cd) {
0956: return pathString(cd.containingPackage(), cd.name() + ".html");
0957: }
0958:
0959: /**
0960: * Return the path to the class page for a classdoc. Works same as
0961: * {@link #pathToClass(ClassDoc)}.
0962: *
0963: * @param cd Class to which the path is requested.
0964: * @param name Name of the file(doesn't include path).
0965: */
0966: protected String pathString(ClassDoc cd, String name) {
0967: return pathString(cd.containingPackage(), name);
0968: }
0969:
0970: /**
0971: * Return path to the given file name in the given package. So if the name
0972: * passed is "Object.html" and the name of the package is "java.lang", and
0973: * if the relative path is "../.." then returned string will be
0974: * "../../java/lang/Object.html"
0975: *
0976: * @param pd Package in which the file name is assumed to be.
0977: * @param name File name, to which path string is.
0978: */
0979: protected String pathString(PackageDoc pd, String name) {
0980: StringBuffer buf = new StringBuffer(relativePath);
0981: buf.append(DirectoryManager.getPathToPackage(pd, name));
0982: return buf.toString();
0983: }
0984:
0985: /**
0986: * Print the link to the given package.
0987: *
0988: * @param pkg the package to link to.
0989: * @param label the label for the link.
0990: * @param isBold true if the label should be bold.
0991: */
0992: public void printPackageLink(PackageDoc pkg, String label,
0993: boolean isBold) {
0994: print(getPackageLink(pkg, label, isBold));
0995: }
0996:
0997: /**
0998: * Print the link to the given package.
0999: *
1000: * @param pkg the package to link to.
1001: * @param label the label for the link.
1002: * @param isBold true if the label should be bold.
1003: * @param style the font of the package link label.
1004: */
1005: public void printPackageLink(PackageDoc pkg, String label,
1006: boolean isBold, String style) {
1007: print(getPackageLink(pkg, label, isBold, style));
1008: }
1009:
1010: /**
1011: * Return the link to the given package.
1012: *
1013: * @param pkg the package to link to.
1014: * @param label the label for the link.
1015: * @param isBold true if the label should be bold.
1016: * @return the link to the given package.
1017: */
1018: public String getPackageLink(PackageDoc pkg, String label,
1019: boolean isBold) {
1020: return getPackageLink(pkg, label, isBold, "");
1021: }
1022:
1023: /**
1024: * Return the link to the given package.
1025: *
1026: * @param pkg the package to link to.
1027: * @param label the label for the link.
1028: * @param isBold true if the label should be bold.
1029: * @param style the font of the package link label.
1030: * @return the link to the given package.
1031: */
1032: public String getPackageLink(PackageDoc pkg, String label,
1033: boolean isBold, String style) {
1034: boolean included = pkg != null && pkg.isIncluded();
1035: if (!included) {
1036: PackageDoc[] packages = configuration.packages;
1037: for (int i = 0; i < packages.length; i++) {
1038: if (packages[i].equals(pkg)) {
1039: included = true;
1040: break;
1041: }
1042: }
1043: }
1044: if (included || pkg == null) {
1045: return getHyperLink(
1046: pathString(pkg, "package-summary.html"), "", label,
1047: isBold, style);
1048: } else {
1049: String crossPkgLink = getCrossPackageLink(Util
1050: .getPackageName(pkg));
1051: if (crossPkgLink != null) {
1052: return getHyperLink(crossPkgLink, "", label, isBold,
1053: style);
1054: } else {
1055: return label;
1056: }
1057: }
1058: }
1059:
1060: public String italicsClassName(ClassDoc cd, boolean qual) {
1061: String name = (qual) ? cd.qualifiedName() : cd.name();
1062: return (cd.isInterface()) ? italicsText(name) : name;
1063: }
1064:
1065: public void printSrcLink(ProgramElementDoc d, String label) {
1066: if (d == null) {
1067: return;
1068: }
1069: ClassDoc cd = d.containingClass();
1070: if (cd == null) {
1071: //d must be a class doc since in has no containing class.
1072: cd = (ClassDoc) d;
1073: }
1074: String href = relativePath
1075: + DocletConstants.SOURCE_OUTPUT_DIR_NAME
1076: + DirectoryManager.getDirectoryPath(cd
1077: .containingPackage()) + cd.name() + ".html#"
1078: + SourceToHTMLConverter.getAnchorName(d);
1079: printHyperLink(href, "", label, true);
1080: }
1081:
1082: /**
1083: * Return the link to the given class.
1084: *
1085: * @param linkInfo the information about the link.
1086: *
1087: * @return the link for the given class.
1088: */
1089: public String getLink(LinkInfoImpl linkInfo) {
1090: LinkFactoryImpl factory = new LinkFactoryImpl(this );
1091: String link = ((LinkOutputImpl) factory.getLinkOutput(linkInfo))
1092: .toString();
1093: displayLength += linkInfo.displayLength;
1094: return link;
1095: }
1096:
1097: /**
1098: * Return the type parameters for the given class.
1099: *
1100: * @param linkInfo the information about the link.
1101: * @return the type for the given class.
1102: */
1103: public String getTypeParameterLinks(LinkInfoImpl linkInfo) {
1104: LinkFactoryImpl factory = new LinkFactoryImpl(this );
1105: return ((LinkOutputImpl) factory.getTypeParameterLinks(
1106: linkInfo, false)).toString();
1107: }
1108:
1109: /**
1110: * Print the link to the given class.
1111: */
1112: public void printLink(LinkInfoImpl linkInfo) {
1113: print(getLink(linkInfo));
1114: }
1115:
1116: /*************************************************************
1117: * Return a class cross link to external class documentation.
1118: * The name must be fully qualified to determine which package
1119: * the class is in. The -link option does not allow users to
1120: * link to external classes in the "default" package.
1121: *
1122: * @param qualifiedClassName the qualified name of the external class.
1123: * @param refMemName the name of the member being referenced. This should
1124: * be null or empty string if no member is being referenced.
1125: * @param label the label for the external link.
1126: * @param bold true if the link should be bold.
1127: * @param style the style of the link.
1128: * @param code true if the label should be code font.
1129: */
1130: public String getCrossClassLink(String qualifiedClassName,
1131: String refMemName, String label, boolean bold,
1132: String style, boolean code) {
1133: String className = "", packageName = qualifiedClassName == null ? ""
1134: : qualifiedClassName;
1135: int periodIndex;
1136: while ((periodIndex = packageName.lastIndexOf('.')) != -1) {
1137: className = packageName.substring(periodIndex + 1,
1138: packageName.length())
1139: + (className.length() > 0 ? "." + className : "");
1140: String defaultLabel = code ? getCode() + className
1141: + getCodeEnd() : className;
1142: packageName = packageName.substring(0, periodIndex);
1143: if (getCrossPackageLink(packageName) != null) {
1144: //The package exists in external documentation, so link to the external
1145: //class (assuming that it exists). This is definitely a limitation of
1146: //the -link option. There are ways to determine if an external package
1147: //exists, but no way to determine if the external class exists. We just
1148: //have to assume that it does.
1149: return getHyperLink(
1150: configuration.extern.getExternalLink(
1151: packageName, relativePath, className
1152: + ".html?is-external=true"),
1153: refMemName == null ? "" : refMemName,
1154: label == null || label.length() == 0 ? defaultLabel
1155: : label, bold, style,
1156: configuration.getText(
1157: "doclet.Href_Class_Or_Interface_Title",
1158: packageName), "");
1159: }
1160: }
1161: return null;
1162: }
1163:
1164: public boolean isClassLinkable(ClassDoc cd) {
1165: if (cd.isIncluded()) {
1166: return configuration.isGeneratedDoc(cd);
1167: }
1168: return configuration.extern.isExternal(cd);
1169: }
1170:
1171: public String getCrossPackageLink(String pkgName) {
1172: return configuration.extern.getExternalLink(pkgName,
1173: relativePath, "package-summary.html?is-external=true");
1174: }
1175:
1176: public void printQualifiedClassLink(int context, ClassDoc cd) {
1177: printLink(new LinkInfoImpl(context, cd, configuration
1178: .getClassName(cd), ""));
1179: }
1180:
1181: /**
1182: * Print Class link, with only class name as the link and prefixing
1183: * plain package name.
1184: */
1185: public void printPreQualifiedClassLink(int context, ClassDoc cd) {
1186: print(getPreQualifiedClassLink(context, cd, false));
1187: }
1188:
1189: /**
1190: * Retrieve the class link with the package portion of the label in
1191: * plain text. If the qualifier is excluded, it willnot be included in the
1192: * link label.
1193: *
1194: * @param cd the class to link to.
1195: * @param isBold true if the link should be bold.
1196: * @return the link with the package portion of the label in plain text.
1197: */
1198: public String getPreQualifiedClassLink(int context, ClassDoc cd,
1199: boolean isBold) {
1200: String classlink = "";
1201: PackageDoc pd = cd.containingPackage();
1202: if (pd != null
1203: && !configuration.shouldExcludeQualifier(pd.name())) {
1204: classlink = getPkgName(cd);
1205: }
1206: classlink += getLink(new LinkInfoImpl(context, cd, cd.name(),
1207: isBold));
1208: return classlink;
1209: }
1210:
1211: /**
1212: * Print Class link, with only class name as the bold link and prefixing
1213: * plain package name.
1214: */
1215: public void printPreQualifiedBoldClassLink(int context, ClassDoc cd) {
1216: print(getPreQualifiedClassLink(context, cd, true));
1217: }
1218:
1219: public void printText(String key) {
1220: print(configuration.getText(key));
1221: }
1222:
1223: public void printText(String key, String a1) {
1224: print(configuration.getText(key, a1));
1225: }
1226:
1227: public void printText(String key, String a1, String a2) {
1228: print(configuration.getText(key, a1, a2));
1229: }
1230:
1231: public void boldText(String key) {
1232: bold(configuration.getText(key));
1233: }
1234:
1235: public void boldText(String key, String a1) {
1236: bold(configuration.getText(key, a1));
1237: }
1238:
1239: public void boldText(String key, String a1, String a2) {
1240: bold(configuration.getText(key, a1, a2));
1241: }
1242:
1243: /**
1244: * Print the link for the given member.
1245: *
1246: * @param context the id of the context where the link will be printed.
1247: * @param doc the member being linked to.
1248: * @param label the label for the link.
1249: * @param bold true if the link should be bold.
1250: */
1251: public void printDocLink(int context, MemberDoc doc, String label,
1252: boolean bold) {
1253: print(getDocLink(context, doc, label, bold));
1254: }
1255:
1256: /**
1257: * Print the link for the given member.
1258: *
1259: * @param context the id of the context where the link will be printed.
1260: * @param classDoc the classDoc that we should link to. This is not
1261: * necessarily equal to doc.containingClass(). We may be
1262: * inheriting comments.
1263: * @param doc the member being linked to.
1264: * @param label the label for the link.
1265: * @param bold true if the link should be bold.
1266: */
1267: public void printDocLink(int context, ClassDoc classDoc,
1268: MemberDoc doc, String label, boolean bold) {
1269: print(getDocLink(context, classDoc, doc, label, bold));
1270: }
1271:
1272: /**
1273: * Return the link for the given member.
1274: *
1275: * @param context the id of the context where the link will be printed.
1276: * @param doc the member being linked to.
1277: * @param label the label for the link.
1278: * @param bold true if the link should be bold.
1279: * @return the link for the given member.
1280: */
1281: public String getDocLink(int context, MemberDoc doc, String label,
1282: boolean bold) {
1283: return getDocLink(context, doc.containingClass(), doc, label,
1284: bold);
1285: }
1286:
1287: /**
1288: * Return the link for the given member.
1289: *
1290: * @param context the id of the context where the link will be printed.
1291: * @param classDoc the classDoc that we should link to. This is not
1292: * necessarily equal to doc.containingClass(). We may be
1293: * inheriting comments.
1294: * @param doc the member being linked to.
1295: * @param label the label for the link.
1296: * @param bold true if the link should be bold.
1297: * @return the link for the given member.
1298: */
1299: public String getDocLink(int context, ClassDoc classDoc,
1300: MemberDoc doc, String label, boolean bold) {
1301: if (!(doc.isIncluded() || Util.isLinkable(classDoc,
1302: configuration()))) {
1303: return label;
1304: } else if (doc instanceof ExecutableMemberDoc) {
1305: ExecutableMemberDoc emd = (ExecutableMemberDoc) doc;
1306: return getLink(new LinkInfoImpl(context, classDoc,
1307: getAnchor(emd), label, bold));
1308: } else if (doc instanceof MemberDoc) {
1309: return getLink(new LinkInfoImpl(context, classDoc, doc
1310: .name(), label, bold));
1311: } else {
1312: return label;
1313: }
1314: }
1315:
1316: public void anchor(ExecutableMemberDoc emd) {
1317: anchor(getAnchor(emd));
1318: }
1319:
1320: public String getAnchor(ExecutableMemberDoc emd) {
1321: StringBuilder signature = new StringBuilder(emd.signature());
1322: StringBuilder signatureParsed = new StringBuilder();
1323: int counter = 0;
1324: for (int i = 0; i < signature.length(); i++) {
1325: char c = signature.charAt(i);
1326: if (c == '<') {
1327: counter++;
1328: } else if (c == '>') {
1329: counter--;
1330: } else if (counter == 0) {
1331: signatureParsed.append(c);
1332: }
1333: }
1334: return emd.name() + signatureParsed.toString();
1335: }
1336:
1337: public String seeTagToString(SeeTag see) {
1338: String tagName = see.name();
1339: if (!(tagName.startsWith("@link") || tagName.equals("@see"))) {
1340: return "";
1341: }
1342: StringBuffer result = new StringBuffer();
1343: boolean isplaintext = tagName.toLowerCase()
1344: .equals("@linkplain");
1345: String label = see.label();
1346: label = (label.length() > 0) ? ((isplaintext) ? label
1347: : getCode() + label + getCodeEnd()) : "";
1348: String seetext = replaceDocRootDir(see.text());
1349:
1350: //Check if @see is an href or "string"
1351: if (seetext.startsWith("<") || seetext.startsWith("\"")) {
1352: result.append(seetext);
1353: return result.toString();
1354: }
1355:
1356: //The text from the @see tag. We will output this text when a label is not specified.
1357: String text = (isplaintext) ? seetext : getCode() + seetext
1358: + getCodeEnd();
1359:
1360: ClassDoc refClass = see.referencedClass();
1361: String refClassName = see.referencedClassName();
1362: MemberDoc refMem = see.referencedMember();
1363: String refMemName = see.referencedMemberName();
1364: if (refClass == null) {
1365: //@see is not referencing an included class
1366: PackageDoc refPackage = see.referencedPackage();
1367: if (refPackage != null && refPackage.isIncluded()) {
1368: //@see is referencing an included package
1369: String packageName = isplaintext ? refPackage.name()
1370: : getCode() + refPackage.name() + getCodeEnd();
1371: result.append(getPackageLink(refPackage,
1372: label.length() == 0 ? packageName : label,
1373: false));
1374: } else {
1375: //@see is not referencing an included class or package. Check for cross links.
1376: String classCrossLink, packageCrossLink = getCrossPackageLink(refClassName);
1377: if (packageCrossLink != null) {
1378: //Package cross link found
1379: result
1380: .append(getHyperLink(packageCrossLink, "",
1381: (label.length() == 0) ? text
1382: : label, false));
1383: } else if ((classCrossLink = getCrossClassLink(
1384: refClassName, refMemName, label, false, "",
1385: !isplaintext)) != null) {
1386: //Class cross link found (possiblly to a member in the class)
1387: result.append(classCrossLink);
1388: } else {
1389: //No cross link found so print warning
1390: configuration.getDocletSpecificMsg().warning(
1391: see.position(),
1392: "doclet.see.class_or_package_not_found",
1393: tagName, seetext);
1394: result.append((label.length() == 0) ? text : label);
1395: }
1396: }
1397: } else if (refMemName == null) {
1398: // Must be a class reference since refClass is not null and refMemName is null.
1399: if (label.length() == 0) {
1400: label = (isplaintext) ? refClass.name() : getCode()
1401: + refClass.name() + getCodeEnd();
1402: result
1403: .append(getLink(new LinkInfoImpl(refClass,
1404: label)));
1405: } else {
1406: result
1407: .append(getLink(new LinkInfoImpl(refClass,
1408: label)));
1409: }
1410: } else if (refMem == null) {
1411: // Must be a member reference since refClass is not null and refMemName is not null.
1412: // However, refMem is null, so this referenced member does not exist.
1413: result.append((label.length() == 0) ? text : label);
1414: } else {
1415: // Must be a member reference since refClass is not null and refMemName is not null.
1416: // refMem is not null, so this @see tag must be referencing a valid member.
1417: ClassDoc containing = refMem.containingClass();
1418: if (see.text().trim().startsWith("#")
1419: && !(containing.isPublic() || Util.isLinkable(
1420: containing, configuration()))) {
1421: // Since the link is relative and the holder is not even being
1422: // documented, this must be an inherited link. Redirect it.
1423: // The current class either overrides the referenced member or
1424: // inherits it automatically.
1425: containing = ((ClassWriterImpl) this ).getClassDoc();
1426: }
1427: if (configuration.currentcd != containing) {
1428: refMemName = containing.name() + "." + refMemName;
1429: }
1430: if (refMem instanceof ExecutableMemberDoc) {
1431: if (refMemName.indexOf('(') < 0) {
1432: refMemName += ((ExecutableMemberDoc) refMem)
1433: .signature();
1434: }
1435: }
1436: text = (isplaintext) ? refMemName : getCode() + refMemName
1437: + getCodeEnd();
1438:
1439: result.append(getDocLink(LinkInfoImpl.CONTEXT_SEE_TAG,
1440: containing, refMem, (label.length() == 0) ? text
1441: : label, false));
1442: }
1443: return result.toString();
1444: }
1445:
1446: public void printInlineComment(Doc doc, Tag tag) {
1447: printCommentTags(doc, tag.inlineTags(), false, false);
1448: }
1449:
1450: public void printInlineDeprecatedComment(Doc doc, Tag tag) {
1451: printCommentTags(doc, tag.inlineTags(), true, false);
1452: }
1453:
1454: public void printSummaryComment(Doc doc) {
1455: printSummaryComment(doc, doc.firstSentenceTags());
1456: }
1457:
1458: public void printSummaryComment(Doc doc, Tag[] firstSentenceTags) {
1459: printCommentTags(doc, firstSentenceTags, false, true);
1460: }
1461:
1462: public void printSummaryDeprecatedComment(Doc doc) {
1463: printCommentTags(doc, doc.firstSentenceTags(), true, true);
1464: }
1465:
1466: public void printSummaryDeprecatedComment(Doc doc, Tag tag) {
1467: printCommentTags(doc, tag.firstSentenceTags(), true, true);
1468: }
1469:
1470: public void printInlineComment(Doc doc) {
1471: printCommentTags(doc, doc.inlineTags(), false, false);
1472: p();
1473: }
1474:
1475: public void printInlineDeprecatedComment(Doc doc) {
1476: printCommentTags(doc, doc.inlineTags(), true, false);
1477: }
1478:
1479: private void printCommentTags(Doc doc, Tag[] tags, boolean depr,
1480: boolean first) {
1481: if (configuration.nocomment) {
1482: return;
1483: }
1484: if (depr) {
1485: italic();
1486: }
1487: String result = commentTagsToString(null, doc, tags, first);
1488: print(result);
1489: if (depr) {
1490: italicEnd();
1491: }
1492: if (tags.length == 0) {
1493: space();
1494: }
1495: }
1496:
1497: /**
1498: * Converts inline tags and text to text strings, expanding the
1499: * inline tags along the way. Called wherever text can contain
1500: * an inline tag, such as in comments or in free-form text arguments
1501: * to non-inline tags.
1502: *
1503: * @param holderTag specific tag where comment resides
1504: * @param doc specific doc where comment resides
1505: * @param tags array of text tags and inline tags (often alternating)
1506: * present in the text of interest for this doc
1507: * @param isFirstSentence true if text is first sentence
1508: */
1509: public String commentTagsToString(Tag holderTag, Doc doc,
1510: Tag[] tags, boolean isFirstSentence) {
1511: StringBuffer result = new StringBuffer();
1512: // Array of all possible inline tags for this javadoc run
1513: configuration.tagletManager.checkTags(doc, tags, true);
1514: for (int i = 0; i < tags.length; i++) {
1515: Tag tagelem = tags[i];
1516: String tagName = tagelem.name();
1517: if (tagelem instanceof SeeTag) {
1518: result.append(seeTagToString((SeeTag) tagelem));
1519: } else if (!tagName.equals("Text")) {
1520: int originalLength = result.length();
1521: TagletOutput output = TagletWriter.getInlineTagOuput(
1522: configuration.tagletManager, holderTag,
1523: (Tag) tagelem,
1524: getTagletWriterInstance(isFirstSentence));
1525: result.append(output == null ? "" : output.toString());
1526: if (originalLength == 0 && isFirstSentence
1527: && tagelem.name().equals("@inheritDoc")
1528: && result.length() > 0) {
1529: break;
1530: } else {
1531: continue;
1532: }
1533: } else {
1534: //This is just a regular text tag. The text may contain html links (<a>)
1535: //or inline tag {@docRoot}, which will be handled as special cases.
1536: String text = redirectRelativeLinks(tagelem.holder(),
1537: tagelem.text());
1538:
1539: // Replace @docRoot only if not represented by an instance of DocRootTaglet,
1540: // that is, only if it was not present in a source file doc comment.
1541: // This happens when inserted by the doclet (a few lines
1542: // above in this method). [It might also happen when passed in on the command
1543: // line as a text argument to an option (like -header).]
1544: text = replaceDocRootDir(text);
1545: if (isFirstSentence) {
1546: text = removeNonInlineHtmlTags(text);
1547: }
1548: StringTokenizer lines = new StringTokenizer(text,
1549: "\r\n", true);
1550: StringBuffer textBuff = new StringBuffer();
1551: while (lines.hasMoreTokens()) {
1552: StringBuffer line = new StringBuffer(lines
1553: .nextToken());
1554: Util.replaceTabs(configuration.sourcetab, line);
1555: textBuff.append(line.toString());
1556: }
1557: result.append(textBuff);
1558: }
1559: }
1560: return result.toString();
1561: }
1562:
1563: /**
1564: * Return true if relative links should not be redirected.
1565: *
1566: * @return Return true if a relative link should not be redirected.
1567: */
1568: private boolean shouldNotRedirectRelativeLinks() {
1569: return this instanceof AnnotationTypeWriter
1570: || this instanceof ClassWriter
1571: || this instanceof PackageSummaryWriter;
1572: }
1573:
1574: /**
1575: * Suppose a piece of documentation has a relative link. When you copy
1576: * that documetation to another place such as the index or class-use page,
1577: * that relative link will no longer work. We should redirect those links
1578: * so that they will work again.
1579: * <p>
1580: * Here is the algorithm used to fix the link:
1581: * <p>
1582: * <relative link> => docRoot + <relative path to file> + <relative link>
1583: * <p>
1584: * For example, suppose com.sun.javadoc.RootDoc has this link:
1585: * <a href="package-summary.html">The package Page</a>
1586: * <p>
1587: * If this link appeared in the index, we would redirect
1588: * the link like this:
1589: *
1590: * <a href="./com/sun/javadoc/package-summary.html">The package Page</a>
1591: *
1592: * @param doc the Doc object whose documentation is being written.
1593: * @param text the text being written.
1594: *
1595: * @return the text, with all the relative links redirected to work.
1596: */
1597: private String redirectRelativeLinks(Doc doc, String text) {
1598: if (doc == null || shouldNotRedirectRelativeLinks()) {
1599: return text;
1600: }
1601:
1602: String redirectPathFromRoot;
1603: if (doc instanceof ClassDoc) {
1604: redirectPathFromRoot = DirectoryManager
1605: .getDirectoryPath(((ClassDoc) doc)
1606: .containingPackage());
1607: } else if (doc instanceof MemberDoc) {
1608: redirectPathFromRoot = DirectoryManager
1609: .getDirectoryPath(((MemberDoc) doc)
1610: .containingPackage());
1611: } else if (doc instanceof PackageDoc) {
1612: redirectPathFromRoot = DirectoryManager
1613: .getDirectoryPath((PackageDoc) doc);
1614: } else {
1615: return text;
1616: }
1617:
1618: if (!redirectPathFromRoot
1619: .endsWith(DirectoryManager.URL_FILE_SEPERATOR)) {
1620: redirectPathFromRoot += DirectoryManager.URL_FILE_SEPERATOR;
1621: }
1622:
1623: //Redirect all relative links.
1624: int end, begin = text.toLowerCase().indexOf("<a");
1625: if (begin >= 0) {
1626: StringBuffer textBuff = new StringBuffer(text);
1627:
1628: while (begin >= 0) {
1629: if (textBuff.length() > begin + 2
1630: && !Character.isWhitespace(textBuff
1631: .charAt(begin + 2))) {
1632: begin = textBuff.toString().toLowerCase().indexOf(
1633: "<a", begin + 1);
1634: continue;
1635: }
1636:
1637: begin = textBuff.indexOf("=", begin) + 1;
1638: end = textBuff.indexOf(">", begin + 1);
1639: if (begin == 0) {
1640: //Link has no equal symbol.
1641: configuration.root.printWarning(doc.position(),
1642: configuration.getText(
1643: "doclet.malformed_html_link_tag",
1644: text));
1645: break;
1646: }
1647: if (end == -1) {
1648: //Break without warning. This <a> tag is not necessarily malformed. The text
1649: //might be missing '>' character because the href has an inline tag.
1650: break;
1651: }
1652: if (textBuff.substring(begin, end).indexOf("\"") != -1) {
1653: begin = textBuff.indexOf("\"", begin) + 1;
1654: end = textBuff.indexOf("\"", begin + 1);
1655: if (begin == 0 || end == -1) {
1656: //Link is missing a quote.
1657: break;
1658: }
1659: }
1660: String relativeLink = textBuff.substring(begin, end);
1661: if (!(relativeLink.toLowerCase().startsWith("mailto:")
1662: || relativeLink.toLowerCase().startsWith(
1663: "http:")
1664: || relativeLink.toLowerCase().startsWith(
1665: "https:") || relativeLink.toLowerCase()
1666: .startsWith("file:"))) {
1667: relativeLink = "{@"
1668: + (new DocRootTaglet()).getName() + "}"
1669: + redirectPathFromRoot + relativeLink;
1670: textBuff.replace(begin, end, relativeLink);
1671: }
1672: begin = textBuff.toString().toLowerCase().indexOf("<a",
1673: begin + 1);
1674: }
1675: return textBuff.toString();
1676: }
1677: return text;
1678: }
1679:
1680: public String removeNonInlineHtmlTags(String text) {
1681: if (text.indexOf('<') < 0) {
1682: return text;
1683: }
1684: String noninlinetags[] = { "<ul>", "</ul>", "<ol>", "</ol>",
1685: "<dl>", "</dl>", "<table>", "</table>", "<tr>",
1686: "</tr>", "<td>", "</td>", "<th>", "</th>", "<p>",
1687: "</p>", "<li>", "</li>", "<dd>", "</dd>", "<dir>",
1688: "</dir>", "<dt>", "</dt>", "<h1>", "</h1>", "<h2>",
1689: "</h2>", "<h3>", "</h3>", "<h4>", "</h4>", "<h5>",
1690: "</h5>", "<h6>", "</h6>", "<pre>", "</pre>", "<menu>",
1691: "</menu>", "<listing>", "</listing>", "<hr>",
1692: "<blockquote>", "</blockquote>", "<center>",
1693: "</center>", "<UL>", "</UL>", "<OL>", "</OL>", "<DL>",
1694: "</DL>", "<TABLE>", "</TABLE>", "<TR>", "</TR>",
1695: "<TD>", "</TD>", "<TH>", "</TH>", "<P>", "</P>",
1696: "<LI>", "</LI>", "<DD>", "</DD>", "<DIR>", "</DIR>",
1697: "<DT>", "</DT>", "<H1>", "</H1>", "<H2>", "</H2>",
1698: "<H3>", "</H3>", "<H4>", "</H4>", "<H5>", "</H5>",
1699: "<H6>", "</H6>", "<PRE>", "</PRE>", "<MENU>",
1700: "</MENU>", "<LISTING>", "</LISTING>", "<HR>",
1701: "<BLOCKQUOTE>", "</BLOCKQUOTE>", "<CENTER>",
1702: "</CENTER>" };
1703: for (int i = 0; i < noninlinetags.length; i++) {
1704: text = replace(text, noninlinetags[i], "");
1705: }
1706: return text;
1707: }
1708:
1709: public String replace(String text, String tobe, String by) {
1710: while (true) {
1711: int startindex = text.indexOf(tobe);
1712: if (startindex < 0) {
1713: return text;
1714: }
1715: int endindex = startindex + tobe.length();
1716: StringBuffer replaced = new StringBuffer();
1717: if (startindex > 0) {
1718: replaced.append(text.substring(0, startindex));
1719: }
1720: replaced.append(by);
1721: if (text.length() > endindex) {
1722: replaced.append(text.substring(endindex));
1723: }
1724: text = replaced.toString();
1725: }
1726: }
1727:
1728: public void printStyleSheetProperties() {
1729: String filename = configuration.stylesheetfile;
1730: if (filename.length() > 0) {
1731: File stylefile = new File(filename);
1732: String parent = stylefile.getParent();
1733: filename = (parent == null) ? filename : filename
1734: .substring(parent.length() + 1);
1735: } else {
1736: filename = "stylesheet.css";
1737: }
1738: filename = relativePath + filename;
1739: link("REL =\"stylesheet\" TYPE=\"text/css\" HREF=\"" + filename
1740: + "\" " + "TITLE=\"Style\"");
1741: }
1742:
1743: /**
1744: * According to the Java Language Specifications, all the outer classes
1745: * and static nested classes are core classes.
1746: */
1747: public boolean isCoreClass(ClassDoc cd) {
1748: return cd.containingClass() == null || cd.isStatic();
1749: }
1750:
1751: /**
1752: * Write the annotatation types for the given packageDoc.
1753: *
1754: * @param packageDoc the package to write annotations for.
1755: */
1756: public void writeAnnotationInfo(PackageDoc packageDoc) {
1757: writeAnnotationInfo(packageDoc, packageDoc.annotations());
1758: }
1759:
1760: /**
1761: * Write the annotatation types for the given doc.
1762: *
1763: * @param doc the doc to write annotations for.
1764: */
1765: public void writeAnnotationInfo(ProgramElementDoc doc) {
1766: writeAnnotationInfo(doc, doc.annotations());
1767: }
1768:
1769: /**
1770: * Write the annotatation types for the given doc and parameter.
1771: *
1772: * @param indent the number of spaced to indent the parameters.
1773: * @param doc the doc to write annotations for.
1774: * @param param the parameter to write annotations for.
1775: */
1776: public boolean writeAnnotationInfo(int indent, Doc doc,
1777: Parameter param) {
1778: return writeAnnotationInfo(indent, doc, param.annotations(),
1779: false);
1780: }
1781:
1782: /**
1783: * Write the annotatation types for the given doc.
1784: *
1785: * @param doc the doc to write annotations for.
1786: * @param descList the array of {@link AnnotationDesc}.
1787: */
1788: private void writeAnnotationInfo(Doc doc, AnnotationDesc[] descList) {
1789: writeAnnotationInfo(0, doc, descList, true);
1790: }
1791:
1792: /**
1793: * Write the annotatation types for the given doc.
1794: *
1795: * @param indent the number of extra spaces to indent the annotations.
1796: * @param doc the doc to write annotations for.
1797: * @param descList the array of {@link AnnotationDesc}.
1798: */
1799: private boolean writeAnnotationInfo(int indent, Doc doc,
1800: AnnotationDesc[] descList, boolean lineBreak) {
1801: List annotations = getAnnotations(indent, descList, lineBreak);
1802: if (annotations.size() == 0) {
1803: return false;
1804: }
1805: fontNoNewLine("-1");
1806: for (Iterator iter = annotations.iterator(); iter.hasNext();) {
1807: print((String) iter.next());
1808: }
1809: fontEnd();
1810: return true;
1811: }
1812:
1813: /**
1814: * Return the string representations of the annotation types for
1815: * the given doc.
1816: *
1817: * @param indent the number of extra spaces to indent the annotations.
1818: * @param descList the array of {@link AnnotationDesc}.
1819: * @param linkBreak if true, add new line between each member value.
1820: * @return an array of strings representing the annotations being
1821: * documented.
1822: */
1823: private List getAnnotations(int indent, AnnotationDesc[] descList,
1824: boolean linkBreak) {
1825: List results = new ArrayList();
1826: StringBuffer annotation;
1827: for (int i = 0; i < descList.length; i++) {
1828: AnnotationTypeDoc annotationDoc = descList[i]
1829: .annotationType();
1830: if (!Util.isDocumentedAnnotation(annotationDoc)) {
1831: continue;
1832: }
1833: annotation = new StringBuffer();
1834: LinkInfoImpl linkInfo = new LinkInfoImpl(
1835: LinkInfoImpl.CONTEXT_ANNOTATION, annotationDoc);
1836: linkInfo.label = "@" + annotationDoc.name();
1837: annotation.append(getLink(linkInfo));
1838: AnnotationDesc.ElementValuePair[] pairs = descList[i]
1839: .elementValues();
1840: if (pairs.length > 0) {
1841: annotation.append('(');
1842: for (int j = 0; j < pairs.length; j++) {
1843: if (j > 0) {
1844: annotation.append(",");
1845: if (linkBreak) {
1846: annotation.append(DocletConstants.NL);
1847: int spaces = annotationDoc.name().length() + 2;
1848: for (int k = 0; k < (spaces + indent); k++) {
1849: annotation.append(' ');
1850: }
1851: }
1852: }
1853: annotation.append(getDocLink(
1854: LinkInfoImpl.CONTEXT_ANNOTATION, pairs[j]
1855: .element(), pairs[j].element()
1856: .name(), false));
1857: annotation.append('=');
1858: AnnotationValue annotationValue = pairs[j].value();
1859: List annotationTypeValues = new ArrayList();
1860: if (annotationValue.value() instanceof AnnotationValue[]) {
1861: AnnotationValue[] annotationArray = (AnnotationValue[]) annotationValue
1862: .value();
1863: for (int k = 0; k < annotationArray.length; k++) {
1864: annotationTypeValues
1865: .add(annotationArray[k]);
1866: }
1867: } else {
1868: annotationTypeValues.add(annotationValue);
1869: }
1870: annotation
1871: .append(annotationTypeValues.size() == 1 ? ""
1872: : "{");
1873: for (Iterator iter = annotationTypeValues
1874: .iterator(); iter.hasNext();) {
1875: annotation
1876: .append(annotationValueToString((AnnotationValue) iter
1877: .next()));
1878: annotation.append(iter.hasNext() ? "," : "");
1879: }
1880: annotation
1881: .append(annotationTypeValues.size() == 1 ? ""
1882: : "}");
1883: }
1884: annotation.append(")");
1885: }
1886: annotation.append(linkBreak ? DocletConstants.NL : "");
1887: results.add(annotation.toString());
1888: }
1889: return results;
1890: }
1891:
1892: private String annotationValueToString(
1893: AnnotationValue annotationValue) {
1894: if (annotationValue.value() instanceof Type) {
1895: Type type = (Type) annotationValue.value();
1896: if (type.asClassDoc() != null) {
1897: LinkInfoImpl linkInfo = new LinkInfoImpl(
1898: LinkInfoImpl.CONTEXT_ANNOTATION, type);
1899: linkInfo.label = (type.asClassDoc().isIncluded() ? type
1900: .typeName() : type.qualifiedTypeName())
1901: + type.dimension() + ".class";
1902: return getLink(linkInfo);
1903: } else {
1904: return type.typeName() + type.dimension() + ".class";
1905: }
1906: } else if (annotationValue.value() instanceof AnnotationDesc) {
1907: List list = getAnnotations(
1908: 0,
1909: new AnnotationDesc[] { (AnnotationDesc) annotationValue
1910: .value() }, false);
1911: StringBuffer buf = new StringBuffer();
1912: for (Iterator iter = list.iterator(); iter.hasNext();) {
1913: buf.append(iter.next());
1914: }
1915: return buf.toString();
1916: } else if (annotationValue.value() instanceof MemberDoc) {
1917: return getDocLink(LinkInfoImpl.CONTEXT_ANNOTATION,
1918: (MemberDoc) annotationValue.value(),
1919: ((MemberDoc) annotationValue.value()).name(), false);
1920: } else {
1921: return annotationValue.toString();
1922: }
1923: }
1924:
1925: /**
1926: * Return the configuation for this doclet.
1927: *
1928: * @return the configuration for this doclet.
1929: */
1930: public Configuration configuration() {
1931: return configuration;
1932: }
1933: }
|