src/share/classes/com/sun/tools/doclets/formats/html/HtmlDocletWriter.java

Wed, 18 Feb 2009 13:47:27 -0800

author
bpatel
date
Wed, 18 Feb 2009 13:47:27 -0800
changeset 222
d424ed561993
parent 184
905e151a185a
child 229
03bcd66bd8e7
child 233
5240b1120530
permissions
-rw-r--r--

6802694: Javadoc doclet does not display deprecated information with -nocomment option for serialized form
Reviewed-by: jjg

     1 /*
     2  * Copyright 1998-2008 Sun Microsystems, Inc.  All Rights Reserved.
     3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
     4  *
     5  * This code is free software; you can redistribute it and/or modify it
     6  * under the terms of the GNU General Public License version 2 only, as
     7  * published by the Free Software Foundation.  Sun designates this
     8  * particular file as subject to the "Classpath" exception as provided
     9  * by Sun in the LICENSE file that accompanied this code.
    10  *
    11  * This code is distributed in the hope that it will be useful, but WITHOUT
    12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
    13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
    14  * version 2 for more details (a copy is included in the LICENSE file that
    15  * accompanied this code).
    16  *
    17  * You should have received a copy of the GNU General Public License version
    18  * 2 along with this work; if not, write to the Free Software Foundation,
    19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
    20  *
    21  * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
    22  * CA 95054 USA or visit www.sun.com if you need additional information or
    23  * have any questions.
    24  */
    26 package com.sun.tools.doclets.formats.html;
    27 import com.sun.tools.doclets.formats.html.markup.*;
    29 import com.sun.tools.doclets.internal.toolkit.*;
    30 import com.sun.tools.doclets.internal.toolkit.util.*;
    31 import com.sun.tools.doclets.internal.toolkit.taglets.*;
    33 import com.sun.javadoc.*;
    34 import java.io.*;
    35 import java.text.SimpleDateFormat;
    36 import java.util.*;
    39 /**
    40  * Class for the Html Format Code Generation specific to JavaDoc.
    41  * This Class contains methods related to the Html Code Generation which
    42  * are used extensively while generating the entire documentation.
    43  *
    44  * @since 1.2
    45  * @author Atul M Dambalkar
    46  * @author Robert Field
    47  */
    48 public class HtmlDocletWriter extends HtmlDocWriter {
    50     /**
    51      * Relative path from the file getting generated to the destination
    52      * directory. For example, if the file getting generated is
    53      * "java/lang/Object.html", then the relative path string is "../../".
    54      * This string can be empty if the file getting generated is in
    55      * the destination directory.
    56      */
    57     public String relativePath = "";
    59     /**
    60      * Same as relativepath, but normalized to never be empty or
    61      * end with a slash.
    62      */
    63     public String relativepathNoSlash = "";
    65     /**
    66      * Platform-dependent directory path from the current or the
    67      * destination directory to the file getting generated.
    68      * Used when creating the file.
    69      * For example, if the file getting generated is
    70      * "java/lang/Object.html", then the path string is "java/lang".
    71      */
    72     public String path = "";
    74     /**
    75      * Name of the file getting generated. If the file getting generated is
    76      * "java/lang/Object.html", then the filename is "Object.html".
    77      */
    78     public String filename = "";
    80     /**
    81      * The display length used for indentation while generating the class page.
    82      */
    83     public int displayLength = 0;
    85     /**
    86      * The global configuration information for this run.
    87      */
    88     public ConfigurationImpl configuration;
    90     /**
    91      * Constructor to construct the HtmlStandardWriter object.
    92      *
    93      * @param filename File to be generated.
    94      */
    95     public HtmlDocletWriter(ConfigurationImpl configuration,
    96                               String filename) throws IOException {
    97         super(configuration, filename);
    98         this.configuration = configuration;
    99         this.filename = filename;
   100     }
   102     /**
   103      * Constructor to construct the HtmlStandardWriter object.
   104      *
   105      * @param path         Platform-dependent {@link #path} used when
   106      *                     creating file.
   107      * @param filename     Name of file to be generated.
   108      * @param relativePath Value for the variable {@link #relativePath}.
   109      */
   110     public HtmlDocletWriter(ConfigurationImpl configuration,
   111                               String path, String filename,
   112                               String relativePath) throws IOException {
   113         super(configuration, path, filename);
   114         this.configuration = configuration;
   115         this.path = path;
   116         this.relativePath = relativePath;
   117         this.relativepathNoSlash =
   118             DirectoryManager.getPathNoTrailingSlash(this.relativePath);
   119         this.filename = filename;
   120     }
   122     /**
   123      * Replace {@docRoot} tag used in options that accept HTML text, such
   124      * as -header, -footer, -top and -bottom, and when converting a relative
   125      * HREF where commentTagsToString inserts a {@docRoot} where one was
   126      * missing.  (Also see DocRootTaglet for {@docRoot} tags in doc
   127      * comments.)
   128      * <p>
   129      * Replace {&#064;docRoot} tag in htmlstr with the relative path to the
   130      * destination directory from the directory where the file is being
   131      * written, looping to handle all such tags in htmlstr.
   132      * <p>
   133      * For example, for "-d docs" and -header containing {&#064;docRoot}, when
   134      * the HTML page for source file p/C1.java is being generated, the
   135      * {&#064;docRoot} tag would be inserted into the header as "../",
   136      * the relative path from docs/p/ to docs/ (the document root).
   137      * <p>
   138      * Note: This doc comment was written with '&amp;#064;' representing '@'
   139      * to prevent the inline tag from being interpreted.
   140      */
   141     public String replaceDocRootDir(String htmlstr) {
   142         // Return if no inline tags exist
   143         int index = htmlstr.indexOf("{@");
   144         if (index < 0) {
   145             return htmlstr;
   146         }
   147         String lowerHtml = htmlstr.toLowerCase();
   148         // Return index of first occurrence of {@docroot}
   149         // Note: {@docRoot} is not case sensitive when passed in w/command line option
   150         index = lowerHtml.indexOf("{@docroot}", index);
   151         if (index < 0) {
   152             return htmlstr;
   153         }
   154         StringBuffer buf = new StringBuffer();
   155         int previndex = 0;
   156         while (true) {
   157             // Search for lowercase version of {@docRoot}
   158             index = lowerHtml.indexOf("{@docroot}", previndex);
   159             // If next {@docRoot} tag not found, append rest of htmlstr and exit loop
   160             if (index < 0) {
   161                 buf.append(htmlstr.substring(previndex));
   162                 break;
   163             }
   164             // If next {@docroot} tag found, append htmlstr up to start of tag
   165             buf.append(htmlstr.substring(previndex, index));
   166             previndex = index + 10;  // length for {@docroot} string
   167             // Insert relative path where {@docRoot} was located
   168             buf.append(relativepathNoSlash);
   169             // Append slash if next character is not a slash
   170             if (relativepathNoSlash.length() > 0 && previndex < htmlstr.length()
   171                     && htmlstr.charAt(previndex) != '/') {
   172                 buf.append(DirectoryManager.URL_FILE_SEPERATOR);
   173             }
   174         }
   175         return buf.toString();
   176     }
   178     /**
   179      * Print Html Hyper Link, with target frame.  This
   180      * link will only appear if page is not in a frame.
   181      *
   182      * @param link String name of the file.
   183      * @param where Position in the file
   184      * @param target Name of the target frame.
   185      * @param label Tag for the link.
   186      * @param strong Whether the label should be strong or not?
   187      */
   188     public void printNoFramesTargetHyperLink(String link, String where,
   189                                                String target, String label,
   190                                                boolean strong) {
   191         script();
   192         println("  <!--");
   193         println("  if(window==top) {");
   194         println("    document.writeln('"
   195             + getHyperLink(link, where, label, strong, "", "", target) + "');");
   196         println("  }");
   197         println("  //-->");
   198         scriptEnd();
   199         noScript();
   200         println("  " + getHyperLink(link, where, label, strong, "", "", target));
   201         noScriptEnd();
   202         println(DocletConstants.NL);
   203     }
   205     private void printMethodInfo(MethodDoc method) {
   206         ClassDoc[] intfacs = method.containingClass().interfaces();
   207         MethodDoc overriddenMethod = method.overriddenMethod();
   208         if (intfacs.length > 0 || overriddenMethod != null) {
   209             dd();
   210             printTagsInfoHeader();
   211             MethodWriterImpl.printImplementsInfo(this, method);
   212             if (overriddenMethod != null) {
   213                 MethodWriterImpl.printOverridden(this,
   214                     method.overriddenType(), overriddenMethod);
   215             }
   216             printTagsInfoFooter();
   217             ddEnd();
   218         }
   219         dd();
   220     }
   222     protected void printTags(Doc doc) {
   223         if(configuration.nocomment){
   224             return;
   225         }
   226         if (doc instanceof MethodDoc) {
   227             printMethodInfo((MethodDoc) doc);
   228         }
   229         TagletOutputImpl output = new TagletOutputImpl("");
   230         TagletWriter.genTagOuput(configuration.tagletManager, doc,
   231             configuration.tagletManager.getCustomTags(doc),
   232                 getTagletWriterInstance(false), output);
   233         if (output.toString().trim().length() > 0) {
   234             printTagsInfoHeader();
   235             print(output.toString());
   236             printTagsInfoFooter();
   237         } else if (! (doc instanceof ConstructorDoc ||
   238             doc instanceof RootDoc || doc instanceof ClassDoc)) {
   239             //To be consistent with 1.4.2 output.
   240             //I hate to do this but we have to pass the diff test to prove
   241             //nothing has broken.
   242             printTagsInfoHeader();
   243             printTagsInfoFooter();
   244         }
   245     }
   247     /**
   248      * Check whether there are any tags to be printed.
   249      *
   250      * @param doc the Doc object to check for tags.
   251      * @return true if there are tags to be printed else return false.
   252      */
   253     protected boolean hasTagsToPrint(Doc doc) {
   254         if (doc instanceof MethodDoc) {
   255             ClassDoc[] intfacs = ((MethodDoc)doc).containingClass().interfaces();
   256             MethodDoc overriddenMethod = ((MethodDoc)doc).overriddenMethod();
   257             if ((intfacs.length > 0 &&
   258                 new ImplementedMethods((MethodDoc)doc, this.configuration).build().length > 0) ||
   259                 overriddenMethod != null) {
   260                 return true;
   261             }
   262         }
   263         TagletOutputImpl output = new TagletOutputImpl("");
   264         TagletWriter.genTagOuput(configuration.tagletManager, doc,
   265             configuration.tagletManager.getCustomTags(doc),
   266                 getTagletWriterInstance(false), output);
   267         return (output.toString().trim().isEmpty());
   268     }
   270     /**
   271      * Returns a TagletWriter that knows how to write HTML.
   272      *
   273      * @return a TagletWriter that knows how to write HTML.
   274      */
   275     public TagletWriter getTagletWriterInstance(boolean isFirstSentence) {
   276         return new TagletWriterImpl(this, isFirstSentence);
   277     }
   279     protected void printTagsInfoHeader() {
   280         dl();
   281     }
   283     protected void printTagsInfoFooter() {
   284         dlEnd();
   285     }
   287     /**
   288      * Print Package link, with target frame.
   289      *
   290      * @param pd The link will be to the "package-summary.html" page for this
   291      * package.
   292      * @param target Name of the target frame.
   293      * @param label Tag for the link.
   294      */
   295     public void printTargetPackageLink(PackageDoc pd, String target,
   296         String label) {
   297         print(getHyperLink(pathString(pd, "package-summary.html"), "", label,
   298             false, "", "", target));
   299     }
   301     /**
   302      * Print the html file header. Also print Html page title and stylesheet
   303      * default properties.
   304      *
   305      * @param title         String window title to go in the &lt;TITLE&gt; tag
   306      * @param metakeywords  Array of String keywords for META tag.  Each element
   307      *                      of the array is assigned to a separate META tag.
   308      *                      Pass in null for no array.
   309      * @param includeScript boolean true if printing windowtitle script.
   310      *             False for files that appear in the left-hand frames.
   311      */
   312     public void printHtmlHeader(String title, String[] metakeywords,
   313             boolean includeScript) {
   314         println("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 " +
   315                     "Transitional//EN\" " +
   316                     "\"http://www.w3.org/TR/html4/loose.dtd\">");
   317         println("<!--NewPage-->");
   318         html();
   319         head();
   320         if (! configuration.notimestamp) {
   321             print("<!-- Generated by javadoc (build " + ConfigurationImpl.BUILD_DATE + ") on ");
   322             print(today());
   323             println(" -->");
   324         }
   325         if (configuration.charset.length() > 0) {
   326             println("<META http-equiv=\"Content-Type\" content=\"text/html; "
   327                         + "charset=" + configuration.charset + "\">");
   328         }
   329         if ( configuration.windowtitle.length() > 0 ) {
   330             title += " (" + configuration.windowtitle  + ")";
   331         }
   332         title(title);
   333         println(title);
   334         titleEnd();
   335         println("");
   336         if (! configuration.notimestamp) {
   337                 SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
   338                 println("<META NAME=\"date\" "
   339                                     + "CONTENT=\"" + dateFormat.format(new Date()) + "\">");
   340         }
   341         if ( metakeywords != null ) {
   342             for ( int i=0; i < metakeywords.length; i++ ) {
   343                 println("<META NAME=\"keywords\" "
   344                             + "CONTENT=\"" + metakeywords[i] + "\">");
   345             }
   346         }
   347         println("");
   348         printStyleSheetProperties();
   349         println("");
   350         // Don't print windowtitle script for overview-frame, allclasses-frame
   351         // and package-frame
   352         if (includeScript) {
   353             printWinTitleScript(title);
   354         }
   355         println("");
   356         headEnd();
   357         println("");
   358         body("white", includeScript);
   359     }
   361     /**
   362      * Print user specified header and the footer.
   363      *
   364      * @param header if true print the user provided header else print the
   365      * user provided footer.
   366      */
   367     public void printUserHeaderFooter(boolean header) {
   368         em();
   369         if (header) {
   370             print(replaceDocRootDir(configuration.header));
   371         } else {
   372             if (configuration.footer.length() != 0) {
   373                 print(replaceDocRootDir(configuration.footer));
   374             } else {
   375                 print(replaceDocRootDir(configuration.header));
   376             }
   377         }
   378         emEnd();
   379     }
   381     /**
   382      * Print the user specified top.
   383      */
   384     public void printTop() {
   385         print(replaceDocRootDir(configuration.top));
   386         hr();
   387     }
   389     /**
   390      * Print the user specified bottom.
   391      */
   392     public void printBottom() {
   393         hr();
   394         print(replaceDocRootDir(configuration.bottom));
   395     }
   397     /**
   398      * Print the navigation bar for the Html page at the top and and the bottom.
   399      *
   400      * @param header If true print navigation bar at the top of the page else
   401      * print the nevigation bar at the bottom.
   402      */
   403     protected void navLinks(boolean header) {
   404         println("");
   405         if (!configuration.nonavbar) {
   406             if (header) {
   407                 println(DocletConstants.NL + "<!-- ========= START OF TOP NAVBAR ======= -->");
   408                 anchor("navbar_top");
   409                 println();
   410                 print(getHyperLink("", "skip-navbar_top", "", false, "",
   411                     configuration.getText("doclet.Skip_navigation_links"), ""));
   412             } else {
   413                 println(DocletConstants.NL + "<!-- ======= START OF BOTTOM NAVBAR ====== -->");
   414                 anchor("navbar_bottom");
   415                 println();
   416                 print(getHyperLink("", "skip-navbar_bottom", "", false, "",
   417                     configuration.getText("doclet.Skip_navigation_links"), ""));
   418             }
   419             table(0, "100%", 1, 0);
   420             tr();
   421             tdColspanBgcolorStyle(2, "#EEEEFF", "NavBarCell1");
   422             println("");
   423             if (header) {
   424                 anchor("navbar_top_firstrow");
   425             } else {
   426                 anchor("navbar_bottom_firstrow");
   427             }
   428             table(0, 0, 3);
   429             print("  ");
   430             trAlignVAlign("center", "top");
   432             if (configuration.createoverview) {
   433                 navLinkContents();
   434             }
   436             if (configuration.packages.length == 1) {
   437                 navLinkPackage(configuration.packages[0]);
   438             } else if (configuration.packages.length > 1) {
   439                 navLinkPackage();
   440             }
   442             navLinkClass();
   444             if(configuration.classuse) {
   445                 navLinkClassUse();
   446             }
   447             if(configuration.createtree) {
   448                 navLinkTree();
   449             }
   450             if(!(configuration.nodeprecated ||
   451                      configuration.nodeprecatedlist)) {
   452                 navLinkDeprecated();
   453             }
   454             if(configuration.createindex) {
   455                 navLinkIndex();
   456             }
   457             if (!configuration.nohelp) {
   458                 navLinkHelp();
   459             }
   460             print("  ");
   461             trEnd();
   462             tableEnd();
   463             tdEnd();
   465             tdAlignVAlignRowspan("right", "top", 3);
   467             printUserHeaderFooter(header);
   468             tdEnd();
   469             trEnd();
   470             println("");
   472             tr();
   473             tdBgcolorStyle("white", "NavBarCell2");
   474             font("-2");
   475             space();
   476             navLinkPrevious();
   477             space();
   478             println("");
   479             space();
   480             navLinkNext();
   481             fontEnd();
   482             tdEnd();
   484             tdBgcolorStyle("white", "NavBarCell2");
   485             font("-2");
   486             print("  ");
   487             navShowLists();
   488             print("  ");
   489             space();
   490             println("");
   491             space();
   492             navHideLists(filename);
   493             print("  ");
   494             space();
   495             println("");
   496             space();
   497             navLinkClassIndex();
   498             fontEnd();
   499             tdEnd();
   501             trEnd();
   503             printSummaryDetailLinks();
   505             tableEnd();
   506             if (header) {
   507                 aName("skip-navbar_top");
   508                 aEnd();
   509                 println(DocletConstants.NL + "<!-- ========= END OF TOP NAVBAR ========= -->");
   510             } else {
   511                 aName("skip-navbar_bottom");
   512                 aEnd();
   513                 println(DocletConstants.NL + "<!-- ======== END OF BOTTOM NAVBAR ======= -->");
   514             }
   515             println("");
   516         }
   517     }
   519     /**
   520      * Print the word "NEXT" to indicate that no link is available.  Override
   521      * this method to customize next link.
   522      */
   523     protected void navLinkNext() {
   524         navLinkNext(null);
   525     }
   527     /**
   528      * Print the word "PREV" to indicate that no link is available.  Override
   529      * this method to customize prev link.
   530      */
   531     protected void navLinkPrevious() {
   532         navLinkPrevious(null);
   533     }
   535     /**
   536      * Do nothing. This is the default method.
   537      */
   538     protected void printSummaryDetailLinks() {
   539     }
   541     /**
   542      * Print link to the "overview-summary.html" page.
   543      */
   544     protected void navLinkContents() {
   545         navCellStart();
   546         printHyperLink(relativePath + "overview-summary.html", "",
   547                        configuration.getText("doclet.Overview"), true, "NavBarFont1");
   548         navCellEnd();
   549     }
   551     /**
   552      * Description for a cell in the navigation bar.
   553      */
   554     protected void navCellStart() {
   555         print("  ");
   556         tdBgcolorStyle("#EEEEFF", "NavBarCell1");
   557         print("    ");
   558     }
   560     /**
   561      * Description for a cell in the navigation bar, but with reverse
   562      * high-light effect.
   563      */
   564     protected void navCellRevStart() {
   565         print("  ");
   566         tdBgcolorStyle("#FFFFFF", "NavBarCell1Rev");
   567         print(" ");
   568         space();
   569     }
   571     /**
   572      * Closing tag for navigation bar cell.
   573      */
   574     protected void navCellEnd() {
   575         space();
   576         tdEnd();
   577     }
   579     /**
   580      * Print link to the "package-summary.html" page for the package passed.
   581      *
   582      * @param pkg Package to which link will be generated.
   583      */
   584     protected void navLinkPackage(PackageDoc pkg) {
   585         navCellStart();
   586         printPackageLink(pkg, configuration.getText("doclet.Package"), true,
   587             "NavBarFont1");
   588         navCellEnd();
   589     }
   591     /**
   592      * Print the word "Package" in the navigation bar cell, to indicate that
   593      * link is not available here.
   594      */
   595     protected void navLinkPackage() {
   596         navCellStart();
   597         fontStyle("NavBarFont1");
   598         printText("doclet.Package");
   599         fontEnd();
   600         navCellEnd();
   601     }
   603     /**
   604      * Print the word "Use" in the navigation bar cell, to indicate that link
   605      * is not available.
   606      */
   607     protected void navLinkClassUse() {
   608         navCellStart();
   609         fontStyle("NavBarFont1");
   610         printText("doclet.navClassUse");
   611         fontEnd();
   612         navCellEnd();
   613     }
   615     /**
   616      * Print link for previous file.
   617      *
   618      * @param prev File name for the prev link.
   619      */
   620     public void navLinkPrevious(String prev) {
   621         String tag = configuration.getText("doclet.Prev");
   622         if (prev != null) {
   623             printHyperLink(prev, "", tag, true) ;
   624         } else {
   625             print(tag);
   626         }
   627     }
   629     /**
   630      * Print link for next file.  If next is null, just print the label
   631      * without linking it anywhere.
   632      *
   633      * @param next File name for the next link.
   634      */
   635     public void navLinkNext(String next) {
   636         String tag = configuration.getText("doclet.Next");
   637         if (next != null) {
   638             printHyperLink(next, "", tag, true);
   639         } else {
   640             print(tag);
   641         }
   642     }
   644     /**
   645      * Print "FRAMES" link, to switch to the frame version of the output.
   646      *
   647      * @param link File to be linked, "index.html".
   648      */
   649     protected void navShowLists(String link) {
   650         print(getHyperLink(link + "?" + path + filename, "",
   651             configuration.getText("doclet.FRAMES"), true, "", "", "_top"));
   652     }
   654     /**
   655      * Print "FRAMES" link, to switch to the frame version of the output.
   656      */
   657     protected void navShowLists() {
   658         navShowLists(relativePath + "index.html");
   659     }
   661     /**
   662      * Print "NO FRAMES" link, to switch to the non-frame version of the output.
   663      *
   664      * @param link File to be linked.
   665      */
   666     protected void navHideLists(String link) {
   667         print(getHyperLink(link, "", configuration.getText("doclet.NO_FRAMES"),
   668             true, "", "", "_top"));
   669     }
   671     /**
   672      * Print "Tree" link in the navigation bar. If there is only one package
   673      * specified on the command line, then the "Tree" link will be to the
   674      * only "package-tree.html" file otherwise it will be to the
   675      * "overview-tree.html" file.
   676      */
   677     protected void navLinkTree() {
   678         navCellStart();
   679         PackageDoc[] packages = configuration.root.specifiedPackages();
   680         if (packages.length == 1 && configuration.root.specifiedClasses().length == 0) {
   681             printHyperLink(pathString(packages[0], "package-tree.html"), "",
   682                            configuration.getText("doclet.Tree"), true, "NavBarFont1");
   683         } else {
   684             printHyperLink(relativePath + "overview-tree.html", "",
   685                            configuration.getText("doclet.Tree"), true, "NavBarFont1");
   686         }
   687         navCellEnd();
   688     }
   690     /**
   691      * Print "Tree" link to the "overview-tree.html" file.
   692      */
   693     protected void navLinkMainTree(String label) {
   694         printHyperLink(relativePath + "overview-tree.html", label);
   695     }
   697     /**
   698      * Print the word "Class" in the navigation bar cell, to indicate that
   699      * class link is not available.
   700      */
   701     protected void navLinkClass() {
   702         navCellStart();
   703         fontStyle("NavBarFont1");
   704         printText("doclet.Class");
   705         fontEnd();
   706         navCellEnd();
   707     }
   709     /**
   710      * Print "Deprecated" API link in the navigation bar.
   711      */
   712     protected void navLinkDeprecated() {
   713         navCellStart();
   714         printHyperLink(relativePath + "deprecated-list.html", "",
   715                        configuration.getText("doclet.navDeprecated"), true, "NavBarFont1");
   716         navCellEnd();
   717     }
   719     /**
   720      * Print link for generated index. If the user has used "-splitindex"
   721      * command line option, then link to file "index-files/index-1.html" is
   722      * generated otherwise link to file "index-all.html" is generated.
   723      */
   724     protected void navLinkClassIndex() {
   725         printNoFramesTargetHyperLink(relativePath +
   726                 AllClassesFrameWriter.OUTPUT_FILE_NAME_NOFRAMES,
   727             "", "", configuration.getText("doclet.All_Classes"), true);
   728     }
   729     /**
   730      * Print link for generated class index.
   731      */
   732     protected void navLinkIndex() {
   733         navCellStart();
   734         printHyperLink(relativePath +
   735                            (configuration.splitindex?
   736                                 DirectoryManager.getPath("index-files") +
   737                                 fileseparator: "") +
   738                            (configuration.splitindex?
   739                                 "index-1.html" : "index-all.html"), "",
   740                        configuration.getText("doclet.Index"), true, "NavBarFont1");
   741         navCellEnd();
   742     }
   744     /**
   745      * Print help file link. If user has provided a help file, then generate a
   746      * link to the user given file, which is already copied to current or
   747      * destination directory.
   748      */
   749     protected void navLinkHelp() {
   750         String helpfilenm = configuration.helpfile;
   751         if (helpfilenm.equals("")) {
   752             helpfilenm = "help-doc.html";
   753         } else {
   754             int lastsep;
   755             if ((lastsep = helpfilenm.lastIndexOf(File.separatorChar)) != -1) {
   756                 helpfilenm = helpfilenm.substring(lastsep + 1);
   757             }
   758         }
   759         navCellStart();
   760         printHyperLink(relativePath + helpfilenm, "",
   761                        configuration.getText("doclet.Help"), true, "NavBarFont1");
   762         navCellEnd();
   763     }
   765     /**
   766      * Print the word "Detail" in the navigation bar. No link is available.
   767      */
   768     protected void navDetail() {
   769         printText("doclet.Detail");
   770     }
   772     /**
   773      * Print the word "Summary" in the navigation bar. No link is available.
   774      */
   775     protected void navSummary() {
   776         printText("doclet.Summary");
   777     }
   779     /**
   780      * Print the Html table tag for the index summary tables. The table tag
   781      * printed is
   782      * &lt;TABLE BORDER="1" CELLPADDING="3" CELLSPACING="0" WIDTH="100%">
   783      */
   784     public void tableIndexSummary() {
   785         table(1, "100%", 3, 0);
   786     }
   788     /**
   789      * Same as {@link #tableIndexSummary()}.
   790      */
   791     public void tableIndexDetail() {
   792         table(1, "100%", 3, 0);
   793     }
   795     /**
   796      * Print Html tag for table elements. The tag printed is
   797      * &lt;TD ALIGN="right" VALIGN="top" WIDTH="1%"&gt;.
   798      */
   799     public void tdIndex() {
   800         print("<TD ALIGN=\"right\" VALIGN=\"top\" WIDTH=\"1%\">");
   801     }
   803     /**
   804      * Prine table header information about color, column span and the font.
   805      *
   806      * @param color Background color.
   807      * @param span  Column span.
   808      */
   809     public void tableHeaderStart(String color, int span) {
   810         trBgcolorStyle(color, "TableHeadingColor");
   811         thAlignColspan("left", span);
   812         font("+2");
   813     }
   815     /**
   816      * Print table header for the inherited members summary tables. Print the
   817      * background color information.
   818      *
   819      * @param color Background color.
   820      */
   821     public void tableInheritedHeaderStart(String color) {
   822         trBgcolorStyle(color, "TableSubHeadingColor");
   823         thAlign("left");
   824     }
   826     /**
   827      * Print "Use" table header. Print the background color and the column span.
   828      *
   829      * @param color Background color.
   830      */
   831     public void tableUseInfoHeaderStart(String color) {
   832         trBgcolorStyle(color, "TableSubHeadingColor");
   833         thAlignColspan("left", 2);
   834     }
   836     /**
   837      * Print table header with the background color with default column span 2.
   838      *
   839      * @param color Background color.
   840      */
   841     public void tableHeaderStart(String color) {
   842         tableHeaderStart(color, 2);
   843     }
   845     /**
   846      * Print table header with the column span, with the default color #CCCCFF.
   847      *
   848      * @param span Column span.
   849      */
   850     public void tableHeaderStart(int span) {
   851         tableHeaderStart("#CCCCFF", span);
   852     }
   854     /**
   855      * Print table header with default column span 2 and default color #CCCCFF.
   856      */
   857     public void tableHeaderStart() {
   858         tableHeaderStart(2);
   859     }
   861     /**
   862      * Print table header end tags for font, column and row.
   863      */
   864     public void tableHeaderEnd() {
   865         fontEnd();
   866         thEnd();
   867         trEnd();
   868     }
   870     /**
   871      * Print table header end tags in inherited tables for column and row.
   872      */
   873     public void tableInheritedHeaderEnd() {
   874         thEnd();
   875         trEnd();
   876     }
   878     /**
   879      * Print the summary table row cell attribute width.
   880      *
   881      * @param width Width of the table cell.
   882      */
   883     public void summaryRow(int width) {
   884         if (width != 0) {
   885             tdWidth(width + "%");
   886         } else {
   887             td();
   888         }
   889     }
   891     /**
   892      * Print the summary table row cell end tag.
   893      */
   894     public void summaryRowEnd() {
   895         tdEnd();
   896     }
   898     /**
   899      * Print the heading in Html &lt;H2> format.
   900      *
   901      * @param str The Header string.
   902      */
   903     public void printIndexHeading(String str) {
   904         h2();
   905         print(str);
   906         h2End();
   907     }
   909     /**
   910      * Print Html tag &lt;FRAMESET=arg&gt;.
   911      *
   912      * @param arg Argument for the tag.
   913      */
   914     public void frameSet(String arg) {
   915         println("<FRAMESET " + arg + ">");
   916     }
   918     /**
   919      * Print Html closing tag &lt;/FRAMESET&gt;.
   920      */
   921     public void frameSetEnd() {
   922         println("</FRAMESET>");
   923     }
   925     /**
   926      * Print Html tag &lt;FRAME=arg&gt;.
   927      *
   928      * @param arg Argument for the tag.
   929      */
   930     public void frame(String arg) {
   931         println("<FRAME " + arg + ">");
   932     }
   934     /**
   935      * Print Html closing tag &lt;/FRAME&gt;.
   936      */
   937     public void frameEnd() {
   938         println("</FRAME>");
   939     }
   941     /**
   942      * Return path to the class page for a classdoc. For example, the class
   943      * name is "java.lang.Object" and if the current file getting generated is
   944      * "java/io/File.html", then the path string to the class, returned is
   945      * "../../java/lang.Object.html".
   946      *
   947      * @param cd Class to which the path is requested.
   948      */
   949     protected String pathToClass(ClassDoc cd) {
   950         return pathString(cd.containingPackage(), cd.name() + ".html");
   951     }
   953     /**
   954      * Return the path to the class page for a classdoc. Works same as
   955      * {@link #pathToClass(ClassDoc)}.
   956      *
   957      * @param cd   Class to which the path is requested.
   958      * @param name Name of the file(doesn't include path).
   959      */
   960     protected String pathString(ClassDoc cd, String name) {
   961         return pathString(cd.containingPackage(), name);
   962     }
   964     /**
   965      * Return path to the given file name in the given package. So if the name
   966      * passed is "Object.html" and the name of the package is "java.lang", and
   967      * if the relative path is "../.." then returned string will be
   968      * "../../java/lang/Object.html"
   969      *
   970      * @param pd Package in which the file name is assumed to be.
   971      * @param name File name, to which path string is.
   972      */
   973     protected String pathString(PackageDoc pd, String name) {
   974         StringBuffer buf = new StringBuffer(relativePath);
   975         buf.append(DirectoryManager.getPathToPackage(pd, name));
   976         return buf.toString();
   977     }
   979     /**
   980      * Print the link to the given package.
   981      *
   982      * @param pkg the package to link to.
   983      * @param label the label for the link.
   984      * @param isStrong true if the label should be strong.
   985      */
   986     public void printPackageLink(PackageDoc pkg, String label, boolean isStrong) {
   987         print(getPackageLink(pkg, label, isStrong));
   988     }
   990     /**
   991      * Print the link to the given package.
   992      *
   993      * @param pkg the package to link to.
   994      * @param label the label for the link.
   995      * @param isStrong true if the label should be strong.
   996      * @param style  the font of the package link label.
   997      */
   998     public void printPackageLink(PackageDoc pkg, String label, boolean isStrong,
   999             String style) {
  1000         print(getPackageLink(pkg, label, isStrong, style));
  1003     /**
  1004      * Return the link to the given package.
  1006      * @param pkg the package to link to.
  1007      * @param label the label for the link.
  1008      * @param isStrong true if the label should be strong.
  1009      * @return the link to the given package.
  1010      */
  1011     public String getPackageLink(PackageDoc pkg, String label,
  1012                                  boolean isStrong) {
  1013         return getPackageLink(pkg, label, isStrong, "");
  1016     /**
  1017      * Return the link to the given package.
  1019      * @param pkg the package to link to.
  1020      * @param label the label for the link.
  1021      * @param isStrong true if the label should be strong.
  1022      * @param style  the font of the package link label.
  1023      * @return the link to the given package.
  1024      */
  1025     public String getPackageLink(PackageDoc pkg, String label, boolean isStrong,
  1026             String style) {
  1027         boolean included = pkg != null && pkg.isIncluded();
  1028         if (! included) {
  1029             PackageDoc[] packages = configuration.packages;
  1030             for (int i = 0; i < packages.length; i++) {
  1031                 if (packages[i].equals(pkg)) {
  1032                     included = true;
  1033                     break;
  1037         if (included || pkg == null) {
  1038             return getHyperLink(pathString(pkg, "package-summary.html"),
  1039                                 "", label, isStrong, style);
  1040         } else {
  1041             String crossPkgLink = getCrossPackageLink(Util.getPackageName(pkg));
  1042             if (crossPkgLink != null) {
  1043                 return getHyperLink(crossPkgLink, "", label, isStrong, style);
  1044             } else {
  1045                 return label;
  1050     public String italicsClassName(ClassDoc cd, boolean qual) {
  1051         String name = (qual)? cd.qualifiedName(): cd.name();
  1052         return (cd.isInterface())?  italicsText(name): name;
  1055     public void printSrcLink(ProgramElementDoc d, String label) {
  1056         if (d == null) {
  1057             return;
  1059         ClassDoc cd = d.containingClass();
  1060         if (cd == null) {
  1061             //d must be a class doc since in has no containing class.
  1062             cd = (ClassDoc) d;
  1064         String href = relativePath + DocletConstants.SOURCE_OUTPUT_DIR_NAME
  1065             + DirectoryManager.getDirectoryPath(cd.containingPackage())
  1066             + cd.name() + ".html#" + SourceToHTMLConverter.getAnchorName(d);
  1067         printHyperLink(href, "", label, true);
  1070     /**
  1071      * Return the link to the given class.
  1073      * @param linkInfo the information about the link.
  1075      * @return the link for the given class.
  1076      */
  1077     public String getLink(LinkInfoImpl linkInfo) {
  1078         LinkFactoryImpl factory = new LinkFactoryImpl(this);
  1079         String link = ((LinkOutputImpl) factory.getLinkOutput(linkInfo)).toString();
  1080         displayLength += linkInfo.displayLength;
  1081         return link;
  1084     /**
  1085      * Return the type parameters for the given class.
  1087      * @param linkInfo the information about the link.
  1088      * @return the type for the given class.
  1089      */
  1090     public String getTypeParameterLinks(LinkInfoImpl linkInfo) {
  1091         LinkFactoryImpl factory = new LinkFactoryImpl(this);
  1092         return ((LinkOutputImpl)
  1093             factory.getTypeParameterLinks(linkInfo, false)).toString();
  1096     /**
  1097      * Print the link to the given class.
  1098      */
  1099     public void printLink(LinkInfoImpl linkInfo) {
  1100         print(getLink(linkInfo));
  1103     /*************************************************************
  1104      * Return a class cross link to external class documentation.
  1105      * The name must be fully qualified to determine which package
  1106      * the class is in.  The -link option does not allow users to
  1107      * link to external classes in the "default" package.
  1109      * @param qualifiedClassName the qualified name of the external class.
  1110      * @param refMemName the name of the member being referenced.  This should
  1111      * be null or empty string if no member is being referenced.
  1112      * @param label the label for the external link.
  1113      * @param strong true if the link should be strong.
  1114      * @param style the style of the link.
  1115      * @param code true if the label should be code font.
  1116      */
  1117     public String getCrossClassLink(String qualifiedClassName, String refMemName,
  1118                                     String label, boolean strong, String style,
  1119                                     boolean code) {
  1120         String className = "",
  1121             packageName = qualifiedClassName == null ? "" : qualifiedClassName;
  1122         int periodIndex;
  1123         while((periodIndex = packageName.lastIndexOf('.')) != -1) {
  1124             className = packageName.substring(periodIndex + 1, packageName.length()) +
  1125                 (className.length() > 0 ? "." + className : "");
  1126             String defaultLabel = code ? getCode() + className + getCodeEnd() : className;
  1127             packageName = packageName.substring(0, periodIndex);
  1128             if (getCrossPackageLink(packageName) != null) {
  1129                 //The package exists in external documentation, so link to the external
  1130                 //class (assuming that it exists).  This is definitely a limitation of
  1131                 //the -link option.  There are ways to determine if an external package
  1132                 //exists, but no way to determine if the external class exists.  We just
  1133                 //have to assume that it does.
  1134                 return getHyperLink(
  1135                     configuration.extern.getExternalLink(packageName, relativePath,
  1136                                 className + ".html?is-external=true"),
  1137                     refMemName == null ? "" : refMemName,
  1138                     label == null || label.length() == 0 ? defaultLabel : label,
  1139                     strong, style,
  1140                     configuration.getText("doclet.Href_Class_Or_Interface_Title", packageName),
  1141                     "");
  1144         return null;
  1147     public boolean isClassLinkable(ClassDoc cd) {
  1148         if (cd.isIncluded()) {
  1149             return configuration.isGeneratedDoc(cd);
  1151         return configuration.extern.isExternal(cd);
  1154     public String getCrossPackageLink(String pkgName) {
  1155         return configuration.extern.getExternalLink(pkgName, relativePath,
  1156             "package-summary.html?is-external=true");
  1159     public void printQualifiedClassLink(int context, ClassDoc cd) {
  1160         printLink(new LinkInfoImpl(context, cd,
  1161             configuration.getClassName(cd), ""));
  1164     /**
  1165      * Print Class link, with only class name as the link and prefixing
  1166      * plain package name.
  1167      */
  1168     public void printPreQualifiedClassLink(int context, ClassDoc cd) {
  1169         print(getPreQualifiedClassLink(context, cd, false));
  1172     /**
  1173      * Retrieve the class link with the package portion of the label in
  1174      * plain text.  If the qualifier is excluded, it willnot be included in the
  1175      * link label.
  1177      * @param cd the class to link to.
  1178      * @param isStrong true if the link should be strong.
  1179      * @return the link with the package portion of the label in plain text.
  1180      */
  1181     public String getPreQualifiedClassLink(int context,
  1182             ClassDoc cd, boolean isStrong) {
  1183         String classlink = "";
  1184         PackageDoc pd = cd.containingPackage();
  1185         if(pd != null && ! configuration.shouldExcludeQualifier(pd.name())) {
  1186             classlink = getPkgName(cd);
  1188         classlink += getLink(new LinkInfoImpl(context, cd, cd.name(), isStrong));
  1189         return classlink;
  1193     /**
  1194      * Print Class link, with only class name as the strong link and prefixing
  1195      * plain package name.
  1196      */
  1197     public void printPreQualifiedStrongClassLink(int context, ClassDoc cd) {
  1198         print(getPreQualifiedClassLink(context, cd, true));
  1201     public void printText(String key) {
  1202         print(configuration.getText(key));
  1205     public void printText(String key, String a1) {
  1206         print(configuration.getText(key, a1));
  1209     public void printText(String key, String a1, String a2) {
  1210         print(configuration.getText(key, a1, a2));
  1213     public void strongText(String key) {
  1214         strong(configuration.getText(key));
  1217     public void strongText(String key, String a1) {
  1218         strong(configuration.getText(key, a1));
  1221     public void strongText(String key, String a1, String a2) {
  1222         strong(configuration.getText(key, a1, a2));
  1225     /**
  1226      * Print the link for the given member.
  1228      * @param context the id of the context where the link will be printed.
  1229      * @param doc the member being linked to.
  1230      * @param label the label for the link.
  1231      * @param strong true if the link should be strong.
  1232      */
  1233     public void printDocLink(int context, MemberDoc doc, String label,
  1234             boolean strong) {
  1235         print(getDocLink(context, doc, label, strong));
  1238     /**
  1239      * Print the link for the given member.
  1241      * @param context the id of the context where the link will be printed.
  1242      * @param classDoc the classDoc that we should link to.  This is not
  1243      *                 necessarily equal to doc.containingClass().  We may be
  1244      *                 inheriting comments.
  1245      * @param doc the member being linked to.
  1246      * @param label the label for the link.
  1247      * @param strong true if the link should be strong.
  1248      */
  1249     public void printDocLink(int context, ClassDoc classDoc, MemberDoc doc,
  1250             String label, boolean strong) {
  1251         print(getDocLink(context, classDoc, doc, label, strong));
  1254     /**
  1255      * Return the link for the given member.
  1257      * @param context the id of the context where the link will be printed.
  1258      * @param doc the member being linked to.
  1259      * @param label the label for the link.
  1260      * @param strong true if the link should be strong.
  1261      * @return the link for the given member.
  1262      */
  1263     public String getDocLink(int context, MemberDoc doc, String label,
  1264                 boolean strong) {
  1265         return getDocLink(context, doc.containingClass(), doc, label, strong);
  1268     /**
  1269      * Return the link for the given member.
  1271      * @param context the id of the context where the link will be printed.
  1272      * @param classDoc the classDoc that we should link to.  This is not
  1273      *                 necessarily equal to doc.containingClass().  We may be
  1274      *                 inheriting comments.
  1275      * @param doc the member being linked to.
  1276      * @param label the label for the link.
  1277      * @param strong true if the link should be strong.
  1278      * @return the link for the given member.
  1279      */
  1280     public String getDocLink(int context, ClassDoc classDoc, MemberDoc doc,
  1281         String label, boolean strong) {
  1282         if (! (doc.isIncluded() ||
  1283             Util.isLinkable(classDoc, configuration()))) {
  1284             return label;
  1285         } else if (doc instanceof ExecutableMemberDoc) {
  1286             ExecutableMemberDoc emd = (ExecutableMemberDoc)doc;
  1287             return getLink(new LinkInfoImpl(context, classDoc,
  1288                 getAnchor(emd), label, strong));
  1289         } else if (doc instanceof MemberDoc) {
  1290             return getLink(new LinkInfoImpl(context, classDoc,
  1291                 doc.name(), label, strong));
  1292         } else {
  1293             return label;
  1297     public void anchor(ExecutableMemberDoc emd) {
  1298         anchor(getAnchor(emd));
  1301     public String getAnchor(ExecutableMemberDoc emd) {
  1302         StringBuilder signature = new StringBuilder(emd.signature());
  1303         StringBuilder signatureParsed = new StringBuilder();
  1304         int counter = 0;
  1305         for (int i = 0; i < signature.length(); i++) {
  1306             char c = signature.charAt(i);
  1307             if (c == '<') {
  1308                 counter++;
  1309             } else if (c == '>') {
  1310                 counter--;
  1311             } else if (counter == 0) {
  1312                 signatureParsed.append(c);
  1315         return emd.name() + signatureParsed.toString();
  1318     public String seeTagToString(SeeTag see) {
  1319         String tagName = see.name();
  1320         if (! (tagName.startsWith("@link") || tagName.equals("@see"))) {
  1321             return "";
  1323         StringBuffer result = new StringBuffer();
  1324         boolean isplaintext = tagName.toLowerCase().equals("@linkplain");
  1325         String label = see.label();
  1326         label = (label.length() > 0)?
  1327             ((isplaintext) ? label :
  1328                  getCode() + label + getCodeEnd()):"";
  1329         String seetext = replaceDocRootDir(see.text());
  1331         //Check if @see is an href or "string"
  1332         if (seetext.startsWith("<") || seetext.startsWith("\"")) {
  1333             result.append(seetext);
  1334             return result.toString();
  1337         //The text from the @see tag.  We will output this text when a label is not specified.
  1338         String text = (isplaintext) ? seetext : getCode() + seetext + getCodeEnd();
  1340         ClassDoc refClass = see.referencedClass();
  1341         String refClassName = see.referencedClassName();
  1342         MemberDoc refMem = see.referencedMember();
  1343         String refMemName = see.referencedMemberName();
  1344         if (refClass == null) {
  1345             //@see is not referencing an included class
  1346             PackageDoc refPackage = see.referencedPackage();
  1347             if (refPackage != null && refPackage.isIncluded()) {
  1348                 //@see is referencing an included package
  1349                 String packageName = isplaintext ? refPackage.name() :
  1350                     getCode() + refPackage.name() + getCodeEnd();
  1351                 result.append(getPackageLink(refPackage,
  1352                     label.length() == 0 ? packageName : label, false));
  1353             } else {
  1354                 //@see is not referencing an included class or package.  Check for cross links.
  1355                 String classCrossLink, packageCrossLink = getCrossPackageLink(refClassName);
  1356                 if (packageCrossLink != null) {
  1357                     //Package cross link found
  1358                     result.append(getHyperLink(packageCrossLink, "",
  1359                         (label.length() == 0)? text : label, false));
  1360                 } else if ((classCrossLink = getCrossClassLink(refClassName,
  1361                         refMemName, label, false, "", ! isplaintext)) != null) {
  1362                     //Class cross link found (possiblly to a member in the class)
  1363                     result.append(classCrossLink);
  1364                 } else {
  1365                     //No cross link found so print warning
  1366                     configuration.getDocletSpecificMsg().warning(see.position(), "doclet.see.class_or_package_not_found",
  1367                             tagName, seetext);
  1368                     result.append((label.length() == 0)? text: label);
  1371         } else if (refMemName == null) {
  1372             // Must be a class reference since refClass is not null and refMemName is null.
  1373             if (label.length() == 0) {
  1374                 label = (isplaintext) ? refClass.name() : getCode() + refClass.name() + getCodeEnd();
  1375                 result.append(getLink(new LinkInfoImpl(refClass, label)));
  1376             } else {
  1377                 result.append(getLink(new LinkInfoImpl(refClass, label)));
  1379         } else if (refMem == null) {
  1380             // Must be a member reference since refClass is not null and refMemName is not null.
  1381             // However, refMem is null, so this referenced member does not exist.
  1382             result.append((label.length() == 0)? text: label);
  1383         } else {
  1384             // Must be a member reference since refClass is not null and refMemName is not null.
  1385             // refMem is not null, so this @see tag must be referencing a valid member.
  1386             ClassDoc containing = refMem.containingClass();
  1387             if (see.text().trim().startsWith("#") &&
  1388                 ! (containing.isPublic() ||
  1389                 Util.isLinkable(containing, configuration()))) {
  1390                 // Since the link is relative and the holder is not even being
  1391                 // documented, this must be an inherited link.  Redirect it.
  1392                 // The current class either overrides the referenced member or
  1393                 // inherits it automatically.
  1394                 containing = ((ClassWriterImpl) this).getClassDoc();
  1396             if (configuration.currentcd != containing) {
  1397                 refMemName = containing.name() + "." + refMemName;
  1399             if (refMem instanceof ExecutableMemberDoc) {
  1400                 if (refMemName.indexOf('(') < 0) {
  1401                     refMemName += ((ExecutableMemberDoc)refMem).signature();
  1404             text = (isplaintext) ?
  1405                 refMemName : getCode() + refMemName + getCodeEnd();
  1407             result.append(getDocLink(LinkInfoImpl.CONTEXT_SEE_TAG, containing,
  1408                 refMem, (label.length() == 0)? text: label, false));
  1410         return result.toString();
  1413     public void printInlineComment(Doc doc, Tag tag) {
  1414         printCommentTags(doc, tag.inlineTags(), false, false);
  1417     public void printInlineDeprecatedComment(Doc doc, Tag tag) {
  1418         printCommentTags(doc, tag.inlineTags(), true, false);
  1421     public void printSummaryComment(Doc doc) {
  1422         printSummaryComment(doc, doc.firstSentenceTags());
  1425     public void printSummaryComment(Doc doc, Tag[] firstSentenceTags) {
  1426         printCommentTags(doc, firstSentenceTags, false, true);
  1429     public void printSummaryDeprecatedComment(Doc doc) {
  1430         printCommentTags(doc, doc.firstSentenceTags(), true, true);
  1433     public void printSummaryDeprecatedComment(Doc doc, Tag tag) {
  1434         printCommentTags(doc, tag.firstSentenceTags(), true, true);
  1437     public void printInlineComment(Doc doc) {
  1438         printCommentTags(doc, doc.inlineTags(), false, false);
  1439         p();
  1442     public void printInlineDeprecatedComment(Doc doc) {
  1443         printCommentTags(doc, doc.inlineTags(), true, false);
  1446     private void printCommentTags(Doc doc, Tag[] tags, boolean depr, boolean first) {
  1447         if(configuration.nocomment){
  1448             return;
  1450         if (depr) {
  1451             italic();
  1453         String result = commentTagsToString(null, doc, tags, first);
  1454         print(result);
  1455         if (depr) {
  1456             italicEnd();
  1458         if (tags.length == 0) {
  1459             space();
  1463     /**
  1464      * Converts inline tags and text to text strings, expanding the
  1465      * inline tags along the way.  Called wherever text can contain
  1466      * an inline tag, such as in comments or in free-form text arguments
  1467      * to non-inline tags.
  1469      * @param holderTag    specific tag where comment resides
  1470      * @param doc    specific doc where comment resides
  1471      * @param tags   array of text tags and inline tags (often alternating)
  1472      *               present in the text of interest for this doc
  1473      * @param isFirstSentence  true if text is first sentence
  1474      */
  1475     public String commentTagsToString(Tag holderTag, Doc doc, Tag[] tags,
  1476             boolean isFirstSentence) {
  1477         StringBuffer result = new StringBuffer();
  1478         // Array of all possible inline tags for this javadoc run
  1479         configuration.tagletManager.checkTags(doc, tags, true);
  1480         for (int i = 0; i < tags.length; i++) {
  1481             Tag tagelem = tags[i];
  1482             String tagName = tagelem.name();
  1483             if (tagelem instanceof SeeTag) {
  1484                 result.append(seeTagToString((SeeTag)tagelem));
  1485             } else if (! tagName.equals("Text")) {
  1486                 int originalLength = result.length();
  1487                 TagletOutput output = TagletWriter.getInlineTagOuput(
  1488                     configuration.tagletManager, holderTag,
  1489                     tagelem, getTagletWriterInstance(isFirstSentence));
  1490                 result.append(output == null ? "" : output.toString());
  1491                 if (originalLength == 0 && isFirstSentence && tagelem.name().equals("@inheritDoc") && result.length() > 0) {
  1492                     break;
  1493                 } else {
  1494                         continue;
  1496             } else {
  1497                 //This is just a regular text tag.  The text may contain html links (<a>)
  1498                 //or inline tag {@docRoot}, which will be handled as special cases.
  1499                 String text = redirectRelativeLinks(tagelem.holder(), tagelem.text());
  1501                 // Replace @docRoot only if not represented by an instance of DocRootTaglet,
  1502                 // that is, only if it was not present in a source file doc comment.
  1503                 // This happens when inserted by the doclet (a few lines
  1504                 // above in this method).  [It might also happen when passed in on the command
  1505                 // line as a text argument to an option (like -header).]
  1506                 text = replaceDocRootDir(text);
  1507                 if (isFirstSentence) {
  1508                     text = removeNonInlineHtmlTags(text);
  1510                 StringTokenizer lines = new StringTokenizer(text, "\r\n", true);
  1511                 StringBuffer textBuff = new StringBuffer();
  1512                 while (lines.hasMoreTokens()) {
  1513                     StringBuffer line = new StringBuffer(lines.nextToken());
  1514                     Util.replaceTabs(configuration.sourcetab, line);
  1515                     textBuff.append(line.toString());
  1517                 result.append(textBuff);
  1520         return result.toString();
  1523     /**
  1524      * Return true if relative links should not be redirected.
  1526      * @return Return true if a relative link should not be redirected.
  1527      */
  1528     private boolean shouldNotRedirectRelativeLinks() {
  1529         return  this instanceof AnnotationTypeWriter ||
  1530                 this instanceof ClassWriter ||
  1531                 this instanceof PackageSummaryWriter;
  1534     /**
  1535      * Suppose a piece of documentation has a relative link.  When you copy
  1536      * that documetation to another place such as the index or class-use page,
  1537      * that relative link will no longer work.  We should redirect those links
  1538      * so that they will work again.
  1539      * <p>
  1540      * Here is the algorithm used to fix the link:
  1541      * <p>
  1542      * &lt;relative link&gt; => docRoot + &lt;relative path to file&gt; + &lt;relative link&gt;
  1543      * <p>
  1544      * For example, suppose com.sun.javadoc.RootDoc has this link:
  1545      * &lt;a href="package-summary.html"&gt;The package Page&lt;/a&gt;
  1546      * <p>
  1547      * If this link appeared in the index, we would redirect
  1548      * the link like this:
  1550      * &lt;a href="./com/sun/javadoc/package-summary.html"&gt;The package Page&lt;/a&gt;
  1552      * @param doc the Doc object whose documentation is being written.
  1553      * @param text the text being written.
  1555      * @return the text, with all the relative links redirected to work.
  1556      */
  1557     private String redirectRelativeLinks(Doc doc, String text) {
  1558         if (doc == null || shouldNotRedirectRelativeLinks()) {
  1559             return text;
  1562         String redirectPathFromRoot;
  1563         if (doc instanceof ClassDoc) {
  1564             redirectPathFromRoot = DirectoryManager.getDirectoryPath(((ClassDoc) doc).containingPackage());
  1565         } else if (doc instanceof MemberDoc) {
  1566             redirectPathFromRoot = DirectoryManager.getDirectoryPath(((MemberDoc) doc).containingPackage());
  1567         } else if (doc instanceof PackageDoc) {
  1568             redirectPathFromRoot = DirectoryManager.getDirectoryPath((PackageDoc) doc);
  1569         } else {
  1570             return text;
  1573         if (! redirectPathFromRoot.endsWith(DirectoryManager.URL_FILE_SEPERATOR)) {
  1574             redirectPathFromRoot += DirectoryManager.URL_FILE_SEPERATOR;
  1577         //Redirect all relative links.
  1578         int end, begin = text.toLowerCase().indexOf("<a");
  1579         if(begin >= 0){
  1580             StringBuffer textBuff = new StringBuffer(text);
  1582             while(begin >=0){
  1583                 if (textBuff.length() > begin + 2 && ! Character.isWhitespace(textBuff.charAt(begin+2))) {
  1584                     begin = textBuff.toString().toLowerCase().indexOf("<a", begin + 1);
  1585                     continue;
  1588                 begin = textBuff.indexOf("=", begin) + 1;
  1589                 end = textBuff.indexOf(">", begin +1);
  1590                 if(begin == 0){
  1591                     //Link has no equal symbol.
  1592                     configuration.root.printWarning(
  1593                         doc.position(),
  1594                         configuration.getText("doclet.malformed_html_link_tag", text));
  1595                     break;
  1597                 if (end == -1) {
  1598                     //Break without warning.  This <a> tag is not necessarily malformed.  The text
  1599                     //might be missing '>' character because the href has an inline tag.
  1600                     break;
  1602                 if(textBuff.substring(begin, end).indexOf("\"") != -1){
  1603                     begin = textBuff.indexOf("\"", begin) + 1;
  1604                     end = textBuff.indexOf("\"", begin +1);
  1605                     if(begin == 0 || end == -1){
  1606                         //Link is missing a quote.
  1607                         break;
  1610                 String relativeLink = textBuff.substring(begin, end);
  1611                 if(!(relativeLink.toLowerCase().startsWith("mailto:") ||
  1612                      relativeLink.toLowerCase().startsWith("http:") ||
  1613                      relativeLink.toLowerCase().startsWith("https:") ||
  1614                      relativeLink.toLowerCase().startsWith("file:"))){
  1615                      relativeLink = "{@"+(new DocRootTaglet()).getName() + "}"
  1616                         + redirectPathFromRoot
  1617                         + relativeLink;
  1618                     textBuff.replace(begin, end, relativeLink);
  1620                 begin = textBuff.toString().toLowerCase().indexOf("<a", begin + 1);
  1622             return textBuff.toString();
  1624         return text;
  1627     public String removeNonInlineHtmlTags(String text) {
  1628         if (text.indexOf('<') < 0) {
  1629             return text;
  1631         String noninlinetags[] = { "<ul>", "</ul>", "<ol>", "</ol>",
  1632                 "<dl>", "</dl>", "<table>", "</table>",
  1633                 "<tr>", "</tr>", "<td>", "</td>",
  1634                 "<th>", "</th>", "<p>", "</p>",
  1635                 "<li>", "</li>", "<dd>", "</dd>",
  1636                 "<dir>", "</dir>", "<dt>", "</dt>",
  1637                 "<h1>", "</h1>", "<h2>", "</h2>",
  1638                 "<h3>", "</h3>", "<h4>", "</h4>",
  1639                 "<h5>", "</h5>", "<h6>", "</h6>",
  1640                 "<pre>", "</pre>", "<menu>", "</menu>",
  1641                 "<listing>", "</listing>", "<hr>",
  1642                 "<blockquote>", "</blockquote>",
  1643                 "<center>", "</center>",
  1644                 "<UL>", "</UL>", "<OL>", "</OL>",
  1645                 "<DL>", "</DL>", "<TABLE>", "</TABLE>",
  1646                 "<TR>", "</TR>", "<TD>", "</TD>",
  1647                 "<TH>", "</TH>", "<P>", "</P>",
  1648                 "<LI>", "</LI>", "<DD>", "</DD>",
  1649                 "<DIR>", "</DIR>", "<DT>", "</DT>",
  1650                 "<H1>", "</H1>", "<H2>", "</H2>",
  1651                 "<H3>", "</H3>", "<H4>", "</H4>",
  1652                 "<H5>", "</H5>", "<H6>", "</H6>",
  1653                 "<PRE>", "</PRE>", "<MENU>", "</MENU>",
  1654                 "<LISTING>", "</LISTING>", "<HR>",
  1655                 "<BLOCKQUOTE>", "</BLOCKQUOTE>",
  1656                 "<CENTER>", "</CENTER>"
  1657         };
  1658         for (int i = 0; i < noninlinetags.length; i++) {
  1659             text = replace(text, noninlinetags[i], "");
  1661         return text;
  1664     public String replace(String text, String tobe, String by) {
  1665         while (true) {
  1666             int startindex = text.indexOf(tobe);
  1667             if (startindex < 0) {
  1668                 return text;
  1670             int endindex = startindex + tobe.length();
  1671             StringBuffer replaced = new StringBuffer();
  1672             if (startindex > 0) {
  1673                 replaced.append(text.substring(0, startindex));
  1675             replaced.append(by);
  1676             if (text.length() > endindex) {
  1677                 replaced.append(text.substring(endindex));
  1679             text = replaced.toString();
  1683     public void printStyleSheetProperties() {
  1684         String filename = configuration.stylesheetfile;
  1685         if (filename.length() > 0) {
  1686             File stylefile = new File(filename);
  1687             String parent = stylefile.getParent();
  1688             filename = (parent == null)?
  1689                 filename:
  1690                 filename.substring(parent.length() + 1);
  1691         } else {
  1692             filename = "stylesheet.css";
  1694         filename = relativePath + filename;
  1695         link("REL =\"stylesheet\" TYPE=\"text/css\" HREF=\"" +
  1696                  filename + "\" " + "TITLE=\"Style\"");
  1699     /**
  1700      * According to the Java Language Specifications, all the outer classes
  1701      * and static nested classes are core classes.
  1702      */
  1703     public boolean isCoreClass(ClassDoc cd) {
  1704         return cd.containingClass() == null || cd.isStatic();
  1707     /**
  1708      * Write the annotatation types for the given packageDoc.
  1710      * @param packageDoc the package to write annotations for.
  1711      */
  1712     public void writeAnnotationInfo(PackageDoc packageDoc) {
  1713         writeAnnotationInfo(packageDoc, packageDoc.annotations());
  1716     /**
  1717      * Write the annotatation types for the given doc.
  1719      * @param doc the doc to write annotations for.
  1720      */
  1721     public void writeAnnotationInfo(ProgramElementDoc doc) {
  1722         writeAnnotationInfo(doc, doc.annotations());
  1725     /**
  1726      * Write the annotatation types for the given doc and parameter.
  1728      * @param indent the number of spaced to indent the parameters.
  1729      * @param doc the doc to write annotations for.
  1730      * @param param the parameter to write annotations for.
  1731      */
  1732     public boolean writeAnnotationInfo(int indent, Doc doc, Parameter param) {
  1733         return writeAnnotationInfo(indent, doc, param.annotations(), false);
  1736     /**
  1737      * Write the annotatation types for the given doc.
  1739      * @param doc the doc to write annotations for.
  1740      * @param descList the array of {@link AnnotationDesc}.
  1741      */
  1742     private void writeAnnotationInfo(Doc doc, AnnotationDesc[] descList) {
  1743         writeAnnotationInfo(0, doc, descList, true);
  1746     /**
  1747      * Write the annotatation types for the given doc.
  1749      * @param indent the number of extra spaces to indent the annotations.
  1750      * @param doc the doc to write annotations for.
  1751      * @param descList the array of {@link AnnotationDesc}.
  1752      */
  1753     private boolean writeAnnotationInfo(int indent, Doc doc, AnnotationDesc[] descList, boolean lineBreak) {
  1754         List<String> annotations = getAnnotations(indent, descList, lineBreak);
  1755         if (annotations.size() == 0) {
  1756             return false;
  1758         fontNoNewLine("-1");
  1759         for (Iterator<String> iter = annotations.iterator(); iter.hasNext();) {
  1760             print(iter.next());
  1762         fontEnd();
  1763         return true;
  1766     /**
  1767      * Return the string representations of the annotation types for
  1768      * the given doc.
  1770      * @param indent the number of extra spaces to indent the annotations.
  1771      * @param descList the array of {@link AnnotationDesc}.
  1772      * @param linkBreak if true, add new line between each member value.
  1773      * @return an array of strings representing the annotations being
  1774      *         documented.
  1775      */
  1776     private List<String> getAnnotations(int indent, AnnotationDesc[] descList, boolean linkBreak) {
  1777         List<String> results = new ArrayList<String>();
  1778         StringBuffer annotation;
  1779         for (int i = 0; i < descList.length; i++) {
  1780             AnnotationTypeDoc annotationDoc = descList[i].annotationType();
  1781             if (! Util.isDocumentedAnnotation(annotationDoc)){
  1782                 continue;
  1784             annotation = new StringBuffer();
  1785             LinkInfoImpl linkInfo = new LinkInfoImpl(
  1786                 LinkInfoImpl.CONTEXT_ANNOTATION, annotationDoc);
  1787             linkInfo.label = "@" + annotationDoc.name();
  1788             annotation.append(getLink(linkInfo));
  1789             AnnotationDesc.ElementValuePair[] pairs = descList[i].elementValues();
  1790             if (pairs.length > 0) {
  1791                 annotation.append('(');
  1792                 for (int j = 0; j < pairs.length; j++) {
  1793                     if (j > 0) {
  1794                         annotation.append(",");
  1795                         if (linkBreak) {
  1796                             annotation.append(DocletConstants.NL);
  1797                             int spaces = annotationDoc.name().length() + 2;
  1798                             for (int k = 0; k < (spaces + indent); k++) {
  1799                                 annotation.append(' ');
  1803                     annotation.append(getDocLink(LinkInfoImpl.CONTEXT_ANNOTATION,
  1804                         pairs[j].element(), pairs[j].element().name(), false));
  1805                     annotation.append('=');
  1806                     AnnotationValue annotationValue = pairs[j].value();
  1807                     List<AnnotationValue> annotationTypeValues = new ArrayList<AnnotationValue>();
  1808                     if (annotationValue.value() instanceof AnnotationValue[]) {
  1809                         AnnotationValue[] annotationArray =
  1810                             (AnnotationValue[]) annotationValue.value();
  1811                         for (int k = 0; k < annotationArray.length; k++) {
  1812                             annotationTypeValues.add(annotationArray[k]);
  1814                     } else {
  1815                         annotationTypeValues.add(annotationValue);
  1817                     annotation.append(annotationTypeValues.size() == 1 ? "" : "{");
  1818                     for (Iterator<AnnotationValue> iter = annotationTypeValues.iterator(); iter.hasNext(); ) {
  1819                         annotation.append(annotationValueToString(iter.next()));
  1820                         annotation.append(iter.hasNext() ? "," : "");
  1822                     annotation.append(annotationTypeValues.size() == 1 ? "" : "}");
  1824                 annotation.append(")");
  1826             annotation.append(linkBreak ? DocletConstants.NL : "");
  1827             results.add(annotation.toString());
  1829         return results;
  1832     private String annotationValueToString(AnnotationValue annotationValue) {
  1833         if (annotationValue.value() instanceof Type) {
  1834             Type type = (Type) annotationValue.value();
  1835             if (type.asClassDoc() != null) {
  1836                 LinkInfoImpl linkInfo = new LinkInfoImpl(
  1837                     LinkInfoImpl.CONTEXT_ANNOTATION, type);
  1838                     linkInfo.label = (type.asClassDoc().isIncluded() ?
  1839                         type.typeName() :
  1840                         type.qualifiedTypeName()) + type.dimension() + ".class";
  1841                 return getLink(linkInfo);
  1842             } else {
  1843                 return type.typeName() + type.dimension() + ".class";
  1845         } else if (annotationValue.value() instanceof AnnotationDesc) {
  1846             List<String> list = getAnnotations(0,
  1847                 new AnnotationDesc[]{(AnnotationDesc) annotationValue.value()},
  1848                     false);
  1849             StringBuffer buf = new StringBuffer();
  1850             for (Iterator<String> iter = list.iterator(); iter.hasNext(); ) {
  1851                 buf.append(iter.next());
  1853             return buf.toString();
  1854         } else if (annotationValue.value() instanceof MemberDoc) {
  1855             return getDocLink(LinkInfoImpl.CONTEXT_ANNOTATION,
  1856                 (MemberDoc) annotationValue.value(),
  1857                 ((MemberDoc) annotationValue.value()).name(), false);
  1858          } else {
  1859             return annotationValue.toString();
  1863     /**
  1864      * Return the configuation for this doclet.
  1866      * @return the configuration for this doclet.
  1867      */
  1868     public Configuration configuration() {
  1869         return configuration;

mercurial