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

Thu, 02 Oct 2008 19:58:40 -0700

author
xdono
date
Thu, 02 Oct 2008 19:58:40 -0700
changeset 117
24a47c3062fe
parent 74
5a9172b251dd
child 182
47a62d8d98b4
permissions
-rw-r--r--

6754988: Update copyright year
Summary: Update for files that have been modified starting July 2008
Reviewed-by: ohair, tbell

     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 bold Whether the label should be bold or not?
   187      */
   188     public void printNoFramesTargetHyperLink(String link, String where,
   189                                                String target, String label,
   190                                                boolean bold) {
   191         script();
   192         println("  <!--");
   193         println("  if(window==top) {");
   194         println("    document.writeln('"
   195             + getHyperLink(link, where, label, bold, "", "", target) + "');");
   196         println("  }");
   197         println("  //-->");
   198         scriptEnd();
   199         noScript();
   200         println("  " + getHyperLink(link, where, label, bold, "", "", 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      * Returns a TagletWriter that knows how to write HTML.
   249      *
   250      * @return a TagletWriter that knows how to write HTML.
   251      */
   252     public TagletWriter getTagletWriterInstance(boolean isFirstSentence) {
   253         return new TagletWriterImpl(this, isFirstSentence);
   254     }
   256     protected void printTagsInfoHeader() {
   257         dl();
   258     }
   260     protected void printTagsInfoFooter() {
   261         dlEnd();
   262     }
   264     /**
   265      * Print Package link, with target frame.
   266      *
   267      * @param pd The link will be to the "package-summary.html" page for this
   268      * package.
   269      * @param target Name of the target frame.
   270      * @param label Tag for the link.
   271      */
   272     public void printTargetPackageLink(PackageDoc pd, String target,
   273         String label) {
   274         print(getHyperLink(pathString(pd, "package-summary.html"), "", label,
   275             false, "", "", target));
   276     }
   278     /**
   279      * Print the html file header. Also print Html page title and stylesheet
   280      * default properties.
   281      *
   282      * @param title         String window title to go in the &lt;TITLE&gt; tag
   283      * @param metakeywords  Array of String keywords for META tag.  Each element
   284      *                      of the array is assigned to a separate META tag.
   285      *                      Pass in null for no array.
   286      * @param includeScript boolean true if printing windowtitle script.
   287      *             False for files that appear in the left-hand frames.
   288      */
   289     public void printHtmlHeader(String title, String[] metakeywords,
   290             boolean includeScript) {
   291         println("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 " +
   292                     "Transitional//EN\" " +
   293                     "\"http://www.w3.org/TR/html4/loose.dtd\">");
   294         println("<!--NewPage-->");
   295         html();
   296         head();
   297         if (! configuration.notimestamp) {
   298             print("<!-- Generated by javadoc (build " + ConfigurationImpl.BUILD_DATE + ") on ");
   299             print(today());
   300             println(" -->");
   301         }
   302         if (configuration.charset.length() > 0) {
   303             println("<META http-equiv=\"Content-Type\" content=\"text/html; "
   304                         + "charset=" + configuration.charset + "\">");
   305         }
   306         if ( configuration.windowtitle.length() > 0 ) {
   307             title += " (" + configuration.windowtitle  + ")";
   308         }
   309         title(title);
   310         println(title);
   311         titleEnd();
   312         println("");
   313         if (! configuration.notimestamp) {
   314                 SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
   315                 println("<META NAME=\"date\" "
   316                                     + "CONTENT=\"" + dateFormat.format(new Date()) + "\">");
   317         }
   318         if ( metakeywords != null ) {
   319             for ( int i=0; i < metakeywords.length; i++ ) {
   320                 println("<META NAME=\"keywords\" "
   321                             + "CONTENT=\"" + metakeywords[i] + "\">");
   322             }
   323         }
   324         println("");
   325         printStyleSheetProperties();
   326         println("");
   327         // Don't print windowtitle script for overview-frame, allclasses-frame
   328         // and package-frame
   329         if (includeScript) {
   330             printWinTitleScript(title);
   331         }
   332         println("");
   333         headEnd();
   334         println("");
   335         body("white", includeScript);
   336     }
   338     /**
   339      * Print user specified header and the footer.
   340      *
   341      * @param header if true print the user provided header else print the
   342      * user provided footer.
   343      */
   344     public void printUserHeaderFooter(boolean header) {
   345         em();
   346         if (header) {
   347             print(replaceDocRootDir(configuration.header));
   348         } else {
   349             if (configuration.footer.length() != 0) {
   350                 print(replaceDocRootDir(configuration.footer));
   351             } else {
   352                 print(replaceDocRootDir(configuration.header));
   353             }
   354         }
   355         emEnd();
   356     }
   358     /**
   359      * Print the user specified top.
   360      */
   361     public void printTop() {
   362         print(replaceDocRootDir(configuration.top));
   363         hr();
   364     }
   366     /**
   367      * Print the user specified bottom.
   368      */
   369     public void printBottom() {
   370         hr();
   371         print(replaceDocRootDir(configuration.bottom));
   372     }
   374     /**
   375      * Print the navigation bar for the Html page at the top and and the bottom.
   376      *
   377      * @param header If true print navigation bar at the top of the page else
   378      * print the nevigation bar at the bottom.
   379      */
   380     protected void navLinks(boolean header) {
   381         println("");
   382         if (!configuration.nonavbar) {
   383             if (header) {
   384                 println(DocletConstants.NL + "<!-- ========= START OF TOP NAVBAR ======= -->");
   385                 anchor("navbar_top");
   386                 println();
   387                 print(getHyperLink("", "skip-navbar_top", "", false, "",
   388                     configuration.getText("doclet.Skip_navigation_links"), ""));
   389             } else {
   390                 println(DocletConstants.NL + "<!-- ======= START OF BOTTOM NAVBAR ====== -->");
   391                 anchor("navbar_bottom");
   392                 println();
   393                 print(getHyperLink("", "skip-navbar_bottom", "", false, "",
   394                     configuration.getText("doclet.Skip_navigation_links"), ""));
   395             }
   396             table(0, "100%", 1, 0);
   397             tr();
   398             tdColspanBgcolorStyle(2, "#EEEEFF", "NavBarCell1");
   399             println("");
   400             if (header) {
   401                 anchor("navbar_top_firstrow");
   402             } else {
   403                 anchor("navbar_bottom_firstrow");
   404             }
   405             table(0, 0, 3);
   406             print("  ");
   407             trAlignVAlign("center", "top");
   409             if (configuration.createoverview) {
   410                 navLinkContents();
   411             }
   413             if (configuration.packages.length == 1) {
   414                 navLinkPackage(configuration.packages[0]);
   415             } else if (configuration.packages.length > 1) {
   416                 navLinkPackage();
   417             }
   419             navLinkClass();
   421             if(configuration.classuse) {
   422                 navLinkClassUse();
   423             }
   424             if(configuration.createtree) {
   425                 navLinkTree();
   426             }
   427             if(!(configuration.nodeprecated ||
   428                      configuration.nodeprecatedlist)) {
   429                 navLinkDeprecated();
   430             }
   431             if(configuration.createindex) {
   432                 navLinkIndex();
   433             }
   434             if (!configuration.nohelp) {
   435                 navLinkHelp();
   436             }
   437             print("  ");
   438             trEnd();
   439             tableEnd();
   440             tdEnd();
   442             tdAlignVAlignRowspan("right", "top", 3);
   444             printUserHeaderFooter(header);
   445             tdEnd();
   446             trEnd();
   447             println("");
   449             tr();
   450             tdBgcolorStyle("white", "NavBarCell2");
   451             font("-2");
   452             space();
   453             navLinkPrevious();
   454             space();
   455             println("");
   456             space();
   457             navLinkNext();
   458             fontEnd();
   459             tdEnd();
   461             tdBgcolorStyle("white", "NavBarCell2");
   462             font("-2");
   463             print("  ");
   464             navShowLists();
   465             print("  ");
   466             space();
   467             println("");
   468             space();
   469             navHideLists(filename);
   470             print("  ");
   471             space();
   472             println("");
   473             space();
   474             navLinkClassIndex();
   475             fontEnd();
   476             tdEnd();
   478             trEnd();
   480             printSummaryDetailLinks();
   482             tableEnd();
   483             if (header) {
   484                 aName("skip-navbar_top");
   485                 aEnd();
   486                 println(DocletConstants.NL + "<!-- ========= END OF TOP NAVBAR ========= -->");
   487             } else {
   488                 aName("skip-navbar_bottom");
   489                 aEnd();
   490                 println(DocletConstants.NL + "<!-- ======== END OF BOTTOM NAVBAR ======= -->");
   491             }
   492             println("");
   493         }
   494     }
   496     /**
   497      * Print the word "NEXT" to indicate that no link is available.  Override
   498      * this method to customize next link.
   499      */
   500     protected void navLinkNext() {
   501         navLinkNext(null);
   502     }
   504     /**
   505      * Print the word "PREV" to indicate that no link is available.  Override
   506      * this method to customize prev link.
   507      */
   508     protected void navLinkPrevious() {
   509         navLinkPrevious(null);
   510     }
   512     /**
   513      * Do nothing. This is the default method.
   514      */
   515     protected void printSummaryDetailLinks() {
   516     }
   518     /**
   519      * Print link to the "overview-summary.html" page.
   520      */
   521     protected void navLinkContents() {
   522         navCellStart();
   523         printHyperLink(relativePath + "overview-summary.html", "",
   524                        configuration.getText("doclet.Overview"), true, "NavBarFont1");
   525         navCellEnd();
   526     }
   528     /**
   529      * Description for a cell in the navigation bar.
   530      */
   531     protected void navCellStart() {
   532         print("  ");
   533         tdBgcolorStyle("#EEEEFF", "NavBarCell1");
   534         print("    ");
   535     }
   537     /**
   538      * Description for a cell in the navigation bar, but with reverse
   539      * high-light effect.
   540      */
   541     protected void navCellRevStart() {
   542         print("  ");
   543         tdBgcolorStyle("#FFFFFF", "NavBarCell1Rev");
   544         print(" ");
   545         space();
   546     }
   548     /**
   549      * Closing tag for navigation bar cell.
   550      */
   551     protected void navCellEnd() {
   552         space();
   553         tdEnd();
   554     }
   556     /**
   557      * Print link to the "package-summary.html" page for the package passed.
   558      *
   559      * @param pkg Package to which link will be generated.
   560      */
   561     protected void navLinkPackage(PackageDoc pkg) {
   562         navCellStart();
   563         printPackageLink(pkg, configuration.getText("doclet.Package"), true,
   564             "NavBarFont1");
   565         navCellEnd();
   566     }
   568     /**
   569      * Print the word "Package" in the navigation bar cell, to indicate that
   570      * link is not available here.
   571      */
   572     protected void navLinkPackage() {
   573         navCellStart();
   574         fontStyle("NavBarFont1");
   575         printText("doclet.Package");
   576         fontEnd();
   577         navCellEnd();
   578     }
   580     /**
   581      * Print the word "Use" in the navigation bar cell, to indicate that link
   582      * is not available.
   583      */
   584     protected void navLinkClassUse() {
   585         navCellStart();
   586         fontStyle("NavBarFont1");
   587         printText("doclet.navClassUse");
   588         fontEnd();
   589         navCellEnd();
   590     }
   592     /**
   593      * Print link for previous file.
   594      *
   595      * @param prev File name for the prev link.
   596      */
   597     public void navLinkPrevious(String prev) {
   598         String tag = configuration.getText("doclet.Prev");
   599         if (prev != null) {
   600             printHyperLink(prev, "", tag, true) ;
   601         } else {
   602             print(tag);
   603         }
   604     }
   606     /**
   607      * Print link for next file.  If next is null, just print the label
   608      * without linking it anywhere.
   609      *
   610      * @param next File name for the next link.
   611      */
   612     public void navLinkNext(String next) {
   613         String tag = configuration.getText("doclet.Next");
   614         if (next != null) {
   615             printHyperLink(next, "", tag, true);
   616         } else {
   617             print(tag);
   618         }
   619     }
   621     /**
   622      * Print "FRAMES" link, to switch to the frame version of the output.
   623      *
   624      * @param link File to be linked, "index.html".
   625      */
   626     protected void navShowLists(String link) {
   627         print(getHyperLink(link + "?" + path + filename, "",
   628             configuration.getText("doclet.FRAMES"), true, "", "", "_top"));
   629     }
   631     /**
   632      * Print "FRAMES" link, to switch to the frame version of the output.
   633      */
   634     protected void navShowLists() {
   635         navShowLists(relativePath + "index.html");
   636     }
   638     /**
   639      * Print "NO FRAMES" link, to switch to the non-frame version of the output.
   640      *
   641      * @param link File to be linked.
   642      */
   643     protected void navHideLists(String link) {
   644         print(getHyperLink(link, "", configuration.getText("doclet.NO_FRAMES"),
   645             true, "", "", "_top"));
   646     }
   648     /**
   649      * Print "Tree" link in the navigation bar. If there is only one package
   650      * specified on the command line, then the "Tree" link will be to the
   651      * only "package-tree.html" file otherwise it will be to the
   652      * "overview-tree.html" file.
   653      */
   654     protected void navLinkTree() {
   655         navCellStart();
   656         PackageDoc[] packages = configuration.root.specifiedPackages();
   657         if (packages.length == 1 && configuration.root.specifiedClasses().length == 0) {
   658             printHyperLink(pathString(packages[0], "package-tree.html"), "",
   659                            configuration.getText("doclet.Tree"), true, "NavBarFont1");
   660         } else {
   661             printHyperLink(relativePath + "overview-tree.html", "",
   662                            configuration.getText("doclet.Tree"), true, "NavBarFont1");
   663         }
   664         navCellEnd();
   665     }
   667     /**
   668      * Print "Tree" link to the "overview-tree.html" file.
   669      */
   670     protected void navLinkMainTree(String label) {
   671         printHyperLink(relativePath + "overview-tree.html", label);
   672     }
   674     /**
   675      * Print the word "Class" in the navigation bar cell, to indicate that
   676      * class link is not available.
   677      */
   678     protected void navLinkClass() {
   679         navCellStart();
   680         fontStyle("NavBarFont1");
   681         printText("doclet.Class");
   682         fontEnd();
   683         navCellEnd();
   684     }
   686     /**
   687      * Print "Deprecated" API link in the navigation bar.
   688      */
   689     protected void navLinkDeprecated() {
   690         navCellStart();
   691         printHyperLink(relativePath + "deprecated-list.html", "",
   692                        configuration.getText("doclet.navDeprecated"), true, "NavBarFont1");
   693         navCellEnd();
   694     }
   696     /**
   697      * Print link for generated index. If the user has used "-splitindex"
   698      * command line option, then link to file "index-files/index-1.html" is
   699      * generated otherwise link to file "index-all.html" is generated.
   700      */
   701     protected void navLinkClassIndex() {
   702         printNoFramesTargetHyperLink(relativePath +
   703                 AllClassesFrameWriter.OUTPUT_FILE_NAME_NOFRAMES,
   704             "", "", configuration.getText("doclet.All_Classes"), true);
   705     }
   706     /**
   707      * Print link for generated class index.
   708      */
   709     protected void navLinkIndex() {
   710         navCellStart();
   711         printHyperLink(relativePath +
   712                            (configuration.splitindex?
   713                                 DirectoryManager.getPath("index-files") +
   714                                 fileseparator: "") +
   715                            (configuration.splitindex?
   716                                 "index-1.html" : "index-all.html"), "",
   717                        configuration.getText("doclet.Index"), true, "NavBarFont1");
   718         navCellEnd();
   719     }
   721     /**
   722      * Print help file link. If user has provided a help file, then generate a
   723      * link to the user given file, which is already copied to current or
   724      * destination directory.
   725      */
   726     protected void navLinkHelp() {
   727         String helpfilenm = configuration.helpfile;
   728         if (helpfilenm.equals("")) {
   729             helpfilenm = "help-doc.html";
   730         } else {
   731             int lastsep;
   732             if ((lastsep = helpfilenm.lastIndexOf(File.separatorChar)) != -1) {
   733                 helpfilenm = helpfilenm.substring(lastsep + 1);
   734             }
   735         }
   736         navCellStart();
   737         printHyperLink(relativePath + helpfilenm, "",
   738                        configuration.getText("doclet.Help"), true, "NavBarFont1");
   739         navCellEnd();
   740     }
   742     /**
   743      * Print the word "Detail" in the navigation bar. No link is available.
   744      */
   745     protected void navDetail() {
   746         printText("doclet.Detail");
   747     }
   749     /**
   750      * Print the word "Summary" in the navigation bar. No link is available.
   751      */
   752     protected void navSummary() {
   753         printText("doclet.Summary");
   754     }
   756     /**
   757      * Print the Html table tag for the index summary tables. The table tag
   758      * printed is
   759      * &lt;TABLE BORDER="1" CELLPADDING="3" CELLSPACING="0" WIDTH="100%">
   760      */
   761     public void tableIndexSummary() {
   762         table(1, "100%", 3, 0);
   763     }
   765     /**
   766      * Same as {@link #tableIndexSummary()}.
   767      */
   768     public void tableIndexDetail() {
   769         table(1, "100%", 3, 0);
   770     }
   772     /**
   773      * Print Html tag for table elements. The tag printed is
   774      * &lt;TD ALIGN="right" VALIGN="top" WIDTH="1%"&gt;.
   775      */
   776     public void tdIndex() {
   777         print("<TD ALIGN=\"right\" VALIGN=\"top\" WIDTH=\"1%\">");
   778     }
   780     /**
   781      * Prine table header information about color, column span and the font.
   782      *
   783      * @param color Background color.
   784      * @param span  Column span.
   785      */
   786     public void tableHeaderStart(String color, int span) {
   787         trBgcolorStyle(color, "TableHeadingColor");
   788         thAlignColspan("left", span);
   789         font("+2");
   790     }
   792     /**
   793      * Print table header for the inherited members summary tables. Print the
   794      * background color information.
   795      *
   796      * @param color Background color.
   797      */
   798     public void tableInheritedHeaderStart(String color) {
   799         trBgcolorStyle(color, "TableSubHeadingColor");
   800         thAlign("left");
   801     }
   803     /**
   804      * Print "Use" table header. Print the background color and the column span.
   805      *
   806      * @param color Background color.
   807      */
   808     public void tableUseInfoHeaderStart(String color) {
   809         trBgcolorStyle(color, "TableSubHeadingColor");
   810         thAlignColspan("left", 2);
   811     }
   813     /**
   814      * Print table header with the background color with default column span 2.
   815      *
   816      * @param color Background color.
   817      */
   818     public void tableHeaderStart(String color) {
   819         tableHeaderStart(color, 2);
   820     }
   822     /**
   823      * Print table header with the column span, with the default color #CCCCFF.
   824      *
   825      * @param span Column span.
   826      */
   827     public void tableHeaderStart(int span) {
   828         tableHeaderStart("#CCCCFF", span);
   829     }
   831     /**
   832      * Print table header with default column span 2 and default color #CCCCFF.
   833      */
   834     public void tableHeaderStart() {
   835         tableHeaderStart(2);
   836     }
   838     /**
   839      * Print table header end tags for font, column and row.
   840      */
   841     public void tableHeaderEnd() {
   842         fontEnd();
   843         thEnd();
   844         trEnd();
   845     }
   847     /**
   848      * Print table header end tags in inherited tables for column and row.
   849      */
   850     public void tableInheritedHeaderEnd() {
   851         thEnd();
   852         trEnd();
   853     }
   855     /**
   856      * Print the summary table row cell attribute width.
   857      *
   858      * @param width Width of the table cell.
   859      */
   860     public void summaryRow(int width) {
   861         if (width != 0) {
   862             tdWidth(width + "%");
   863         } else {
   864             td();
   865         }
   866     }
   868     /**
   869      * Print the summary table row cell end tag.
   870      */
   871     public void summaryRowEnd() {
   872         tdEnd();
   873     }
   875     /**
   876      * Print the heading in Html &lt;H2> format.
   877      *
   878      * @param str The Header string.
   879      */
   880     public void printIndexHeading(String str) {
   881         h2();
   882         print(str);
   883         h2End();
   884     }
   886     /**
   887      * Print Html tag &lt;FRAMESET=arg&gt;.
   888      *
   889      * @param arg Argument for the tag.
   890      */
   891     public void frameSet(String arg) {
   892         println("<FRAMESET " + arg + ">");
   893     }
   895     /**
   896      * Print Html closing tag &lt;/FRAMESET&gt;.
   897      */
   898     public void frameSetEnd() {
   899         println("</FRAMESET>");
   900     }
   902     /**
   903      * Print Html tag &lt;FRAME=arg&gt;.
   904      *
   905      * @param arg Argument for the tag.
   906      */
   907     public void frame(String arg) {
   908         println("<FRAME " + arg + ">");
   909     }
   911     /**
   912      * Print Html closing tag &lt;/FRAME&gt;.
   913      */
   914     public void frameEnd() {
   915         println("</FRAME>");
   916     }
   918     /**
   919      * Return path to the class page for a classdoc. For example, the class
   920      * name is "java.lang.Object" and if the current file getting generated is
   921      * "java/io/File.html", then the path string to the class, returned is
   922      * "../../java/lang.Object.html".
   923      *
   924      * @param cd Class to which the path is requested.
   925      */
   926     protected String pathToClass(ClassDoc cd) {
   927         return pathString(cd.containingPackage(), cd.name() + ".html");
   928     }
   930     /**
   931      * Return the path to the class page for a classdoc. Works same as
   932      * {@link #pathToClass(ClassDoc)}.
   933      *
   934      * @param cd   Class to which the path is requested.
   935      * @param name Name of the file(doesn't include path).
   936      */
   937     protected String pathString(ClassDoc cd, String name) {
   938         return pathString(cd.containingPackage(), name);
   939     }
   941     /**
   942      * Return path to the given file name in the given package. So if the name
   943      * passed is "Object.html" and the name of the package is "java.lang", and
   944      * if the relative path is "../.." then returned string will be
   945      * "../../java/lang/Object.html"
   946      *
   947      * @param pd Package in which the file name is assumed to be.
   948      * @param name File name, to which path string is.
   949      */
   950     protected String pathString(PackageDoc pd, String name) {
   951         StringBuffer buf = new StringBuffer(relativePath);
   952         buf.append(DirectoryManager.getPathToPackage(pd, name));
   953         return buf.toString();
   954     }
   956     /**
   957      * Print the link to the given package.
   958      *
   959      * @param pkg the package to link to.
   960      * @param label the label for the link.
   961      * @param isBold true if the label should be bold.
   962      */
   963     public void printPackageLink(PackageDoc pkg, String label, boolean isBold) {
   964         print(getPackageLink(pkg, label, isBold));
   965     }
   967     /**
   968      * Print the link to the given package.
   969      *
   970      * @param pkg the package to link to.
   971      * @param label the label for the link.
   972      * @param isBold true if the label should be bold.
   973      * @param style  the font of the package link label.
   974      */
   975     public void printPackageLink(PackageDoc pkg, String label, boolean isBold,
   976             String style) {
   977         print(getPackageLink(pkg, label, isBold, style));
   978     }
   980     /**
   981      * Return the link to the given package.
   982      *
   983      * @param pkg the package to link to.
   984      * @param label the label for the link.
   985      * @param isBold true if the label should be bold.
   986      * @return the link to the given package.
   987      */
   988     public String getPackageLink(PackageDoc pkg, String label,
   989                                  boolean isBold) {
   990         return getPackageLink(pkg, label, isBold, "");
   991     }
   993     /**
   994      * Return the link to the given package.
   995      *
   996      * @param pkg the package to link to.
   997      * @param label the label for the link.
   998      * @param isBold true if the label should be bold.
   999      * @param style  the font of the package link label.
  1000      * @return the link to the given package.
  1001      */
  1002     public String getPackageLink(PackageDoc pkg, String label, boolean isBold,
  1003             String style) {
  1004         boolean included = pkg != null && pkg.isIncluded();
  1005         if (! included) {
  1006             PackageDoc[] packages = configuration.packages;
  1007             for (int i = 0; i < packages.length; i++) {
  1008                 if (packages[i].equals(pkg)) {
  1009                     included = true;
  1010                     break;
  1014         if (included || pkg == null) {
  1015             return getHyperLink(pathString(pkg, "package-summary.html"),
  1016                                 "", label, isBold, style);
  1017         } else {
  1018             String crossPkgLink = getCrossPackageLink(Util.getPackageName(pkg));
  1019             if (crossPkgLink != null) {
  1020                 return getHyperLink(crossPkgLink, "", label, isBold, style);
  1021             } else {
  1022                 return label;
  1027     public String italicsClassName(ClassDoc cd, boolean qual) {
  1028         String name = (qual)? cd.qualifiedName(): cd.name();
  1029         return (cd.isInterface())?  italicsText(name): name;
  1032     public void printSrcLink(ProgramElementDoc d, String label) {
  1033         if (d == null) {
  1034             return;
  1036         ClassDoc cd = d.containingClass();
  1037         if (cd == null) {
  1038             //d must be a class doc since in has no containing class.
  1039             cd = (ClassDoc) d;
  1041         String href = relativePath + DocletConstants.SOURCE_OUTPUT_DIR_NAME
  1042             + DirectoryManager.getDirectoryPath(cd.containingPackage())
  1043             + cd.name() + ".html#" + SourceToHTMLConverter.getAnchorName(d);
  1044         printHyperLink(href, "", label, true);
  1047     /**
  1048      * Return the link to the given class.
  1050      * @param linkInfo the information about the link.
  1052      * @return the link for the given class.
  1053      */
  1054     public String getLink(LinkInfoImpl linkInfo) {
  1055         LinkFactoryImpl factory = new LinkFactoryImpl(this);
  1056         String link = ((LinkOutputImpl) factory.getLinkOutput(linkInfo)).toString();
  1057         displayLength += linkInfo.displayLength;
  1058         return link;
  1061     /**
  1062      * Return the type parameters for the given class.
  1064      * @param linkInfo the information about the link.
  1065      * @return the type for the given class.
  1066      */
  1067     public String getTypeParameterLinks(LinkInfoImpl linkInfo) {
  1068         LinkFactoryImpl factory = new LinkFactoryImpl(this);
  1069         return ((LinkOutputImpl)
  1070             factory.getTypeParameterLinks(linkInfo, false)).toString();
  1073     /**
  1074      * Print the link to the given class.
  1075      */
  1076     public void printLink(LinkInfoImpl linkInfo) {
  1077         print(getLink(linkInfo));
  1080     /*************************************************************
  1081      * Return a class cross link to external class documentation.
  1082      * The name must be fully qualified to determine which package
  1083      * the class is in.  The -link option does not allow users to
  1084      * link to external classes in the "default" package.
  1086      * @param qualifiedClassName the qualified name of the external class.
  1087      * @param refMemName the name of the member being referenced.  This should
  1088      * be null or empty string if no member is being referenced.
  1089      * @param label the label for the external link.
  1090      * @param bold true if the link should be bold.
  1091      * @param style the style of the link.
  1092      * @param code true if the label should be code font.
  1093      */
  1094     public String getCrossClassLink(String qualifiedClassName, String refMemName,
  1095                                     String label, boolean bold, String style,
  1096                                     boolean code) {
  1097         String className = "",
  1098             packageName = qualifiedClassName == null ? "" : qualifiedClassName;
  1099         int periodIndex;
  1100         while((periodIndex = packageName.lastIndexOf('.')) != -1) {
  1101             className = packageName.substring(periodIndex + 1, packageName.length()) +
  1102                 (className.length() > 0 ? "." + className : "");
  1103             String defaultLabel = code ? getCode() + className + getCodeEnd() : className;
  1104             packageName = packageName.substring(0, periodIndex);
  1105             if (getCrossPackageLink(packageName) != null) {
  1106                 //The package exists in external documentation, so link to the external
  1107                 //class (assuming that it exists).  This is definitely a limitation of
  1108                 //the -link option.  There are ways to determine if an external package
  1109                 //exists, but no way to determine if the external class exists.  We just
  1110                 //have to assume that it does.
  1111                 return getHyperLink(
  1112                     configuration.extern.getExternalLink(packageName, relativePath,
  1113                                 className + ".html?is-external=true"),
  1114                     refMemName == null ? "" : refMemName,
  1115                     label == null || label.length() == 0 ? defaultLabel : label,
  1116                     bold, style,
  1117                     configuration.getText("doclet.Href_Class_Or_Interface_Title", packageName),
  1118                     "");
  1121         return null;
  1124     public boolean isClassLinkable(ClassDoc cd) {
  1125         if (cd.isIncluded()) {
  1126             return configuration.isGeneratedDoc(cd);
  1128         return configuration.extern.isExternal(cd);
  1131     public String getCrossPackageLink(String pkgName) {
  1132         return configuration.extern.getExternalLink(pkgName, relativePath,
  1133             "package-summary.html?is-external=true");
  1136     public void printQualifiedClassLink(int context, ClassDoc cd) {
  1137         printLink(new LinkInfoImpl(context, cd,
  1138             configuration.getClassName(cd), ""));
  1141     /**
  1142      * Print Class link, with only class name as the link and prefixing
  1143      * plain package name.
  1144      */
  1145     public void printPreQualifiedClassLink(int context, ClassDoc cd) {
  1146         print(getPreQualifiedClassLink(context, cd, false));
  1149     /**
  1150      * Retrieve the class link with the package portion of the label in
  1151      * plain text.  If the qualifier is excluded, it willnot be included in the
  1152      * link label.
  1154      * @param cd the class to link to.
  1155      * @param isBold true if the link should be bold.
  1156      * @return the link with the package portion of the label in plain text.
  1157      */
  1158     public String getPreQualifiedClassLink(int context,
  1159             ClassDoc cd, boolean isBold) {
  1160         String classlink = "";
  1161         PackageDoc pd = cd.containingPackage();
  1162         if(pd != null && ! configuration.shouldExcludeQualifier(pd.name())) {
  1163             classlink = getPkgName(cd);
  1165         classlink += getLink(new LinkInfoImpl(context, cd, cd.name(), isBold));
  1166         return classlink;
  1170     /**
  1171      * Print Class link, with only class name as the bold link and prefixing
  1172      * plain package name.
  1173      */
  1174     public void printPreQualifiedBoldClassLink(int context, ClassDoc cd) {
  1175         print(getPreQualifiedClassLink(context, cd, true));
  1178     public void printText(String key) {
  1179         print(configuration.getText(key));
  1182     public void printText(String key, String a1) {
  1183         print(configuration.getText(key, a1));
  1186     public void printText(String key, String a1, String a2) {
  1187         print(configuration.getText(key, a1, a2));
  1190     public void boldText(String key) {
  1191         bold(configuration.getText(key));
  1194     public void boldText(String key, String a1) {
  1195         bold(configuration.getText(key, a1));
  1198     public void boldText(String key, String a1, String a2) {
  1199         bold(configuration.getText(key, a1, a2));
  1202     /**
  1203      * Print the link for the given member.
  1205      * @param context the id of the context where the link will be printed.
  1206      * @param doc the member being linked to.
  1207      * @param label the label for the link.
  1208      * @param bold true if the link should be bold.
  1209      */
  1210     public void printDocLink(int context, MemberDoc doc, String label,
  1211             boolean bold) {
  1212         print(getDocLink(context, doc, label, bold));
  1215     /**
  1216      * Print the link for the given member.
  1218      * @param context the id of the context where the link will be printed.
  1219      * @param classDoc the classDoc that we should link to.  This is not
  1220      *                 necessarily equal to doc.containingClass().  We may be
  1221      *                 inheriting comments.
  1222      * @param doc the member being linked to.
  1223      * @param label the label for the link.
  1224      * @param bold true if the link should be bold.
  1225      */
  1226     public void printDocLink(int context, ClassDoc classDoc, MemberDoc doc,
  1227             String label, boolean bold) {
  1228         print(getDocLink(context, classDoc, doc, label, bold));
  1231     /**
  1232      * Return the link for the given member.
  1234      * @param context the id of the context where the link will be printed.
  1235      * @param doc the member being linked to.
  1236      * @param label the label for the link.
  1237      * @param bold true if the link should be bold.
  1238      * @return the link for the given member.
  1239      */
  1240     public String getDocLink(int context, MemberDoc doc, String label,
  1241                 boolean bold) {
  1242         return getDocLink(context, doc.containingClass(), doc, label, bold);
  1245     /**
  1246      * Return the link for the given member.
  1248      * @param context the id of the context where the link will be printed.
  1249      * @param classDoc the classDoc that we should link to.  This is not
  1250      *                 necessarily equal to doc.containingClass().  We may be
  1251      *                 inheriting comments.
  1252      * @param doc the member being linked to.
  1253      * @param label the label for the link.
  1254      * @param bold true if the link should be bold.
  1255      * @return the link for the given member.
  1256      */
  1257     public String getDocLink(int context, ClassDoc classDoc, MemberDoc doc,
  1258         String label, boolean bold) {
  1259         if (! (doc.isIncluded() ||
  1260             Util.isLinkable(classDoc, configuration()))) {
  1261             return label;
  1262         } else if (doc instanceof ExecutableMemberDoc) {
  1263             ExecutableMemberDoc emd = (ExecutableMemberDoc)doc;
  1264             return getLink(new LinkInfoImpl(context, classDoc,
  1265                 getAnchor(emd), label, bold));
  1266         } else if (doc instanceof MemberDoc) {
  1267             return getLink(new LinkInfoImpl(context, classDoc,
  1268                 doc.name(), label, bold));
  1269         } else {
  1270             return label;
  1274     public void anchor(ExecutableMemberDoc emd) {
  1275         anchor(getAnchor(emd));
  1278     public String getAnchor(ExecutableMemberDoc emd) {
  1279         StringBuilder signature = new StringBuilder(emd.signature());
  1280         StringBuilder signatureParsed = new StringBuilder();
  1281         int counter = 0;
  1282         for (int i = 0; i < signature.length(); i++) {
  1283             char c = signature.charAt(i);
  1284             if (c == '<') {
  1285                 counter++;
  1286             } else if (c == '>') {
  1287                 counter--;
  1288             } else if (counter == 0) {
  1289                 signatureParsed.append(c);
  1292         return emd.name() + signatureParsed.toString();
  1295     public String seeTagToString(SeeTag see) {
  1296         String tagName = see.name();
  1297         if (! (tagName.startsWith("@link") || tagName.equals("@see"))) {
  1298             return "";
  1300         StringBuffer result = new StringBuffer();
  1301         boolean isplaintext = tagName.toLowerCase().equals("@linkplain");
  1302         String label = see.label();
  1303         label = (label.length() > 0)?
  1304             ((isplaintext) ? label :
  1305                  getCode() + label + getCodeEnd()):"";
  1306         String seetext = replaceDocRootDir(see.text());
  1308         //Check if @see is an href or "string"
  1309         if (seetext.startsWith("<") || seetext.startsWith("\"")) {
  1310             result.append(seetext);
  1311             return result.toString();
  1314         //The text from the @see tag.  We will output this text when a label is not specified.
  1315         String text = (isplaintext) ? seetext : getCode() + seetext + getCodeEnd();
  1317         ClassDoc refClass = see.referencedClass();
  1318         String refClassName = see.referencedClassName();
  1319         MemberDoc refMem = see.referencedMember();
  1320         String refMemName = see.referencedMemberName();
  1321         if (refClass == null) {
  1322             //@see is not referencing an included class
  1323             PackageDoc refPackage = see.referencedPackage();
  1324             if (refPackage != null && refPackage.isIncluded()) {
  1325                 //@see is referencing an included package
  1326                 String packageName = isplaintext ? refPackage.name() :
  1327                     getCode() + refPackage.name() + getCodeEnd();
  1328                 result.append(getPackageLink(refPackage,
  1329                     label.length() == 0 ? packageName : label, false));
  1330             } else {
  1331                 //@see is not referencing an included class or package.  Check for cross links.
  1332                 String classCrossLink, packageCrossLink = getCrossPackageLink(refClassName);
  1333                 if (packageCrossLink != null) {
  1334                     //Package cross link found
  1335                     result.append(getHyperLink(packageCrossLink, "",
  1336                         (label.length() == 0)? text : label, false));
  1337                 } else if ((classCrossLink = getCrossClassLink(refClassName,
  1338                         refMemName, label, false, "", ! isplaintext)) != null) {
  1339                     //Class cross link found (possiblly to a member in the class)
  1340                     result.append(classCrossLink);
  1341                 } else {
  1342                     //No cross link found so print warning
  1343                     configuration.getDocletSpecificMsg().warning(see.position(), "doclet.see.class_or_package_not_found",
  1344                             tagName, seetext);
  1345                     result.append((label.length() == 0)? text: label);
  1348         } else if (refMemName == null) {
  1349             // Must be a class reference since refClass is not null and refMemName is null.
  1350             if (label.length() == 0) {
  1351                 label = (isplaintext) ? refClass.name() : getCode() + refClass.name() + getCodeEnd();
  1352                 result.append(getLink(new LinkInfoImpl(refClass, label)));
  1353             } else {
  1354                 result.append(getLink(new LinkInfoImpl(refClass, label)));
  1356         } else if (refMem == null) {
  1357             // Must be a member reference since refClass is not null and refMemName is not null.
  1358             // However, refMem is null, so this referenced member does not exist.
  1359             result.append((label.length() == 0)? text: label);
  1360         } else {
  1361             // Must be a member reference since refClass is not null and refMemName is not null.
  1362             // refMem is not null, so this @see tag must be referencing a valid member.
  1363             ClassDoc containing = refMem.containingClass();
  1364             if (see.text().trim().startsWith("#") &&
  1365                 ! (containing.isPublic() ||
  1366                 Util.isLinkable(containing, configuration()))) {
  1367                 // Since the link is relative and the holder is not even being
  1368                 // documented, this must be an inherited link.  Redirect it.
  1369                 // The current class either overrides the referenced member or
  1370                 // inherits it automatically.
  1371                 containing = ((ClassWriterImpl) this).getClassDoc();
  1373             if (configuration.currentcd != containing) {
  1374                 refMemName = containing.name() + "." + refMemName;
  1376             if (refMem instanceof ExecutableMemberDoc) {
  1377                 if (refMemName.indexOf('(') < 0) {
  1378                     refMemName += ((ExecutableMemberDoc)refMem).signature();
  1381             text = (isplaintext) ?
  1382                 refMemName : getCode() + refMemName + getCodeEnd();
  1384             result.append(getDocLink(LinkInfoImpl.CONTEXT_SEE_TAG, containing,
  1385                 refMem, (label.length() == 0)? text: label, false));
  1387         return result.toString();
  1390     public void printInlineComment(Doc doc, Tag tag) {
  1391         printCommentTags(doc, tag.inlineTags(), false, false);
  1394     public void printInlineDeprecatedComment(Doc doc, Tag tag) {
  1395         printCommentTags(doc, tag.inlineTags(), true, false);
  1398     public void printSummaryComment(Doc doc) {
  1399         printSummaryComment(doc, doc.firstSentenceTags());
  1402     public void printSummaryComment(Doc doc, Tag[] firstSentenceTags) {
  1403         printCommentTags(doc, firstSentenceTags, false, true);
  1406     public void printSummaryDeprecatedComment(Doc doc) {
  1407         printCommentTags(doc, doc.firstSentenceTags(), true, true);
  1410     public void printSummaryDeprecatedComment(Doc doc, Tag tag) {
  1411         printCommentTags(doc, tag.firstSentenceTags(), true, true);
  1414     public void printInlineComment(Doc doc) {
  1415         printCommentTags(doc, doc.inlineTags(), false, false);
  1416         p();
  1419     public void printInlineDeprecatedComment(Doc doc) {
  1420         printCommentTags(doc, doc.inlineTags(), true, false);
  1423     private void printCommentTags(Doc doc, Tag[] tags, boolean depr, boolean first) {
  1424         if(configuration.nocomment){
  1425             return;
  1427         if (depr) {
  1428             italic();
  1430         String result = commentTagsToString(null, doc, tags, first);
  1431         print(result);
  1432         if (depr) {
  1433             italicEnd();
  1435         if (tags.length == 0) {
  1436             space();
  1440     /**
  1441      * Converts inline tags and text to text strings, expanding the
  1442      * inline tags along the way.  Called wherever text can contain
  1443      * an inline tag, such as in comments or in free-form text arguments
  1444      * to non-inline tags.
  1446      * @param holderTag    specific tag where comment resides
  1447      * @param doc    specific doc where comment resides
  1448      * @param tags   array of text tags and inline tags (often alternating)
  1449      *               present in the text of interest for this doc
  1450      * @param isFirstSentence  true if text is first sentence
  1451      */
  1452     public String commentTagsToString(Tag holderTag, Doc doc, Tag[] tags,
  1453             boolean isFirstSentence) {
  1454         StringBuffer result = new StringBuffer();
  1455         // Array of all possible inline tags for this javadoc run
  1456         configuration.tagletManager.checkTags(doc, tags, true);
  1457         for (int i = 0; i < tags.length; i++) {
  1458             Tag tagelem = tags[i];
  1459             String tagName = tagelem.name();
  1460             if (tagelem instanceof SeeTag) {
  1461                 result.append(seeTagToString((SeeTag)tagelem));
  1462             } else if (! tagName.equals("Text")) {
  1463                 int originalLength = result.length();
  1464                 TagletOutput output = TagletWriter.getInlineTagOuput(
  1465                     configuration.tagletManager, holderTag,
  1466                     tagelem, getTagletWriterInstance(isFirstSentence));
  1467                 result.append(output == null ? "" : output.toString());
  1468                 if (originalLength == 0 && isFirstSentence && tagelem.name().equals("@inheritDoc") && result.length() > 0) {
  1469                     break;
  1470                 } else {
  1471                         continue;
  1473             } else {
  1474                 //This is just a regular text tag.  The text may contain html links (<a>)
  1475                 //or inline tag {@docRoot}, which will be handled as special cases.
  1476                 String text = redirectRelativeLinks(tagelem.holder(), tagelem.text());
  1478                 // Replace @docRoot only if not represented by an instance of DocRootTaglet,
  1479                 // that is, only if it was not present in a source file doc comment.
  1480                 // This happens when inserted by the doclet (a few lines
  1481                 // above in this method).  [It might also happen when passed in on the command
  1482                 // line as a text argument to an option (like -header).]
  1483                 text = replaceDocRootDir(text);
  1484                 if (isFirstSentence) {
  1485                     text = removeNonInlineHtmlTags(text);
  1487                 StringTokenizer lines = new StringTokenizer(text, "\r\n", true);
  1488                 StringBuffer textBuff = new StringBuffer();
  1489                 while (lines.hasMoreTokens()) {
  1490                     StringBuffer line = new StringBuffer(lines.nextToken());
  1491                     Util.replaceTabs(configuration.sourcetab, line);
  1492                     textBuff.append(line.toString());
  1494                 result.append(textBuff);
  1497         return result.toString();
  1500     /**
  1501      * Return true if relative links should not be redirected.
  1503      * @return Return true if a relative link should not be redirected.
  1504      */
  1505     private boolean shouldNotRedirectRelativeLinks() {
  1506         return  this instanceof AnnotationTypeWriter ||
  1507                 this instanceof ClassWriter ||
  1508                 this instanceof PackageSummaryWriter;
  1511     /**
  1512      * Suppose a piece of documentation has a relative link.  When you copy
  1513      * that documetation to another place such as the index or class-use page,
  1514      * that relative link will no longer work.  We should redirect those links
  1515      * so that they will work again.
  1516      * <p>
  1517      * Here is the algorithm used to fix the link:
  1518      * <p>
  1519      * &lt;relative link&gt; => docRoot + &lt;relative path to file&gt; + &lt;relative link&gt;
  1520      * <p>
  1521      * For example, suppose com.sun.javadoc.RootDoc has this link:
  1522      * &lt;a href="package-summary.html"&gt;The package Page&lt;/a&gt;
  1523      * <p>
  1524      * If this link appeared in the index, we would redirect
  1525      * the link like this:
  1527      * &lt;a href="./com/sun/javadoc/package-summary.html"&gt;The package Page&lt;/a&gt;
  1529      * @param doc the Doc object whose documentation is being written.
  1530      * @param text the text being written.
  1532      * @return the text, with all the relative links redirected to work.
  1533      */
  1534     private String redirectRelativeLinks(Doc doc, String text) {
  1535         if (doc == null || shouldNotRedirectRelativeLinks()) {
  1536             return text;
  1539         String redirectPathFromRoot;
  1540         if (doc instanceof ClassDoc) {
  1541             redirectPathFromRoot = DirectoryManager.getDirectoryPath(((ClassDoc) doc).containingPackage());
  1542         } else if (doc instanceof MemberDoc) {
  1543             redirectPathFromRoot = DirectoryManager.getDirectoryPath(((MemberDoc) doc).containingPackage());
  1544         } else if (doc instanceof PackageDoc) {
  1545             redirectPathFromRoot = DirectoryManager.getDirectoryPath((PackageDoc) doc);
  1546         } else {
  1547             return text;
  1550         if (! redirectPathFromRoot.endsWith(DirectoryManager.URL_FILE_SEPERATOR)) {
  1551             redirectPathFromRoot += DirectoryManager.URL_FILE_SEPERATOR;
  1554         //Redirect all relative links.
  1555         int end, begin = text.toLowerCase().indexOf("<a");
  1556         if(begin >= 0){
  1557             StringBuffer textBuff = new StringBuffer(text);
  1559             while(begin >=0){
  1560                 if (textBuff.length() > begin + 2 && ! Character.isWhitespace(textBuff.charAt(begin+2))) {
  1561                     begin = textBuff.toString().toLowerCase().indexOf("<a", begin + 1);
  1562                     continue;
  1565                 begin = textBuff.indexOf("=", begin) + 1;
  1566                 end = textBuff.indexOf(">", begin +1);
  1567                 if(begin == 0){
  1568                     //Link has no equal symbol.
  1569                     configuration.root.printWarning(
  1570                         doc.position(),
  1571                         configuration.getText("doclet.malformed_html_link_tag", text));
  1572                     break;
  1574                 if (end == -1) {
  1575                     //Break without warning.  This <a> tag is not necessarily malformed.  The text
  1576                     //might be missing '>' character because the href has an inline tag.
  1577                     break;
  1579                 if(textBuff.substring(begin, end).indexOf("\"") != -1){
  1580                     begin = textBuff.indexOf("\"", begin) + 1;
  1581                     end = textBuff.indexOf("\"", begin +1);
  1582                     if(begin == 0 || end == -1){
  1583                         //Link is missing a quote.
  1584                         break;
  1587                 String relativeLink = textBuff.substring(begin, end);
  1588                 if(!(relativeLink.toLowerCase().startsWith("mailto:") ||
  1589                      relativeLink.toLowerCase().startsWith("http:") ||
  1590                      relativeLink.toLowerCase().startsWith("https:") ||
  1591                      relativeLink.toLowerCase().startsWith("file:"))){
  1592                      relativeLink = "{@"+(new DocRootTaglet()).getName() + "}"
  1593                         + redirectPathFromRoot
  1594                         + relativeLink;
  1595                     textBuff.replace(begin, end, relativeLink);
  1597                 begin = textBuff.toString().toLowerCase().indexOf("<a", begin + 1);
  1599             return textBuff.toString();
  1601         return text;
  1604     public String removeNonInlineHtmlTags(String text) {
  1605         if (text.indexOf('<') < 0) {
  1606             return text;
  1608         String noninlinetags[] = { "<ul>", "</ul>", "<ol>", "</ol>",
  1609                 "<dl>", "</dl>", "<table>", "</table>",
  1610                 "<tr>", "</tr>", "<td>", "</td>",
  1611                 "<th>", "</th>", "<p>", "</p>",
  1612                 "<li>", "</li>", "<dd>", "</dd>",
  1613                 "<dir>", "</dir>", "<dt>", "</dt>",
  1614                 "<h1>", "</h1>", "<h2>", "</h2>",
  1615                 "<h3>", "</h3>", "<h4>", "</h4>",
  1616                 "<h5>", "</h5>", "<h6>", "</h6>",
  1617                 "<pre>", "</pre>", "<menu>", "</menu>",
  1618                 "<listing>", "</listing>", "<hr>",
  1619                 "<blockquote>", "</blockquote>",
  1620                 "<center>", "</center>",
  1621                 "<UL>", "</UL>", "<OL>", "</OL>",
  1622                 "<DL>", "</DL>", "<TABLE>", "</TABLE>",
  1623                 "<TR>", "</TR>", "<TD>", "</TD>",
  1624                 "<TH>", "</TH>", "<P>", "</P>",
  1625                 "<LI>", "</LI>", "<DD>", "</DD>",
  1626                 "<DIR>", "</DIR>", "<DT>", "</DT>",
  1627                 "<H1>", "</H1>", "<H2>", "</H2>",
  1628                 "<H3>", "</H3>", "<H4>", "</H4>",
  1629                 "<H5>", "</H5>", "<H6>", "</H6>",
  1630                 "<PRE>", "</PRE>", "<MENU>", "</MENU>",
  1631                 "<LISTING>", "</LISTING>", "<HR>",
  1632                 "<BLOCKQUOTE>", "</BLOCKQUOTE>",
  1633                 "<CENTER>", "</CENTER>"
  1634         };
  1635         for (int i = 0; i < noninlinetags.length; i++) {
  1636             text = replace(text, noninlinetags[i], "");
  1638         return text;
  1641     public String replace(String text, String tobe, String by) {
  1642         while (true) {
  1643             int startindex = text.indexOf(tobe);
  1644             if (startindex < 0) {
  1645                 return text;
  1647             int endindex = startindex + tobe.length();
  1648             StringBuffer replaced = new StringBuffer();
  1649             if (startindex > 0) {
  1650                 replaced.append(text.substring(0, startindex));
  1652             replaced.append(by);
  1653             if (text.length() > endindex) {
  1654                 replaced.append(text.substring(endindex));
  1656             text = replaced.toString();
  1660     public void printStyleSheetProperties() {
  1661         String filename = configuration.stylesheetfile;
  1662         if (filename.length() > 0) {
  1663             File stylefile = new File(filename);
  1664             String parent = stylefile.getParent();
  1665             filename = (parent == null)?
  1666                 filename:
  1667                 filename.substring(parent.length() + 1);
  1668         } else {
  1669             filename = "stylesheet.css";
  1671         filename = relativePath + filename;
  1672         link("REL =\"stylesheet\" TYPE=\"text/css\" HREF=\"" +
  1673                  filename + "\" " + "TITLE=\"Style\"");
  1676     /**
  1677      * According to the Java Language Specifications, all the outer classes
  1678      * and static nested classes are core classes.
  1679      */
  1680     public boolean isCoreClass(ClassDoc cd) {
  1681         return cd.containingClass() == null || cd.isStatic();
  1684     /**
  1685      * Write the annotatation types for the given packageDoc.
  1687      * @param packageDoc the package to write annotations for.
  1688      */
  1689     public void writeAnnotationInfo(PackageDoc packageDoc) {
  1690         writeAnnotationInfo(packageDoc, packageDoc.annotations());
  1693     /**
  1694      * Write the annotatation types for the given doc.
  1696      * @param doc the doc to write annotations for.
  1697      */
  1698     public void writeAnnotationInfo(ProgramElementDoc doc) {
  1699         writeAnnotationInfo(doc, doc.annotations());
  1702     /**
  1703      * Write the annotatation types for the given doc and parameter.
  1705      * @param indent the number of spaced to indent the parameters.
  1706      * @param doc the doc to write annotations for.
  1707      * @param param the parameter to write annotations for.
  1708      */
  1709     public boolean writeAnnotationInfo(int indent, Doc doc, Parameter param) {
  1710         return writeAnnotationInfo(indent, doc, param.annotations(), false);
  1713     /**
  1714      * Write the annotatation types for the given doc.
  1716      * @param doc the doc to write annotations for.
  1717      * @param descList the array of {@link AnnotationDesc}.
  1718      */
  1719     private void writeAnnotationInfo(Doc doc, AnnotationDesc[] descList) {
  1720         writeAnnotationInfo(0, doc, descList, true);
  1723     /**
  1724      * Write the annotatation types for the given doc.
  1726      * @param indent the number of extra spaces to indent the annotations.
  1727      * @param doc the doc to write annotations for.
  1728      * @param descList the array of {@link AnnotationDesc}.
  1729      */
  1730     private boolean writeAnnotationInfo(int indent, Doc doc, AnnotationDesc[] descList, boolean lineBreak) {
  1731         List annotations = getAnnotations(indent, descList, lineBreak);
  1732         if (annotations.size() == 0) {
  1733             return false;
  1735         fontNoNewLine("-1");
  1736         for (Iterator iter = annotations.iterator(); iter.hasNext();) {
  1737             print((String) iter.next());
  1739         fontEnd();
  1740         return true;
  1743     /**
  1744      * Return the string representations of the annotation types for
  1745      * the given doc.
  1747      * @param indent the number of extra spaces to indent the annotations.
  1748      * @param descList the array of {@link AnnotationDesc}.
  1749      * @param linkBreak if true, add new line between each member value.
  1750      * @return an array of strings representing the annotations being
  1751      *         documented.
  1752      */
  1753     private List<String> getAnnotations(int indent, AnnotationDesc[] descList, boolean linkBreak) {
  1754         List<String> results = new ArrayList<String>();
  1755         StringBuffer annotation;
  1756         for (int i = 0; i < descList.length; i++) {
  1757             AnnotationTypeDoc annotationDoc = descList[i].annotationType();
  1758             if (! Util.isDocumentedAnnotation(annotationDoc)){
  1759                 continue;
  1761             annotation = new StringBuffer();
  1762             LinkInfoImpl linkInfo = new LinkInfoImpl(
  1763                 LinkInfoImpl.CONTEXT_ANNOTATION, annotationDoc);
  1764             linkInfo.label = "@" + annotationDoc.name();
  1765             annotation.append(getLink(linkInfo));
  1766             AnnotationDesc.ElementValuePair[] pairs = descList[i].elementValues();
  1767             if (pairs.length > 0) {
  1768                 annotation.append('(');
  1769                 for (int j = 0; j < pairs.length; j++) {
  1770                     if (j > 0) {
  1771                         annotation.append(",");
  1772                         if (linkBreak) {
  1773                             annotation.append(DocletConstants.NL);
  1774                             int spaces = annotationDoc.name().length() + 2;
  1775                             for (int k = 0; k < (spaces + indent); k++) {
  1776                                 annotation.append(' ');
  1780                     annotation.append(getDocLink(LinkInfoImpl.CONTEXT_ANNOTATION,
  1781                         pairs[j].element(), pairs[j].element().name(), false));
  1782                     annotation.append('=');
  1783                     AnnotationValue annotationValue = pairs[j].value();
  1784                     List<AnnotationValue> annotationTypeValues = new ArrayList<AnnotationValue>();
  1785                     if (annotationValue.value() instanceof AnnotationValue[]) {
  1786                         AnnotationValue[] annotationArray =
  1787                             (AnnotationValue[]) annotationValue.value();
  1788                         for (int k = 0; k < annotationArray.length; k++) {
  1789                             annotationTypeValues.add(annotationArray[k]);
  1791                     } else {
  1792                         annotationTypeValues.add(annotationValue);
  1794                     annotation.append(annotationTypeValues.size() == 1 ? "" : "{");
  1795                     for (Iterator iter = annotationTypeValues.iterator(); iter.hasNext(); ) {
  1796                         annotation.append(annotationValueToString((AnnotationValue) iter.next()));
  1797                         annotation.append(iter.hasNext() ? "," : "");
  1799                     annotation.append(annotationTypeValues.size() == 1 ? "" : "}");
  1801                 annotation.append(")");
  1803             annotation.append(linkBreak ? DocletConstants.NL : "");
  1804             results.add(annotation.toString());
  1806         return results;
  1809     private String annotationValueToString(AnnotationValue annotationValue) {
  1810         if (annotationValue.value() instanceof Type) {
  1811             Type type = (Type) annotationValue.value();
  1812             if (type.asClassDoc() != null) {
  1813                 LinkInfoImpl linkInfo = new LinkInfoImpl(
  1814                     LinkInfoImpl.CONTEXT_ANNOTATION, type);
  1815                     linkInfo.label = (type.asClassDoc().isIncluded() ?
  1816                         type.typeName() :
  1817                         type.qualifiedTypeName()) + type.dimension() + ".class";
  1818                 return getLink(linkInfo);
  1819             } else {
  1820                 return type.typeName() + type.dimension() + ".class";
  1822         } else if (annotationValue.value() instanceof AnnotationDesc) {
  1823             List list = getAnnotations(0,
  1824                 new AnnotationDesc[]{(AnnotationDesc) annotationValue.value()},
  1825                     false);
  1826             StringBuffer buf = new StringBuffer();
  1827             for (Iterator iter = list.iterator(); iter.hasNext(); ) {
  1828                 buf.append(iter.next());
  1830             return buf.toString();
  1831         } else if (annotationValue.value() instanceof MemberDoc) {
  1832             return getDocLink(LinkInfoImpl.CONTEXT_ANNOTATION,
  1833                 (MemberDoc) annotationValue.value(),
  1834                 ((MemberDoc) annotationValue.value()).name(), false);
  1835          } else {
  1836             return annotationValue.toString();
  1840     /**
  1841      * Return the configuation for this doclet.
  1843      * @return the configuration for this doclet.
  1844      */
  1845     public Configuration configuration() {
  1846         return configuration;

mercurial