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

Sun, 11 Apr 2010 23:24:24 -0700

author
yhuang
date
Sun, 11 Apr 2010 23:24:24 -0700
changeset 539
06e06ec0d6f2
parent 405
ebb6ad5a95bb
child 554
9d9f26857129
permissions
-rw-r--r--

6875904: Java 7 message synchronization 1
Reviewed-by: ogino, faryad

     1 /*
     2  * Copyright 1998-2009 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;
    28 import java.io.*;
    29 import java.text.SimpleDateFormat;
    30 import java.util.*;
    32 import com.sun.javadoc.*;
    33 import com.sun.tools.doclets.formats.html.markup.*;
    34 import com.sun.tools.doclets.internal.toolkit.*;
    35 import com.sun.tools.doclets.internal.toolkit.util.*;
    36 import com.sun.tools.doclets.internal.toolkit.taglets.*;
    38 /**
    39  * Class for the Html Format Code Generation specific to JavaDoc.
    40  * This Class contains methods related to the Html Code Generation which
    41  * are used extensively while generating the entire documentation.
    42  *
    43  * @since 1.2
    44  * @author Atul M Dambalkar
    45  * @author Robert Field
    46  * @author Bhavesh Patel (Modified)
    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         // Check whether there is any implementation or overridden info to be
   209         // printed. If no overridden or implementation info needs to be
   210         // printed, do not print this section.
   211         if ((intfacs.length > 0 &&
   212                 new ImplementedMethods(method, this.configuration).build().length > 0) ||
   213                 overriddenMethod != null) {
   214             printMemberDetailsListStartTag();
   215             dd();
   216             printTagsInfoHeader();
   217             MethodWriterImpl.printImplementsInfo(this, method);
   218             if (overriddenMethod != null) {
   219                 MethodWriterImpl.printOverridden(this,
   220                     method.overriddenType(), overriddenMethod);
   221             }
   222             printTagsInfoFooter();
   223             ddEnd();
   224         }
   225     }
   227     protected void printTags(Doc doc) {
   228         if(configuration.nocomment){
   229             return;
   230         }
   231         if (doc instanceof MethodDoc) {
   232             printMethodInfo((MethodDoc) doc);
   233         }
   234         TagletOutputImpl output = new TagletOutputImpl("");
   235         TagletWriter.genTagOuput(configuration.tagletManager, doc,
   236             configuration.tagletManager.getCustomTags(doc),
   237                 getTagletWriterInstance(false), output);
   238         String outputString = output.toString().trim();
   239         // For RootDoc, ClassDoc and PackageDoc, this section is not the
   240         // definition description but the start of definition list.
   241         if (!outputString.isEmpty()) {
   242             if (!(doc instanceof RootDoc || doc instanceof ClassDoc ||
   243                     doc instanceof PackageDoc)) {
   244                 printMemberDetailsListStartTag();
   245                 dd();
   246             }
   247             printTagsInfoHeader();
   248             print(outputString);
   249             printTagsInfoFooter();
   250             if (!(doc instanceof RootDoc || doc instanceof ClassDoc ||
   251                     doc instanceof PackageDoc))
   252                 ddEnd();
   253         }
   254     }
   256     /**
   257      * Check whether there are any tags for Serialization Overview
   258      * section to be printed.
   259      *
   260      * @param field the FieldDoc object to check for tags.
   261      * @return true if there are tags to be printed else return false.
   262      */
   263     protected boolean hasSerializationOverviewTags(FieldDoc field) {
   264         TagletOutputImpl output = new TagletOutputImpl("");
   265         TagletWriter.genTagOuput(configuration.tagletManager, field,
   266             configuration.tagletManager.getCustomTags(field),
   267                 getTagletWriterInstance(false), output);
   268         return (!output.toString().trim().isEmpty());
   269     }
   271     /**
   272      * Returns a TagletWriter that knows how to write HTML.
   273      *
   274      * @return a TagletWriter that knows how to write HTML.
   275      */
   276     public TagletWriter getTagletWriterInstance(boolean isFirstSentence) {
   277         return new TagletWriterImpl(this, isFirstSentence);
   278     }
   280     protected void printTagsInfoHeader() {
   281         dl();
   282     }
   284     protected void printTagsInfoFooter() {
   285         dlEnd();
   286     }
   288     /**
   289      * Print Package link, with target frame.
   290      *
   291      * @param pd The link will be to the "package-summary.html" page for this
   292      * package.
   293      * @param target Name of the target frame.
   294      * @param label Tag for the link.
   295      */
   296     public void printTargetPackageLink(PackageDoc pd, String target,
   297         String label) {
   298         print(getHyperLink(pathString(pd, "package-summary.html"), "", label,
   299             false, "", "", target));
   300     }
   302     /**
   303      * Print the html file header. Also print Html page title and stylesheet
   304      * default properties.
   305      *
   306      * @param title         String window title to go in the &lt;TITLE&gt; tag
   307      * @param metakeywords  Array of String keywords for META tag.  Each element
   308      *                      of the array is assigned to a separate META tag.
   309      *                      Pass in null for no array.
   310      * @param includeScript boolean true if printing windowtitle script.
   311      *             False for files that appear in the left-hand frames.
   312      */
   313     public void printHtmlHeader(String title, String[] metakeywords,
   314             boolean includeScript) {
   315         println("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 " +
   316                     "Transitional//EN\" " +
   317                     "\"http://www.w3.org/TR/html4/loose.dtd\">");
   318         println("<!--NewPage-->");
   319         html();
   320         head();
   321         if (! configuration.notimestamp) {
   322             print("<!-- Generated by javadoc (build " + ConfigurationImpl.BUILD_DATE + ") on ");
   323             print(today());
   324             println(" -->");
   325         }
   326         if (configuration.charset.length() > 0) {
   327             println("<META http-equiv=\"Content-Type\" content=\"text/html; "
   328                         + "charset=" + configuration.charset + "\">");
   329         }
   330         if ( configuration.windowtitle.length() > 0 ) {
   331             title += " (" + configuration.windowtitle  + ")";
   332         }
   333         title(title);
   334         println(title);
   335         titleEnd();
   336         println("");
   337         if (! configuration.notimestamp) {
   338                 SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
   339                 println("<META NAME=\"date\" "
   340                                     + "CONTENT=\"" + dateFormat.format(new Date()) + "\">");
   341         }
   342         if ( metakeywords != null ) {
   343             for ( int i=0; i < metakeywords.length; i++ ) {
   344                 println("<META NAME=\"keywords\" "
   345                             + "CONTENT=\"" + metakeywords[i] + "\">");
   346             }
   347         }
   348         println("");
   349         printStyleSheetProperties();
   350         println("");
   351         // Don't print windowtitle script for overview-frame, allclasses-frame
   352         // and package-frame
   353         if (includeScript) {
   354             printWinTitleScript(title);
   355         }
   356         println("");
   357         headEnd();
   358         println("");
   359         body("white", includeScript);
   360     }
   362     /**
   363      * Print user specified header and the footer.
   364      *
   365      * @param header if true print the user provided header else print the
   366      * user provided footer.
   367      */
   368     public void printUserHeaderFooter(boolean header) {
   369         em();
   370         if (header) {
   371             print(replaceDocRootDir(configuration.header));
   372         } else {
   373             if (configuration.footer.length() != 0) {
   374                 print(replaceDocRootDir(configuration.footer));
   375             } else {
   376                 print(replaceDocRootDir(configuration.header));
   377             }
   378         }
   379         emEnd();
   380     }
   382     /**
   383      * Print the user specified top.
   384      */
   385     public void printTop() {
   386         print(replaceDocRootDir(configuration.top));
   387         hr();
   388     }
   390     /**
   391      * Print the user specified bottom.
   392      */
   393     public void printBottom() {
   394         hr();
   395         print(replaceDocRootDir(configuration.bottom));
   396     }
   398     /**
   399      * Print the navigation bar for the Html page at the top and and the bottom.
   400      *
   401      * @param header If true print navigation bar at the top of the page else
   402      * print the nevigation bar at the bottom.
   403      */
   404     protected void navLinks(boolean header) {
   405         println("");
   406         if (!configuration.nonavbar) {
   407             if (header) {
   408                 println(DocletConstants.NL + "<!-- ========= START OF TOP NAVBAR ======= -->");
   409                 anchor("navbar_top");
   410                 println();
   411                 print(getHyperLink("", "skip-navbar_top", "", false, "",
   412                     configuration.getText("doclet.Skip_navigation_links"), ""));
   413             } else {
   414                 println(DocletConstants.NL + "<!-- ======= START OF BOTTOM NAVBAR ====== -->");
   415                 anchor("navbar_bottom");
   416                 println();
   417                 print(getHyperLink("", "skip-navbar_bottom", "", false, "",
   418                     configuration.getText("doclet.Skip_navigation_links"), ""));
   419             }
   420             table(0, "100%", 1, 0);
   421             tr();
   422             tdColspanBgcolorStyle(2, "#EEEEFF", "NavBarCell1");
   423             println("");
   424             if (header) {
   425                 anchor("navbar_top_firstrow");
   426             } else {
   427                 anchor("navbar_bottom_firstrow");
   428             }
   429             table(0, 0, 3);
   430             print("  ");
   431             trAlignVAlign("center", "top");
   433             if (configuration.createoverview) {
   434                 navLinkContents();
   435             }
   437             if (configuration.packages.length == 1) {
   438                 navLinkPackage(configuration.packages[0]);
   439             } else if (configuration.packages.length > 1) {
   440                 navLinkPackage();
   441             }
   443             navLinkClass();
   445             if(configuration.classuse) {
   446                 navLinkClassUse();
   447             }
   448             if(configuration.createtree) {
   449                 navLinkTree();
   450             }
   451             if(!(configuration.nodeprecated ||
   452                      configuration.nodeprecatedlist)) {
   453                 navLinkDeprecated();
   454             }
   455             if(configuration.createindex) {
   456                 navLinkIndex();
   457             }
   458             if (!configuration.nohelp) {
   459                 navLinkHelp();
   460             }
   461             print("  ");
   462             trEnd();
   463             tableEnd();
   464             tdEnd();
   466             tdAlignVAlignRowspan("right", "top", 3);
   468             printUserHeaderFooter(header);
   469             tdEnd();
   470             trEnd();
   471             println("");
   473             tr();
   474             tdBgcolorStyle("white", "NavBarCell2");
   475             font("-2");
   476             space();
   477             navLinkPrevious();
   478             space();
   479             println("");
   480             space();
   481             navLinkNext();
   482             fontEnd();
   483             tdEnd();
   485             tdBgcolorStyle("white", "NavBarCell2");
   486             font("-2");
   487             print("  ");
   488             navShowLists();
   489             print("  ");
   490             space();
   491             println("");
   492             space();
   493             navHideLists(filename);
   494             print("  ");
   495             space();
   496             println("");
   497             space();
   498             navLinkClassIndex();
   499             fontEnd();
   500             tdEnd();
   502             trEnd();
   504             printSummaryDetailLinks();
   506             tableEnd();
   507             if (header) {
   508                 aName("skip-navbar_top");
   509                 aEnd();
   510                 println(DocletConstants.NL + "<!-- ========= END OF TOP NAVBAR ========= -->");
   511             } else {
   512                 aName("skip-navbar_bottom");
   513                 aEnd();
   514                 println(DocletConstants.NL + "<!-- ======== END OF BOTTOM NAVBAR ======= -->");
   515             }
   516             println("");
   517         }
   518     }
   520     /**
   521      * Print the word "NEXT" to indicate that no link is available.  Override
   522      * this method to customize next link.
   523      */
   524     protected void navLinkNext() {
   525         navLinkNext(null);
   526     }
   528     /**
   529      * Print the word "PREV" to indicate that no link is available.  Override
   530      * this method to customize prev link.
   531      */
   532     protected void navLinkPrevious() {
   533         navLinkPrevious(null);
   534     }
   536     /**
   537      * Do nothing. This is the default method.
   538      */
   539     protected void printSummaryDetailLinks() {
   540     }
   542     /**
   543      * Print link to the "overview-summary.html" page.
   544      */
   545     protected void navLinkContents() {
   546         navCellStart();
   547         printHyperLink(relativePath + "overview-summary.html", "",
   548                        configuration.getText("doclet.Overview"), true, "NavBarFont1");
   549         navCellEnd();
   550     }
   552     /**
   553      * Description for a cell in the navigation bar.
   554      */
   555     protected void navCellStart() {
   556         print("  ");
   557         tdBgcolorStyle("#EEEEFF", "NavBarCell1");
   558         print("    ");
   559     }
   561     /**
   562      * Description for a cell in the navigation bar, but with reverse
   563      * high-light effect.
   564      */
   565     protected void navCellRevStart() {
   566         print("  ");
   567         tdBgcolorStyle("#FFFFFF", "NavBarCell1Rev");
   568         print(" ");
   569         space();
   570     }
   572     /**
   573      * Closing tag for navigation bar cell.
   574      */
   575     protected void navCellEnd() {
   576         space();
   577         tdEnd();
   578     }
   580     /**
   581      * Print link to the "package-summary.html" page for the package passed.
   582      *
   583      * @param pkg Package to which link will be generated.
   584      */
   585     protected void navLinkPackage(PackageDoc pkg) {
   586         navCellStart();
   587         printPackageLink(pkg, configuration.getText("doclet.Package"), true,
   588             "NavBarFont1");
   589         navCellEnd();
   590     }
   592     /**
   593      * Print the word "Package" in the navigation bar cell, to indicate that
   594      * link is not available here.
   595      */
   596     protected void navLinkPackage() {
   597         navCellStart();
   598         fontStyle("NavBarFont1");
   599         printText("doclet.Package");
   600         fontEnd();
   601         navCellEnd();
   602     }
   604     /**
   605      * Print the word "Use" in the navigation bar cell, to indicate that link
   606      * is not available.
   607      */
   608     protected void navLinkClassUse() {
   609         navCellStart();
   610         fontStyle("NavBarFont1");
   611         printText("doclet.navClassUse");
   612         fontEnd();
   613         navCellEnd();
   614     }
   616     /**
   617      * Print link for previous file.
   618      *
   619      * @param prev File name for the prev link.
   620      */
   621     public void navLinkPrevious(String prev) {
   622         String tag = configuration.getText("doclet.Prev");
   623         if (prev != null) {
   624             printHyperLink(prev, "", tag, true) ;
   625         } else {
   626             print(tag);
   627         }
   628     }
   630     /**
   631      * Print link for next file.  If next is null, just print the label
   632      * without linking it anywhere.
   633      *
   634      * @param next File name for the next link.
   635      */
   636     public void navLinkNext(String next) {
   637         String tag = configuration.getText("doclet.Next");
   638         if (next != null) {
   639             printHyperLink(next, "", tag, true);
   640         } else {
   641             print(tag);
   642         }
   643     }
   645     /**
   646      * Print "FRAMES" link, to switch to the frame version of the output.
   647      *
   648      * @param link File to be linked, "index.html".
   649      */
   650     protected void navShowLists(String link) {
   651         print(getHyperLink(link + "?" + path + filename, "",
   652             configuration.getText("doclet.FRAMES"), true, "", "", "_top"));
   653     }
   655     /**
   656      * Print "FRAMES" link, to switch to the frame version of the output.
   657      */
   658     protected void navShowLists() {
   659         navShowLists(relativePath + "index.html");
   660     }
   662     /**
   663      * Print "NO FRAMES" link, to switch to the non-frame version of the output.
   664      *
   665      * @param link File to be linked.
   666      */
   667     protected void navHideLists(String link) {
   668         print(getHyperLink(link, "", configuration.getText("doclet.NO_FRAMES"),
   669             true, "", "", "_top"));
   670     }
   672     /**
   673      * Print "Tree" link in the navigation bar. If there is only one package
   674      * specified on the command line, then the "Tree" link will be to the
   675      * only "package-tree.html" file otherwise it will be to the
   676      * "overview-tree.html" file.
   677      */
   678     protected void navLinkTree() {
   679         navCellStart();
   680         PackageDoc[] packages = configuration.root.specifiedPackages();
   681         if (packages.length == 1 && configuration.root.specifiedClasses().length == 0) {
   682             printHyperLink(pathString(packages[0], "package-tree.html"), "",
   683                            configuration.getText("doclet.Tree"), true, "NavBarFont1");
   684         } else {
   685             printHyperLink(relativePath + "overview-tree.html", "",
   686                            configuration.getText("doclet.Tree"), true, "NavBarFont1");
   687         }
   688         navCellEnd();
   689     }
   691     /**
   692      * Print "Tree" link to the "overview-tree.html" file.
   693      */
   694     protected void navLinkMainTree(String label) {
   695         printHyperLink(relativePath + "overview-tree.html", label);
   696     }
   698     /**
   699      * Print the word "Class" in the navigation bar cell, to indicate that
   700      * class link is not available.
   701      */
   702     protected void navLinkClass() {
   703         navCellStart();
   704         fontStyle("NavBarFont1");
   705         printText("doclet.Class");
   706         fontEnd();
   707         navCellEnd();
   708     }
   710     /**
   711      * Print "Deprecated" API link in the navigation bar.
   712      */
   713     protected void navLinkDeprecated() {
   714         navCellStart();
   715         printHyperLink(relativePath + "deprecated-list.html", "",
   716                        configuration.getText("doclet.navDeprecated"), true, "NavBarFont1");
   717         navCellEnd();
   718     }
   720     /**
   721      * Print link for generated index. If the user has used "-splitindex"
   722      * command line option, then link to file "index-files/index-1.html" is
   723      * generated otherwise link to file "index-all.html" is generated.
   724      */
   725     protected void navLinkClassIndex() {
   726         printNoFramesTargetHyperLink(relativePath +
   727                 AllClassesFrameWriter.OUTPUT_FILE_NAME_NOFRAMES,
   728             "", "", configuration.getText("doclet.All_Classes"), true);
   729     }
   730     /**
   731      * Print link for generated class index.
   732      */
   733     protected void navLinkIndex() {
   734         navCellStart();
   735         printHyperLink(relativePath +
   736                            (configuration.splitindex?
   737                                 DirectoryManager.getPath("index-files") +
   738                                 fileseparator: "") +
   739                            (configuration.splitindex?
   740                                 "index-1.html" : "index-all.html"), "",
   741                        configuration.getText("doclet.Index"), true, "NavBarFont1");
   742         navCellEnd();
   743     }
   745     /**
   746      * Print help file link. If user has provided a help file, then generate a
   747      * link to the user given file, which is already copied to current or
   748      * destination directory.
   749      */
   750     protected void navLinkHelp() {
   751         String helpfilenm = configuration.helpfile;
   752         if (helpfilenm.equals("")) {
   753             helpfilenm = "help-doc.html";
   754         } else {
   755             int lastsep;
   756             if ((lastsep = helpfilenm.lastIndexOf(File.separatorChar)) != -1) {
   757                 helpfilenm = helpfilenm.substring(lastsep + 1);
   758             }
   759         }
   760         navCellStart();
   761         printHyperLink(relativePath + helpfilenm, "",
   762                        configuration.getText("doclet.Help"), true, "NavBarFont1");
   763         navCellEnd();
   764     }
   766     /**
   767      * Print the word "Detail" in the navigation bar. No link is available.
   768      */
   769     protected void navDetail() {
   770         printText("doclet.Detail");
   771     }
   773     /**
   774      * Print the word "Summary" in the navigation bar. No link is available.
   775      */
   776     protected void navSummary() {
   777         printText("doclet.Summary");
   778     }
   780     /**
   781      * Print the Html table tag for the index summary tables. The table tag
   782      * printed is
   783      * &lt;TABLE BORDER="1" CELLPADDING="3" CELLSPACING="0" WIDTH="100%">
   784      */
   785     public void tableIndexSummary() {
   786         table(1, "100%", 3, 0);
   787     }
   789     /**
   790      * Print the Html table tag for the index summary tables.
   791      *
   792      * @param summary the summary for the table tag summary attribute.
   793      */
   794     public void tableIndexSummary(String summary) {
   795         table(1, "100%", 3, 0, summary);
   796     }
   798     /**
   799      * Same as {@link #tableIndexSummary()}.
   800      */
   801     public void tableIndexDetail() {
   802         table(1, "100%", 3, 0);
   803     }
   805     /**
   806      * Print Html tag for table elements. The tag printed is
   807      * &lt;TD ALIGN="right" VALIGN="top" WIDTH="1%"&gt;.
   808      */
   809     public void tdIndex() {
   810         print("<TD ALIGN=\"right\" VALIGN=\"top\" WIDTH=\"1%\">");
   811     }
   813     /**
   814      * Print table caption.
   815      */
   816     public void tableCaptionStart() {
   817         captionStyle("TableCaption");
   818     }
   820     /**
   821      * Print table sub-caption.
   822      */
   823     public void tableSubCaptionStart() {
   824         captionStyle("TableSubCaption");
   825     }
   827     /**
   828      * Print table caption end tags.
   829      */
   830     public void tableCaptionEnd() {
   831         captionEnd();
   832     }
   834     /**
   835      * Print summary table header.
   836      */
   837     public void summaryTableHeader(String[] header, String scope) {
   838         tr();
   839         for ( int i=0; i < header.length; i++ ) {
   840             thScopeNoWrap("TableHeader", scope);
   841             print(header[i]);
   842             thEnd();
   843         }
   844         trEnd();
   845     }
   847     /**
   848      * Prine table header information about color, column span and the font.
   849      *
   850      * @param color Background color.
   851      * @param span  Column span.
   852      */
   853     public void tableHeaderStart(String color, int span) {
   854         trBgcolorStyle(color, "TableHeadingColor");
   855         thAlignColspan("left", span);
   856         font("+2");
   857     }
   859     /**
   860      * Print table header for the inherited members summary tables. Print the
   861      * background color information.
   862      *
   863      * @param color Background color.
   864      */
   865     public void tableInheritedHeaderStart(String color) {
   866         trBgcolorStyle(color, "TableSubHeadingColor");
   867         thAlign("left");
   868     }
   870     /**
   871      * Print "Use" table header. Print the background color and the column span.
   872      *
   873      * @param color Background color.
   874      */
   875     public void tableUseInfoHeaderStart(String color) {
   876         trBgcolorStyle(color, "TableSubHeadingColor");
   877         thAlignColspan("left", 2);
   878     }
   880     /**
   881      * Print table header with the background color with default column span 2.
   882      *
   883      * @param color Background color.
   884      */
   885     public void tableHeaderStart(String color) {
   886         tableHeaderStart(color, 2);
   887     }
   889     /**
   890      * Print table header with the column span, with the default color #CCCCFF.
   891      *
   892      * @param span Column span.
   893      */
   894     public void tableHeaderStart(int span) {
   895         tableHeaderStart("#CCCCFF", span);
   896     }
   898     /**
   899      * Print table header with default column span 2 and default color #CCCCFF.
   900      */
   901     public void tableHeaderStart() {
   902         tableHeaderStart(2);
   903     }
   905     /**
   906      * Print table header end tags for font, column and row.
   907      */
   908     public void tableHeaderEnd() {
   909         fontEnd();
   910         thEnd();
   911         trEnd();
   912     }
   914     /**
   915      * Print table header end tags in inherited tables for column and row.
   916      */
   917     public void tableInheritedHeaderEnd() {
   918         thEnd();
   919         trEnd();
   920     }
   922     /**
   923      * Print the summary table row cell attribute width.
   924      *
   925      * @param width Width of the table cell.
   926      */
   927     public void summaryRow(int width) {
   928         if (width != 0) {
   929             tdWidth(width + "%");
   930         } else {
   931             td();
   932         }
   933     }
   935     /**
   936      * Print the summary table row cell end tag.
   937      */
   938     public void summaryRowEnd() {
   939         tdEnd();
   940     }
   942     /**
   943      * Print the heading in Html &lt;H2> format.
   944      *
   945      * @param str The Header string.
   946      */
   947     public void printIndexHeading(String str) {
   948         h2();
   949         print(str);
   950         h2End();
   951     }
   953     /**
   954      * Print Html tag &lt;FRAMESET=arg&gt;.
   955      *
   956      * @param arg Argument for the tag.
   957      */
   958     public void frameSet(String arg) {
   959         println("<FRAMESET " + arg + ">");
   960     }
   962     /**
   963      * Print Html closing tag &lt;/FRAMESET&gt;.
   964      */
   965     public void frameSetEnd() {
   966         println("</FRAMESET>");
   967     }
   969     /**
   970      * Print Html tag &lt;FRAME=arg&gt;.
   971      *
   972      * @param arg Argument for the tag.
   973      */
   974     public void frame(String arg) {
   975         println("<FRAME " + arg + ">");
   976     }
   978     /**
   979      * Print Html closing tag &lt;/FRAME&gt;.
   980      */
   981     public void frameEnd() {
   982         println("</FRAME>");
   983     }
   985     /**
   986      * Return path to the class page for a classdoc. For example, the class
   987      * name is "java.lang.Object" and if the current file getting generated is
   988      * "java/io/File.html", then the path string to the class, returned is
   989      * "../../java/lang.Object.html".
   990      *
   991      * @param cd Class to which the path is requested.
   992      */
   993     protected String pathToClass(ClassDoc cd) {
   994         return pathString(cd.containingPackage(), cd.name() + ".html");
   995     }
   997     /**
   998      * Return the path to the class page for a classdoc. Works same as
   999      * {@link #pathToClass(ClassDoc)}.
  1001      * @param cd   Class to which the path is requested.
  1002      * @param name Name of the file(doesn't include path).
  1003      */
  1004     protected String pathString(ClassDoc cd, String name) {
  1005         return pathString(cd.containingPackage(), name);
  1008     /**
  1009      * Return path to the given file name in the given package. So if the name
  1010      * passed is "Object.html" and the name of the package is "java.lang", and
  1011      * if the relative path is "../.." then returned string will be
  1012      * "../../java/lang/Object.html"
  1014      * @param pd Package in which the file name is assumed to be.
  1015      * @param name File name, to which path string is.
  1016      */
  1017     protected String pathString(PackageDoc pd, String name) {
  1018         StringBuffer buf = new StringBuffer(relativePath);
  1019         buf.append(DirectoryManager.getPathToPackage(pd, name));
  1020         return buf.toString();
  1023     /**
  1024      * Print the link to the given package.
  1026      * @param pkg the package to link to.
  1027      * @param label the label for the link.
  1028      * @param isStrong true if the label should be strong.
  1029      */
  1030     public void printPackageLink(PackageDoc pkg, String label, boolean isStrong) {
  1031         print(getPackageLink(pkg, label, isStrong));
  1034     /**
  1035      * Print the link to the given package.
  1037      * @param pkg the package to link to.
  1038      * @param label the label for the link.
  1039      * @param isStrong true if the label should be strong.
  1040      * @param style  the font of the package link label.
  1041      */
  1042     public void printPackageLink(PackageDoc pkg, String label, boolean isStrong,
  1043             String style) {
  1044         print(getPackageLink(pkg, label, isStrong, style));
  1047     /**
  1048      * Return the link to the given package.
  1050      * @param pkg the package to link to.
  1051      * @param label the label for the link.
  1052      * @param isStrong true if the label should be strong.
  1053      * @return the link to the given package.
  1054      */
  1055     public String getPackageLink(PackageDoc pkg, String label,
  1056                                  boolean isStrong) {
  1057         return getPackageLink(pkg, label, isStrong, "");
  1060     /**
  1061      * Return the link to the given package.
  1063      * @param pkg the package to link to.
  1064      * @param label the label for the link.
  1065      * @param isStrong true if the label should be strong.
  1066      * @param style  the font of the package link label.
  1067      * @return the link to the given package.
  1068      */
  1069     public String getPackageLink(PackageDoc pkg, String label, boolean isStrong,
  1070             String style) {
  1071         boolean included = pkg != null && pkg.isIncluded();
  1072         if (! included) {
  1073             PackageDoc[] packages = configuration.packages;
  1074             for (int i = 0; i < packages.length; i++) {
  1075                 if (packages[i].equals(pkg)) {
  1076                     included = true;
  1077                     break;
  1081         if (included || pkg == null) {
  1082             return getHyperLink(pathString(pkg, "package-summary.html"),
  1083                                 "", label, isStrong, style);
  1084         } else {
  1085             String crossPkgLink = getCrossPackageLink(Util.getPackageName(pkg));
  1086             if (crossPkgLink != null) {
  1087                 return getHyperLink(crossPkgLink, "", label, isStrong, style);
  1088             } else {
  1089                 return label;
  1094     public String italicsClassName(ClassDoc cd, boolean qual) {
  1095         String name = (qual)? cd.qualifiedName(): cd.name();
  1096         return (cd.isInterface())?  italicsText(name): name;
  1099     public void printSrcLink(ProgramElementDoc d, String label) {
  1100         if (d == null) {
  1101             return;
  1103         ClassDoc cd = d.containingClass();
  1104         if (cd == null) {
  1105             //d must be a class doc since in has no containing class.
  1106             cd = (ClassDoc) d;
  1108         String href = relativePath + DocletConstants.SOURCE_OUTPUT_DIR_NAME
  1109             + DirectoryManager.getDirectoryPath(cd.containingPackage())
  1110             + cd.name() + ".html#" + SourceToHTMLConverter.getAnchorName(d);
  1111         printHyperLink(href, "", label, true);
  1114     /**
  1115      * Return the link to the given class.
  1117      * @param linkInfo the information about the link.
  1119      * @return the link for the given class.
  1120      */
  1121     public String getLink(LinkInfoImpl linkInfo) {
  1122         LinkFactoryImpl factory = new LinkFactoryImpl(this);
  1123         String link = ((LinkOutputImpl) factory.getLinkOutput(linkInfo)).toString();
  1124         displayLength += linkInfo.displayLength;
  1125         return link;
  1128     /**
  1129      * Return the type parameters for the given class.
  1131      * @param linkInfo the information about the link.
  1132      * @return the type for the given class.
  1133      */
  1134     public String getTypeParameterLinks(LinkInfoImpl linkInfo) {
  1135         LinkFactoryImpl factory = new LinkFactoryImpl(this);
  1136         return ((LinkOutputImpl)
  1137             factory.getTypeParameterLinks(linkInfo, false)).toString();
  1140     /**
  1141      * Print the link to the given class.
  1142      */
  1143     public void printLink(LinkInfoImpl linkInfo) {
  1144         print(getLink(linkInfo));
  1147     /*************************************************************
  1148      * Return a class cross link to external class documentation.
  1149      * The name must be fully qualified to determine which package
  1150      * the class is in.  The -link option does not allow users to
  1151      * link to external classes in the "default" package.
  1153      * @param qualifiedClassName the qualified name of the external class.
  1154      * @param refMemName the name of the member being referenced.  This should
  1155      * be null or empty string if no member is being referenced.
  1156      * @param label the label for the external link.
  1157      * @param strong true if the link should be strong.
  1158      * @param style the style of the link.
  1159      * @param code true if the label should be code font.
  1160      */
  1161     public String getCrossClassLink(String qualifiedClassName, String refMemName,
  1162                                     String label, boolean strong, String style,
  1163                                     boolean code) {
  1164         String className = "",
  1165             packageName = qualifiedClassName == null ? "" : qualifiedClassName;
  1166         int periodIndex;
  1167         while((periodIndex = packageName.lastIndexOf('.')) != -1) {
  1168             className = packageName.substring(periodIndex + 1, packageName.length()) +
  1169                 (className.length() > 0 ? "." + className : "");
  1170             String defaultLabel = code ? getCode() + className + getCodeEnd() : className;
  1171             packageName = packageName.substring(0, periodIndex);
  1172             if (getCrossPackageLink(packageName) != null) {
  1173                 //The package exists in external documentation, so link to the external
  1174                 //class (assuming that it exists).  This is definitely a limitation of
  1175                 //the -link option.  There are ways to determine if an external package
  1176                 //exists, but no way to determine if the external class exists.  We just
  1177                 //have to assume that it does.
  1178                 return getHyperLink(
  1179                     configuration.extern.getExternalLink(packageName, relativePath,
  1180                                 className + ".html?is-external=true"),
  1181                     refMemName == null ? "" : refMemName,
  1182                     label == null || label.length() == 0 ? defaultLabel : label,
  1183                     strong, style,
  1184                     configuration.getText("doclet.Href_Class_Or_Interface_Title", packageName),
  1185                     "");
  1188         return null;
  1191     public boolean isClassLinkable(ClassDoc cd) {
  1192         if (cd.isIncluded()) {
  1193             return configuration.isGeneratedDoc(cd);
  1195         return configuration.extern.isExternal(cd);
  1198     public String getCrossPackageLink(String pkgName) {
  1199         return configuration.extern.getExternalLink(pkgName, relativePath,
  1200             "package-summary.html?is-external=true");
  1203     public void printQualifiedClassLink(int context, ClassDoc cd) {
  1204         printLink(new LinkInfoImpl(context, cd,
  1205             configuration.getClassName(cd), ""));
  1208     /**
  1209      * Print Class link, with only class name as the link and prefixing
  1210      * plain package name.
  1211      */
  1212     public void printPreQualifiedClassLink(int context, ClassDoc cd) {
  1213         print(getPreQualifiedClassLink(context, cd, false));
  1216     /**
  1217      * Retrieve the class link with the package portion of the label in
  1218      * plain text.  If the qualifier is excluded, it willnot be included in the
  1219      * link label.
  1221      * @param cd the class to link to.
  1222      * @param isStrong true if the link should be strong.
  1223      * @return the link with the package portion of the label in plain text.
  1224      */
  1225     public String getPreQualifiedClassLink(int context,
  1226             ClassDoc cd, boolean isStrong) {
  1227         String classlink = "";
  1228         PackageDoc pd = cd.containingPackage();
  1229         if(pd != null && ! configuration.shouldExcludeQualifier(pd.name())) {
  1230             classlink = getPkgName(cd);
  1232         classlink += getLink(new LinkInfoImpl(context, cd, cd.name(), isStrong));
  1233         return classlink;
  1237     /**
  1238      * Print Class link, with only class name as the strong link and prefixing
  1239      * plain package name.
  1240      */
  1241     public void printPreQualifiedStrongClassLink(int context, ClassDoc cd) {
  1242         print(getPreQualifiedClassLink(context, cd, true));
  1245     public void printText(String key) {
  1246         print(configuration.getText(key));
  1249     public void printText(String key, String a1) {
  1250         print(configuration.getText(key, a1));
  1253     public void printText(String key, String a1, String a2) {
  1254         print(configuration.getText(key, a1, a2));
  1257     public void strongText(String key) {
  1258         strong(configuration.getText(key));
  1261     public void strongText(String key, String a1) {
  1262         strong(configuration.getText(key, a1));
  1265     public void strongText(String key, String a1, String a2) {
  1266         strong(configuration.getText(key, a1, a2));
  1269     /**
  1270      * Print the link for the given member.
  1272      * @param context the id of the context where the link will be printed.
  1273      * @param doc the member being linked to.
  1274      * @param label the label for the link.
  1275      * @param strong true if the link should be strong.
  1276      */
  1277     public void printDocLink(int context, MemberDoc doc, String label,
  1278             boolean strong) {
  1279         print(getDocLink(context, doc, label, strong));
  1282     /**
  1283      * Print the link for the given member.
  1285      * @param context the id of the context where the link will be printed.
  1286      * @param classDoc the classDoc that we should link to.  This is not
  1287      *                 necessarily equal to doc.containingClass().  We may be
  1288      *                 inheriting comments.
  1289      * @param doc the member being linked to.
  1290      * @param label the label for the link.
  1291      * @param strong true if the link should be strong.
  1292      */
  1293     public void printDocLink(int context, ClassDoc classDoc, MemberDoc doc,
  1294             String label, boolean strong) {
  1295         print(getDocLink(context, classDoc, doc, label, strong));
  1298     /**
  1299      * Return the link for the given member.
  1301      * @param context the id of the context where the link will be printed.
  1302      * @param doc the member being linked to.
  1303      * @param label the label for the link.
  1304      * @param strong true if the link should be strong.
  1305      * @return the link for the given member.
  1306      */
  1307     public String getDocLink(int context, MemberDoc doc, String label,
  1308                 boolean strong) {
  1309         return getDocLink(context, doc.containingClass(), doc, label, strong);
  1312     /**
  1313      * Return the link for the given member.
  1315      * @param context the id of the context where the link will be printed.
  1316      * @param classDoc the classDoc that we should link to.  This is not
  1317      *                 necessarily equal to doc.containingClass().  We may be
  1318      *                 inheriting comments.
  1319      * @param doc the member being linked to.
  1320      * @param label the label for the link.
  1321      * @param strong true if the link should be strong.
  1322      * @return the link for the given member.
  1323      */
  1324     public String getDocLink(int context, ClassDoc classDoc, MemberDoc doc,
  1325         String label, boolean strong) {
  1326         if (! (doc.isIncluded() ||
  1327             Util.isLinkable(classDoc, configuration()))) {
  1328             return label;
  1329         } else if (doc instanceof ExecutableMemberDoc) {
  1330             ExecutableMemberDoc emd = (ExecutableMemberDoc)doc;
  1331             return getLink(new LinkInfoImpl(context, classDoc,
  1332                 getAnchor(emd), label, strong));
  1333         } else if (doc instanceof MemberDoc) {
  1334             return getLink(new LinkInfoImpl(context, classDoc,
  1335                 doc.name(), label, strong));
  1336         } else {
  1337             return label;
  1341     public void anchor(ExecutableMemberDoc emd) {
  1342         anchor(getAnchor(emd));
  1345     public String getAnchor(ExecutableMemberDoc emd) {
  1346         StringBuilder signature = new StringBuilder(emd.signature());
  1347         StringBuilder signatureParsed = new StringBuilder();
  1348         int counter = 0;
  1349         for (int i = 0; i < signature.length(); i++) {
  1350             char c = signature.charAt(i);
  1351             if (c == '<') {
  1352                 counter++;
  1353             } else if (c == '>') {
  1354                 counter--;
  1355             } else if (counter == 0) {
  1356                 signatureParsed.append(c);
  1359         return emd.name() + signatureParsed.toString();
  1362     public String seeTagToString(SeeTag see) {
  1363         String tagName = see.name();
  1364         if (! (tagName.startsWith("@link") || tagName.equals("@see"))) {
  1365             return "";
  1367         StringBuffer result = new StringBuffer();
  1368         boolean isplaintext = tagName.toLowerCase().equals("@linkplain");
  1369         String label = see.label();
  1370         label = (label.length() > 0)?
  1371             ((isplaintext) ? label :
  1372                  getCode() + label + getCodeEnd()):"";
  1373         String seetext = replaceDocRootDir(see.text());
  1375         //Check if @see is an href or "string"
  1376         if (seetext.startsWith("<") || seetext.startsWith("\"")) {
  1377             result.append(seetext);
  1378             return result.toString();
  1381         //The text from the @see tag.  We will output this text when a label is not specified.
  1382         String text = (isplaintext) ? seetext : getCode() + seetext + getCodeEnd();
  1384         ClassDoc refClass = see.referencedClass();
  1385         String refClassName = see.referencedClassName();
  1386         MemberDoc refMem = see.referencedMember();
  1387         String refMemName = see.referencedMemberName();
  1388         if (refClass == null) {
  1389             //@see is not referencing an included class
  1390             PackageDoc refPackage = see.referencedPackage();
  1391             if (refPackage != null && refPackage.isIncluded()) {
  1392                 //@see is referencing an included package
  1393                 String packageName = isplaintext ? refPackage.name() :
  1394                     getCode() + refPackage.name() + getCodeEnd();
  1395                 result.append(getPackageLink(refPackage,
  1396                     label.length() == 0 ? packageName : label, false));
  1397             } else {
  1398                 //@see is not referencing an included class or package.  Check for cross links.
  1399                 String classCrossLink, packageCrossLink = getCrossPackageLink(refClassName);
  1400                 if (packageCrossLink != null) {
  1401                     //Package cross link found
  1402                     result.append(getHyperLink(packageCrossLink, "",
  1403                         (label.length() == 0)? text : label, false));
  1404                 } else if ((classCrossLink = getCrossClassLink(refClassName,
  1405                         refMemName, label, false, "", ! isplaintext)) != null) {
  1406                     //Class cross link found (possiblly to a member in the class)
  1407                     result.append(classCrossLink);
  1408                 } else {
  1409                     //No cross link found so print warning
  1410                     configuration.getDocletSpecificMsg().warning(see.position(), "doclet.see.class_or_package_not_found",
  1411                             tagName, seetext);
  1412                     result.append((label.length() == 0)? text: label);
  1415         } else if (refMemName == null) {
  1416             // Must be a class reference since refClass is not null and refMemName is null.
  1417             if (label.length() == 0) {
  1418                 label = (isplaintext) ? refClass.name() : getCode() + refClass.name() + getCodeEnd();
  1419                 result.append(getLink(new LinkInfoImpl(refClass, label)));
  1420             } else {
  1421                 result.append(getLink(new LinkInfoImpl(refClass, label)));
  1423         } else if (refMem == null) {
  1424             // Must be a member reference since refClass is not null and refMemName is not null.
  1425             // However, refMem is null, so this referenced member does not exist.
  1426             result.append((label.length() == 0)? text: label);
  1427         } else {
  1428             // Must be a member reference since refClass is not null and refMemName is not null.
  1429             // refMem is not null, so this @see tag must be referencing a valid member.
  1430             ClassDoc containing = refMem.containingClass();
  1431             if (see.text().trim().startsWith("#") &&
  1432                 ! (containing.isPublic() ||
  1433                 Util.isLinkable(containing, configuration()))) {
  1434                 // Since the link is relative and the holder is not even being
  1435                 // documented, this must be an inherited link.  Redirect it.
  1436                 // The current class either overrides the referenced member or
  1437                 // inherits it automatically.
  1438                 if (this instanceof ClassWriterImpl) {
  1439                     containing = ((ClassWriterImpl) this).getClassDoc();
  1440                 } else if (!containing.isPublic()){
  1441                     configuration.getDocletSpecificMsg().warning(
  1442                         see.position(), "doclet.see.class_or_package_not_accessible",
  1443                         tagName, containing.qualifiedName());
  1444                 } else {
  1445                     configuration.getDocletSpecificMsg().warning(
  1446                         see.position(), "doclet.see.class_or_package_not_found",
  1447                         tagName, seetext);
  1450             if (configuration.currentcd != containing) {
  1451                 refMemName = containing.name() + "." + refMemName;
  1453             if (refMem instanceof ExecutableMemberDoc) {
  1454                 if (refMemName.indexOf('(') < 0) {
  1455                     refMemName += ((ExecutableMemberDoc)refMem).signature();
  1458             text = (isplaintext) ?
  1459                 refMemName : getCode() + refMemName + getCodeEnd();
  1461             result.append(getDocLink(LinkInfoImpl.CONTEXT_SEE_TAG, containing,
  1462                 refMem, (label.length() == 0)? text: label, false));
  1464         return result.toString();
  1467     public void printInlineComment(Doc doc, Tag tag) {
  1468         printCommentTags(doc, tag.inlineTags(), false, false);
  1471     public void printInlineDeprecatedComment(Doc doc, Tag tag) {
  1472         printCommentTags(doc, tag.inlineTags(), true, false);
  1475     public void printSummaryComment(Doc doc) {
  1476         printSummaryComment(doc, doc.firstSentenceTags());
  1479     public void printSummaryComment(Doc doc, Tag[] firstSentenceTags) {
  1480         printCommentTags(doc, firstSentenceTags, false, true);
  1483     public void printSummaryDeprecatedComment(Doc doc) {
  1484         printCommentTags(doc, doc.firstSentenceTags(), true, true);
  1487     public void printSummaryDeprecatedComment(Doc doc, Tag tag) {
  1488         printCommentTags(doc, tag.firstSentenceTags(), true, true);
  1491     public void printInlineComment(Doc doc) {
  1492         printCommentTags(doc, doc.inlineTags(), false, false);
  1493         p();
  1496     public void printInlineDeprecatedComment(Doc doc) {
  1497         printCommentTags(doc, doc.inlineTags(), true, false);
  1500     private void printCommentTags(Doc doc, Tag[] tags, boolean depr, boolean first) {
  1501         if(configuration.nocomment){
  1502             return;
  1504         if (depr) {
  1505             italic();
  1507         String result = commentTagsToString(null, doc, tags, first);
  1508         print(result);
  1509         if (depr) {
  1510             italicEnd();
  1512         if (tags.length == 0) {
  1513             space();
  1517     /**
  1518      * Converts inline tags and text to text strings, expanding the
  1519      * inline tags along the way.  Called wherever text can contain
  1520      * an inline tag, such as in comments or in free-form text arguments
  1521      * to non-inline tags.
  1523      * @param holderTag    specific tag where comment resides
  1524      * @param doc    specific doc where comment resides
  1525      * @param tags   array of text tags and inline tags (often alternating)
  1526      *               present in the text of interest for this doc
  1527      * @param isFirstSentence  true if text is first sentence
  1528      */
  1529     public String commentTagsToString(Tag holderTag, Doc doc, Tag[] tags,
  1530             boolean isFirstSentence) {
  1531         StringBuffer result = new StringBuffer();
  1532         // Array of all possible inline tags for this javadoc run
  1533         configuration.tagletManager.checkTags(doc, tags, true);
  1534         for (int i = 0; i < tags.length; i++) {
  1535             Tag tagelem = tags[i];
  1536             String tagName = tagelem.name();
  1537             if (tagelem instanceof SeeTag) {
  1538                 result.append(seeTagToString((SeeTag)tagelem));
  1539             } else if (! tagName.equals("Text")) {
  1540                 int originalLength = result.length();
  1541                 TagletOutput output = TagletWriter.getInlineTagOuput(
  1542                     configuration.tagletManager, holderTag,
  1543                     tagelem, getTagletWriterInstance(isFirstSentence));
  1544                 result.append(output == null ? "" : output.toString());
  1545                 if (originalLength == 0 && isFirstSentence && tagelem.name().equals("@inheritDoc") && result.length() > 0) {
  1546                     break;
  1547                 } else {
  1548                         continue;
  1550             } else {
  1551                 //This is just a regular text tag.  The text may contain html links (<a>)
  1552                 //or inline tag {@docRoot}, which will be handled as special cases.
  1553                 String text = redirectRelativeLinks(tagelem.holder(), tagelem.text());
  1555                 // Replace @docRoot only if not represented by an instance of DocRootTaglet,
  1556                 // that is, only if it was not present in a source file doc comment.
  1557                 // This happens when inserted by the doclet (a few lines
  1558                 // above in this method).  [It might also happen when passed in on the command
  1559                 // line as a text argument to an option (like -header).]
  1560                 text = replaceDocRootDir(text);
  1561                 if (isFirstSentence) {
  1562                     text = removeNonInlineHtmlTags(text);
  1564                 StringTokenizer lines = new StringTokenizer(text, "\r\n", true);
  1565                 StringBuffer textBuff = new StringBuffer();
  1566                 while (lines.hasMoreTokens()) {
  1567                     StringBuffer line = new StringBuffer(lines.nextToken());
  1568                     Util.replaceTabs(configuration.sourcetab, line);
  1569                     textBuff.append(line.toString());
  1571                 result.append(textBuff);
  1574         return result.toString();
  1577     /**
  1578      * Return true if relative links should not be redirected.
  1580      * @return Return true if a relative link should not be redirected.
  1581      */
  1582     private boolean shouldNotRedirectRelativeLinks() {
  1583         return  this instanceof AnnotationTypeWriter ||
  1584                 this instanceof ClassWriter ||
  1585                 this instanceof PackageSummaryWriter;
  1588     /**
  1589      * Suppose a piece of documentation has a relative link.  When you copy
  1590      * that documetation to another place such as the index or class-use page,
  1591      * that relative link will no longer work.  We should redirect those links
  1592      * so that they will work again.
  1593      * <p>
  1594      * Here is the algorithm used to fix the link:
  1595      * <p>
  1596      * &lt;relative link&gt; => docRoot + &lt;relative path to file&gt; + &lt;relative link&gt;
  1597      * <p>
  1598      * For example, suppose com.sun.javadoc.RootDoc has this link:
  1599      * &lt;a href="package-summary.html"&gt;The package Page&lt;/a&gt;
  1600      * <p>
  1601      * If this link appeared in the index, we would redirect
  1602      * the link like this:
  1604      * &lt;a href="./com/sun/javadoc/package-summary.html"&gt;The package Page&lt;/a&gt;
  1606      * @param doc the Doc object whose documentation is being written.
  1607      * @param text the text being written.
  1609      * @return the text, with all the relative links redirected to work.
  1610      */
  1611     private String redirectRelativeLinks(Doc doc, String text) {
  1612         if (doc == null || shouldNotRedirectRelativeLinks()) {
  1613             return text;
  1616         String redirectPathFromRoot;
  1617         if (doc instanceof ClassDoc) {
  1618             redirectPathFromRoot = DirectoryManager.getDirectoryPath(((ClassDoc) doc).containingPackage());
  1619         } else if (doc instanceof MemberDoc) {
  1620             redirectPathFromRoot = DirectoryManager.getDirectoryPath(((MemberDoc) doc).containingPackage());
  1621         } else if (doc instanceof PackageDoc) {
  1622             redirectPathFromRoot = DirectoryManager.getDirectoryPath((PackageDoc) doc);
  1623         } else {
  1624             return text;
  1627         if (! redirectPathFromRoot.endsWith(DirectoryManager.URL_FILE_SEPERATOR)) {
  1628             redirectPathFromRoot += DirectoryManager.URL_FILE_SEPERATOR;
  1631         //Redirect all relative links.
  1632         int end, begin = text.toLowerCase().indexOf("<a");
  1633         if(begin >= 0){
  1634             StringBuffer textBuff = new StringBuffer(text);
  1636             while(begin >=0){
  1637                 if (textBuff.length() > begin + 2 && ! Character.isWhitespace(textBuff.charAt(begin+2))) {
  1638                     begin = textBuff.toString().toLowerCase().indexOf("<a", begin + 1);
  1639                     continue;
  1642                 begin = textBuff.indexOf("=", begin) + 1;
  1643                 end = textBuff.indexOf(">", begin +1);
  1644                 if(begin == 0){
  1645                     //Link has no equal symbol.
  1646                     configuration.root.printWarning(
  1647                         doc.position(),
  1648                         configuration.getText("doclet.malformed_html_link_tag", text));
  1649                     break;
  1651                 if (end == -1) {
  1652                     //Break without warning.  This <a> tag is not necessarily malformed.  The text
  1653                     //might be missing '>' character because the href has an inline tag.
  1654                     break;
  1656                 if(textBuff.substring(begin, end).indexOf("\"") != -1){
  1657                     begin = textBuff.indexOf("\"", begin) + 1;
  1658                     end = textBuff.indexOf("\"", begin +1);
  1659                     if(begin == 0 || end == -1){
  1660                         //Link is missing a quote.
  1661                         break;
  1664                 String relativeLink = textBuff.substring(begin, end);
  1665                 if(!(relativeLink.toLowerCase().startsWith("mailto:") ||
  1666                      relativeLink.toLowerCase().startsWith("http:") ||
  1667                      relativeLink.toLowerCase().startsWith("https:") ||
  1668                      relativeLink.toLowerCase().startsWith("file:"))){
  1669                      relativeLink = "{@"+(new DocRootTaglet()).getName() + "}"
  1670                         + redirectPathFromRoot
  1671                         + relativeLink;
  1672                     textBuff.replace(begin, end, relativeLink);
  1674                 begin = textBuff.toString().toLowerCase().indexOf("<a", begin + 1);
  1676             return textBuff.toString();
  1678         return text;
  1681     public String removeNonInlineHtmlTags(String text) {
  1682         if (text.indexOf('<') < 0) {
  1683             return text;
  1685         String noninlinetags[] = { "<ul>", "</ul>", "<ol>", "</ol>",
  1686                 "<dl>", "</dl>", "<table>", "</table>",
  1687                 "<tr>", "</tr>", "<td>", "</td>",
  1688                 "<th>", "</th>", "<p>", "</p>",
  1689                 "<li>", "</li>", "<dd>", "</dd>",
  1690                 "<dir>", "</dir>", "<dt>", "</dt>",
  1691                 "<h1>", "</h1>", "<h2>", "</h2>",
  1692                 "<h3>", "</h3>", "<h4>", "</h4>",
  1693                 "<h5>", "</h5>", "<h6>", "</h6>",
  1694                 "<pre>", "</pre>", "<menu>", "</menu>",
  1695                 "<listing>", "</listing>", "<hr>",
  1696                 "<blockquote>", "</blockquote>",
  1697                 "<center>", "</center>",
  1698                 "<UL>", "</UL>", "<OL>", "</OL>",
  1699                 "<DL>", "</DL>", "<TABLE>", "</TABLE>",
  1700                 "<TR>", "</TR>", "<TD>", "</TD>",
  1701                 "<TH>", "</TH>", "<P>", "</P>",
  1702                 "<LI>", "</LI>", "<DD>", "</DD>",
  1703                 "<DIR>", "</DIR>", "<DT>", "</DT>",
  1704                 "<H1>", "</H1>", "<H2>", "</H2>",
  1705                 "<H3>", "</H3>", "<H4>", "</H4>",
  1706                 "<H5>", "</H5>", "<H6>", "</H6>",
  1707                 "<PRE>", "</PRE>", "<MENU>", "</MENU>",
  1708                 "<LISTING>", "</LISTING>", "<HR>",
  1709                 "<BLOCKQUOTE>", "</BLOCKQUOTE>",
  1710                 "<CENTER>", "</CENTER>"
  1711         };
  1712         for (int i = 0; i < noninlinetags.length; i++) {
  1713             text = replace(text, noninlinetags[i], "");
  1715         return text;
  1718     public String replace(String text, String tobe, String by) {
  1719         while (true) {
  1720             int startindex = text.indexOf(tobe);
  1721             if (startindex < 0) {
  1722                 return text;
  1724             int endindex = startindex + tobe.length();
  1725             StringBuffer replaced = new StringBuffer();
  1726             if (startindex > 0) {
  1727                 replaced.append(text.substring(0, startindex));
  1729             replaced.append(by);
  1730             if (text.length() > endindex) {
  1731                 replaced.append(text.substring(endindex));
  1733             text = replaced.toString();
  1737     public void printStyleSheetProperties() {
  1738         String filename = configuration.stylesheetfile;
  1739         if (filename.length() > 0) {
  1740             File stylefile = new File(filename);
  1741             String parent = stylefile.getParent();
  1742             filename = (parent == null)?
  1743                 filename:
  1744                 filename.substring(parent.length() + 1);
  1745         } else {
  1746             filename = "stylesheet.css";
  1748         filename = relativePath + filename;
  1749         link("REL =\"stylesheet\" TYPE=\"text/css\" HREF=\"" +
  1750                  filename + "\" " + "TITLE=\"Style\"");
  1753     /**
  1754      * According to the Java Language Specifications, all the outer classes
  1755      * and static nested classes are core classes.
  1756      */
  1757     public boolean isCoreClass(ClassDoc cd) {
  1758         return cd.containingClass() == null || cd.isStatic();
  1761     /**
  1762      * Write the annotatation types for the given packageDoc.
  1764      * @param packageDoc the package to write annotations for.
  1765      */
  1766     public void writeAnnotationInfo(PackageDoc packageDoc) {
  1767         writeAnnotationInfo(packageDoc, packageDoc.annotations());
  1770     /**
  1771      * Write the annotatation types for the given doc.
  1773      * @param doc the doc to write annotations for.
  1774      */
  1775     public void writeAnnotationInfo(ProgramElementDoc doc) {
  1776         writeAnnotationInfo(doc, doc.annotations());
  1779     /**
  1780      * Write the annotatation types for the given doc and parameter.
  1782      * @param indent the number of spaced to indent the parameters.
  1783      * @param doc the doc to write annotations for.
  1784      * @param param the parameter to write annotations for.
  1785      */
  1786     public boolean writeAnnotationInfo(int indent, Doc doc, Parameter param) {
  1787         return writeAnnotationInfo(indent, doc, param.annotations(), false);
  1790     /**
  1791      * Write the annotatation types for the given doc.
  1793      * @param doc the doc to write annotations for.
  1794      * @param descList the array of {@link AnnotationDesc}.
  1795      */
  1796     private void writeAnnotationInfo(Doc doc, AnnotationDesc[] descList) {
  1797         writeAnnotationInfo(0, doc, descList, true);
  1800     /**
  1801      * Write the annotatation types for the given doc.
  1803      * @param indent the number of extra spaces to indent the annotations.
  1804      * @param doc the doc to write annotations for.
  1805      * @param descList the array of {@link AnnotationDesc}.
  1806      */
  1807     private boolean writeAnnotationInfo(int indent, Doc doc, AnnotationDesc[] descList, boolean lineBreak) {
  1808         List<String> annotations = getAnnotations(indent, descList, lineBreak);
  1809         if (annotations.size() == 0) {
  1810             return false;
  1812         fontNoNewLine("-1");
  1813         for (Iterator<String> iter = annotations.iterator(); iter.hasNext();) {
  1814             print(iter.next());
  1816         fontEnd();
  1817         return true;
  1820     /**
  1821      * Return the string representations of the annotation types for
  1822      * the given doc.
  1824      * @param indent the number of extra spaces to indent the annotations.
  1825      * @param descList the array of {@link AnnotationDesc}.
  1826      * @param linkBreak if true, add new line between each member value.
  1827      * @return an array of strings representing the annotations being
  1828      *         documented.
  1829      */
  1830     private List<String> getAnnotations(int indent, AnnotationDesc[] descList, boolean linkBreak) {
  1831         List<String> results = new ArrayList<String>();
  1832         StringBuffer annotation;
  1833         for (int i = 0; i < descList.length; i++) {
  1834             AnnotationTypeDoc annotationDoc = descList[i].annotationType();
  1835             if (! Util.isDocumentedAnnotation(annotationDoc)){
  1836                 continue;
  1838             annotation = new StringBuffer();
  1839             LinkInfoImpl linkInfo = new LinkInfoImpl(
  1840                 LinkInfoImpl.CONTEXT_ANNOTATION, annotationDoc);
  1841             linkInfo.label = "@" + annotationDoc.name();
  1842             annotation.append(getLink(linkInfo));
  1843             AnnotationDesc.ElementValuePair[] pairs = descList[i].elementValues();
  1844             if (pairs.length > 0) {
  1845                 annotation.append('(');
  1846                 for (int j = 0; j < pairs.length; j++) {
  1847                     if (j > 0) {
  1848                         annotation.append(",");
  1849                         if (linkBreak) {
  1850                             annotation.append(DocletConstants.NL);
  1851                             int spaces = annotationDoc.name().length() + 2;
  1852                             for (int k = 0; k < (spaces + indent); k++) {
  1853                                 annotation.append(' ');
  1857                     annotation.append(getDocLink(LinkInfoImpl.CONTEXT_ANNOTATION,
  1858                         pairs[j].element(), pairs[j].element().name(), false));
  1859                     annotation.append('=');
  1860                     AnnotationValue annotationValue = pairs[j].value();
  1861                     List<AnnotationValue> annotationTypeValues = new ArrayList<AnnotationValue>();
  1862                     if (annotationValue.value() instanceof AnnotationValue[]) {
  1863                         AnnotationValue[] annotationArray =
  1864                             (AnnotationValue[]) annotationValue.value();
  1865                         for (int k = 0; k < annotationArray.length; k++) {
  1866                             annotationTypeValues.add(annotationArray[k]);
  1868                     } else {
  1869                         annotationTypeValues.add(annotationValue);
  1871                     annotation.append(annotationTypeValues.size() == 1 ? "" : "{");
  1872                     for (Iterator<AnnotationValue> iter = annotationTypeValues.iterator(); iter.hasNext(); ) {
  1873                         annotation.append(annotationValueToString(iter.next()));
  1874                         annotation.append(iter.hasNext() ? "," : "");
  1876                     annotation.append(annotationTypeValues.size() == 1 ? "" : "}");
  1878                 annotation.append(")");
  1880             annotation.append(linkBreak ? DocletConstants.NL : "");
  1881             results.add(annotation.toString());
  1883         return results;
  1886     private String annotationValueToString(AnnotationValue annotationValue) {
  1887         if (annotationValue.value() instanceof Type) {
  1888             Type type = (Type) annotationValue.value();
  1889             if (type.asClassDoc() != null) {
  1890                 LinkInfoImpl linkInfo = new LinkInfoImpl(
  1891                     LinkInfoImpl.CONTEXT_ANNOTATION, type);
  1892                     linkInfo.label = (type.asClassDoc().isIncluded() ?
  1893                         type.typeName() :
  1894                         type.qualifiedTypeName()) + type.dimension() + ".class";
  1895                 return getLink(linkInfo);
  1896             } else {
  1897                 return type.typeName() + type.dimension() + ".class";
  1899         } else if (annotationValue.value() instanceof AnnotationDesc) {
  1900             List<String> list = getAnnotations(0,
  1901                 new AnnotationDesc[]{(AnnotationDesc) annotationValue.value()},
  1902                     false);
  1903             StringBuffer buf = new StringBuffer();
  1904             for (Iterator<String> iter = list.iterator(); iter.hasNext(); ) {
  1905                 buf.append(iter.next());
  1907             return buf.toString();
  1908         } else if (annotationValue.value() instanceof MemberDoc) {
  1909             return getDocLink(LinkInfoImpl.CONTEXT_ANNOTATION,
  1910                 (MemberDoc) annotationValue.value(),
  1911                 ((MemberDoc) annotationValue.value()).name(), false);
  1912          } else {
  1913             return annotationValue.toString();
  1917     /**
  1918      * Return the configuation for this doclet.
  1920      * @return the configuration for this doclet.
  1921      */
  1922     public Configuration configuration() {
  1923         return configuration;

mercurial