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

Sat, 05 Jan 2013 00:55:53 -0800

author
bpatel
date
Sat, 05 Jan 2013 00:55:53 -0800
changeset 1477
8c0c63a6e3b7
parent 1417
522a1ee72340
child 1521
71f35e4b93a5
child 1568
5f0731e4e5e6
permissions
-rw-r--r--

8005092: javadoc should check for synthesized bit on an annotation
Reviewed-by: jjg

     1 /*
     2  * Copyright (c) 1998, 2012, Oracle and/or its affiliates. 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.  Oracle designates this
     8  * particular file as subject to the "Classpath" exception as provided
     9  * by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
    22  * or visit www.oracle.com if you need additional information or have any
    23  * 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.taglets.*;
    36 import com.sun.tools.doclets.internal.toolkit.util.*;
    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  *  <p><b>This is NOT part of any supported API.
    44  *  If you write code that depends on this, you do so at your own risk.
    45  *  This code and its internal interfaces are subject to change or
    46  *  deletion without notice.</b>
    47  *
    48  * @since 1.2
    49  * @author Atul M Dambalkar
    50  * @author Robert Field
    51  * @author Bhavesh Patel (Modified)
    52  */
    53 public class HtmlDocletWriter extends HtmlDocWriter {
    55     /**
    56      * Relative path from the file getting generated to the destination
    57      * directory. For example, if the file getting generated is
    58      * "java/lang/Object.html", then the path to the root is "../..".
    59      * This string can be empty if the file getting generated is in
    60      * the destination directory.
    61      */
    62     public final DocPath pathToRoot;
    64     /**
    65      * Platform-independent path from the current or the
    66      * destination directory to the file getting generated.
    67      * Used when creating the file.
    68      */
    69     public final DocPath path;
    71     /**
    72      * Name of the file getting generated. If the file getting generated is
    73      * "java/lang/Object.html", then the filename is "Object.html".
    74      */
    75     public final DocPath filename;
    77     /**
    78      * The display length used for indentation while generating the class page.
    79      */
    80     public int displayLength = 0;
    82     /**
    83      * The global configuration information for this run.
    84      */
    85     public final ConfigurationImpl configuration;
    87     /**
    88      * To check whether annotation heading is printed or not.
    89      */
    90     protected boolean printedAnnotationHeading = false;
    92     /**
    93      * To check whether the repeated annotations is documented or not.
    94      */
    95     private boolean isAnnotationDocumented = false;
    97     /**
    98      * To check whether the container annotations is documented or not.
    99      */
   100     private boolean isContainerDocumented = false;
   102     /**
   103      * Constructor to construct the HtmlStandardWriter object.
   104      *
   105      * @param path File to be generated.
   106      */
   107     public HtmlDocletWriter(ConfigurationImpl configuration, DocPath path)
   108             throws IOException {
   109         super(configuration, path);
   110         this.configuration = configuration;
   111         this.path = path;
   112         this.pathToRoot = path.parent().invert();
   113         this.filename = path.basename();
   114     }
   116     /**
   117      * Replace {&#064;docRoot} tag used in options that accept HTML text, such
   118      * as -header, -footer, -top and -bottom, and when converting a relative
   119      * HREF where commentTagsToString inserts a {&#064;docRoot} where one was
   120      * missing.  (Also see DocRootTaglet for {&#064;docRoot} tags in doc
   121      * comments.)
   122      * <p>
   123      * Replace {&#064;docRoot} tag in htmlstr with the relative path to the
   124      * destination directory from the directory where the file is being
   125      * written, looping to handle all such tags in htmlstr.
   126      * <p>
   127      * For example, for "-d docs" and -header containing {&#064;docRoot}, when
   128      * the HTML page for source file p/C1.java is being generated, the
   129      * {&#064;docRoot} tag would be inserted into the header as "../",
   130      * the relative path from docs/p/ to docs/ (the document root).
   131      * <p>
   132      * Note: This doc comment was written with '&amp;#064;' representing '@'
   133      * to prevent the inline tag from being interpreted.
   134      */
   135     public String replaceDocRootDir(String htmlstr) {
   136         // Return if no inline tags exist
   137         int index = htmlstr.indexOf("{@");
   138         if (index < 0) {
   139             return htmlstr;
   140         }
   141         String lowerHtml = htmlstr.toLowerCase();
   142         // Return index of first occurrence of {@docroot}
   143         // Note: {@docRoot} is not case sensitive when passed in w/command line option
   144         index = lowerHtml.indexOf("{@docroot}", index);
   145         if (index < 0) {
   146             return htmlstr;
   147         }
   148         StringBuilder buf = new StringBuilder();
   149         int previndex = 0;
   150         while (true) {
   151             if (configuration.docrootparent.length() > 0) {
   152                 final String docroot_parent = "{@docroot}/..";
   153                 // Search for lowercase version of {@docRoot}/..
   154                 index = lowerHtml.indexOf(docroot_parent, previndex);
   155                 // If next {@docRoot}/.. pattern not found, append rest of htmlstr and exit loop
   156                 if (index < 0) {
   157                     buf.append(htmlstr.substring(previndex));
   158                     break;
   159                 }
   160                 // If next {@docroot}/.. pattern found, append htmlstr up to start of tag
   161                 buf.append(htmlstr.substring(previndex, index));
   162                 previndex = index + docroot_parent.length();
   163                 // Insert docrootparent absolute path where {@docRoot}/.. was located
   165                 buf.append(configuration.docrootparent);
   166                 // Append slash if next character is not a slash
   167                 if (previndex < htmlstr.length() && htmlstr.charAt(previndex) != '/') {
   168                     buf.append('/');
   169                 }
   170             } else {
   171                 final String docroot = "{@docroot}";
   172                 // Search for lowercase version of {@docRoot}
   173                 index = lowerHtml.indexOf(docroot, previndex);
   174                 // If next {@docRoot} tag not found, append rest of htmlstr and exit loop
   175                 if (index < 0) {
   176                     buf.append(htmlstr.substring(previndex));
   177                     break;
   178                 }
   179                 // If next {@docroot} tag found, append htmlstr up to start of tag
   180                 buf.append(htmlstr.substring(previndex, index));
   181                 previndex = index + docroot.length();
   182                 // Insert relative path where {@docRoot} was located
   183                 buf.append(pathToRoot.isEmpty() ? "." : pathToRoot.getPath());
   184                 // Append slash if next character is not a slash
   185                 if (previndex < htmlstr.length() && htmlstr.charAt(previndex) != '/') {
   186                     buf.append('/');
   187                 }
   188             }
   189         }
   190         return buf.toString();
   191     }
   193     /**
   194      * Get the script to show or hide the All classes link.
   195      *
   196      * @param id id of the element to show or hide
   197      * @return a content tree for the script
   198      */
   199     public Content getAllClassesLinkScript(String id) {
   200         HtmlTree script = new HtmlTree(HtmlTag.SCRIPT);
   201         script.addAttr(HtmlAttr.TYPE, "text/javascript");
   202         String scriptCode = "<!--" + DocletConstants.NL +
   203                 "  allClassesLink = document.getElementById(\"" + id + "\");" + DocletConstants.NL +
   204                 "  if(window==top) {" + DocletConstants.NL +
   205                 "    allClassesLink.style.display = \"block\";" + DocletConstants.NL +
   206                 "  }" + DocletConstants.NL +
   207                 "  else {" + DocletConstants.NL +
   208                 "    allClassesLink.style.display = \"none\";" + DocletConstants.NL +
   209                 "  }" + DocletConstants.NL +
   210                 "  //-->" + DocletConstants.NL;
   211         Content scriptContent = new RawHtml(scriptCode);
   212         script.addContent(scriptContent);
   213         Content div = HtmlTree.DIV(script);
   214         return div;
   215     }
   217     /**
   218      * Add method information.
   219      *
   220      * @param method the method to be documented
   221      * @param dl the content tree to which the method information will be added
   222      */
   223     private void addMethodInfo(MethodDoc method, Content dl) {
   224         ClassDoc[] intfacs = method.containingClass().interfaces();
   225         MethodDoc overriddenMethod = method.overriddenMethod();
   226         // Check whether there is any implementation or overridden info to be
   227         // printed. If no overridden or implementation info needs to be
   228         // printed, do not print this section.
   229         if ((intfacs.length > 0 &&
   230                 new ImplementedMethods(method, this.configuration).build().length > 0) ||
   231                 overriddenMethod != null) {
   232             MethodWriterImpl.addImplementsInfo(this, method, dl);
   233             if (overriddenMethod != null) {
   234                 MethodWriterImpl.addOverridden(this,
   235                         method.overriddenType(), overriddenMethod, dl);
   236             }
   237         }
   238     }
   240     /**
   241      * Adds the tags information.
   242      *
   243      * @param doc the doc for which the tags will be generated
   244      * @param htmltree the documentation tree to which the tags will be added
   245      */
   246     protected void addTagsInfo(Doc doc, Content htmltree) {
   247         if (configuration.nocomment) {
   248             return;
   249         }
   250         Content dl = new HtmlTree(HtmlTag.DL);
   251         if (doc instanceof MethodDoc) {
   252             addMethodInfo((MethodDoc) doc, dl);
   253         }
   254         TagletOutputImpl output = new TagletOutputImpl("");
   255         TagletWriter.genTagOuput(configuration.tagletManager, doc,
   256             configuration.tagletManager.getCustomTags(doc),
   257                 getTagletWriterInstance(false), output);
   258         String outputString = output.toString().trim();
   259         if (!outputString.isEmpty()) {
   260             Content resultString = new RawHtml(outputString);
   261             dl.addContent(resultString);
   262         }
   263         htmltree.addContent(dl);
   264     }
   266     /**
   267      * Check whether there are any tags for Serialization Overview
   268      * section to be printed.
   269      *
   270      * @param field the FieldDoc object to check for tags.
   271      * @return true if there are tags to be printed else return false.
   272      */
   273     protected boolean hasSerializationOverviewTags(FieldDoc field) {
   274         TagletOutputImpl output = new TagletOutputImpl("");
   275         TagletWriter.genTagOuput(configuration.tagletManager, field,
   276             configuration.tagletManager.getCustomTags(field),
   277                 getTagletWriterInstance(false), output);
   278         return (!output.toString().trim().isEmpty());
   279     }
   281     /**
   282      * Returns a TagletWriter that knows how to write HTML.
   283      *
   284      * @return a TagletWriter that knows how to write HTML.
   285      */
   286     public TagletWriter getTagletWriterInstance(boolean isFirstSentence) {
   287         return new TagletWriterImpl(this, isFirstSentence);
   288     }
   290     /**
   291      * Get Package link, with target frame.
   292      *
   293      * @param pd The link will be to the "package-summary.html" page for this package
   294      * @param target name of the target frame
   295      * @param label tag for the link
   296      * @return a content for the target package link
   297      */
   298     public Content getTargetPackageLink(PackageDoc pd, String target,
   299             Content label) {
   300         return getHyperLink(pathString(pd, DocPaths.PACKAGE_SUMMARY), label, "", target);
   301     }
   303     /**
   304      * Generates the HTML document tree and prints it out.
   305      *
   306      * @param metakeywords Array of String keywords for META tag. Each element
   307      *                     of the array is assigned to a separate META tag.
   308      *                     Pass in null for no array
   309      * @param includeScript true if printing windowtitle script
   310      *                      false for files that appear in the left-hand frames
   311      * @param body the body htmltree to be included in the document
   312      */
   313     public void printHtmlDocument(String[] metakeywords, boolean includeScript,
   314             Content body) throws IOException {
   315         Content htmlDocType = DocType.TRANSITIONAL;
   316         Content htmlComment = new Comment(configuration.getText("doclet.New_Page"));
   317         Content head = new HtmlTree(HtmlTag.HEAD);
   318         if (!configuration.notimestamp) {
   319             Content headComment = new Comment(getGeneratedByString());
   320             head.addContent(headComment);
   321         }
   322         if (configuration.charset.length() > 0) {
   323             Content meta = HtmlTree.META("Content-Type", "text/html",
   324                     configuration.charset);
   325             head.addContent(meta);
   326         }
   327         head.addContent(getTitle());
   328         if (!configuration.notimestamp) {
   329             SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
   330             Content meta = HtmlTree.META("date", dateFormat.format(new Date()));
   331             head.addContent(meta);
   332         }
   333         if (metakeywords != null) {
   334             for (int i=0; i < metakeywords.length; i++) {
   335                 Content meta = HtmlTree.META("keywords", metakeywords[i]);
   336                 head.addContent(meta);
   337             }
   338         }
   339         head.addContent(getStyleSheetProperties());
   340         head.addContent(getScriptProperties());
   341         Content htmlTree = HtmlTree.HTML(configuration.getLocale().getLanguage(),
   342                 head, body);
   343         Content htmlDocument = new HtmlDocument(htmlDocType,
   344                 htmlComment, htmlTree);
   345         write(htmlDocument);
   346     }
   348     /**
   349      * Get the window title.
   350      *
   351      * @param title the title string to construct the complete window title
   352      * @return the window title string
   353      */
   354     public String getWindowTitle(String title) {
   355         if (configuration.windowtitle.length() > 0) {
   356             title += " (" + configuration.windowtitle  + ")";
   357         }
   358         return title;
   359     }
   361     /**
   362      * Get user specified header and the footer.
   363      *
   364      * @param header if true print the user provided header else print the
   365      * user provided footer.
   366      */
   367     public Content getUserHeaderFooter(boolean header) {
   368         String content;
   369         if (header) {
   370             content = replaceDocRootDir(configuration.header);
   371         } else {
   372             if (configuration.footer.length() != 0) {
   373                 content = replaceDocRootDir(configuration.footer);
   374             } else {
   375                 content = replaceDocRootDir(configuration.header);
   376             }
   377         }
   378         Content rawContent = new RawHtml(content);
   379         Content em = HtmlTree.EM(rawContent);
   380         return em;
   381     }
   383     /**
   384      * Adds the user specified top.
   385      *
   386      * @param body the content tree to which user specified top will be added
   387      */
   388     public void addTop(Content body) {
   389         Content top = new RawHtml(replaceDocRootDir(configuration.top));
   390         body.addContent(top);
   391     }
   393     /**
   394      * Adds the user specified bottom.
   395      *
   396      * @param body the content tree to which user specified bottom will be added
   397      */
   398     public void addBottom(Content body) {
   399         Content bottom = new RawHtml(replaceDocRootDir(configuration.bottom));
   400         Content small = HtmlTree.SMALL(bottom);
   401         Content p = HtmlTree.P(HtmlStyle.legalCopy, small);
   402         body.addContent(p);
   403     }
   405     /**
   406      * Adds the navigation bar for the Html page at the top and and the bottom.
   407      *
   408      * @param header If true print navigation bar at the top of the page else
   409      * @param body the HtmlTree to which the nav links will be added
   410      */
   411     protected void addNavLinks(boolean header, Content body) {
   412         if (!configuration.nonavbar) {
   413             String allClassesId = "allclasses_";
   414             HtmlTree navDiv = new HtmlTree(HtmlTag.DIV);
   415             if (header) {
   416                 body.addContent(HtmlConstants.START_OF_TOP_NAVBAR);
   417                 navDiv.addStyle(HtmlStyle.topNav);
   418                 allClassesId += "navbar_top";
   419                 Content a = getMarkerAnchor("navbar_top");
   420                 navDiv.addContent(a);
   421                 Content skipLinkContent = getHyperLink(DocLink.fragment("skip-navbar_top"),
   422                         HtmlTree.EMPTY,
   423                         configuration.getText("doclet.Skip_navigation_links"),
   424                         "");
   425                 navDiv.addContent(skipLinkContent);
   426             } else {
   427                 body.addContent(HtmlConstants.START_OF_BOTTOM_NAVBAR);
   428                 navDiv.addStyle(HtmlStyle.bottomNav);
   429                 allClassesId += "navbar_bottom";
   430                 Content a = getMarkerAnchor("navbar_bottom");
   431                 navDiv.addContent(a);
   432                 Content skipLinkContent = getHyperLink(DocLink.fragment("skip-navbar_bottom"),
   433                         HtmlTree.EMPTY,
   434                         configuration.getText("doclet.Skip_navigation_links"),
   435                         "");
   436                 navDiv.addContent(skipLinkContent);
   437             }
   438             if (header) {
   439                 navDiv.addContent(getMarkerAnchor("navbar_top_firstrow"));
   440             } else {
   441                 navDiv.addContent(getMarkerAnchor("navbar_bottom_firstrow"));
   442             }
   443             HtmlTree navList = new HtmlTree(HtmlTag.UL);
   444             navList.addStyle(HtmlStyle.navList);
   445             navList.addAttr(HtmlAttr.TITLE, "Navigation");
   446             if (configuration.createoverview) {
   447                 navList.addContent(getNavLinkContents());
   448             }
   449             if (configuration.packages.length == 1) {
   450                 navList.addContent(getNavLinkPackage(configuration.packages[0]));
   451             } else if (configuration.packages.length > 1) {
   452                 navList.addContent(getNavLinkPackage());
   453             }
   454             navList.addContent(getNavLinkClass());
   455             if(configuration.classuse) {
   456                 navList.addContent(getNavLinkClassUse());
   457             }
   458             if(configuration.createtree) {
   459                 navList.addContent(getNavLinkTree());
   460             }
   461             if(!(configuration.nodeprecated ||
   462                      configuration.nodeprecatedlist)) {
   463                 navList.addContent(getNavLinkDeprecated());
   464             }
   465             if(configuration.createindex) {
   466                 navList.addContent(getNavLinkIndex());
   467             }
   468             if (!configuration.nohelp) {
   469                 navList.addContent(getNavLinkHelp());
   470             }
   471             navDiv.addContent(navList);
   472             Content aboutDiv = HtmlTree.DIV(HtmlStyle.aboutLanguage, getUserHeaderFooter(header));
   473             navDiv.addContent(aboutDiv);
   474             body.addContent(navDiv);
   475             Content ulNav = HtmlTree.UL(HtmlStyle.navList, getNavLinkPrevious());
   476             ulNav.addContent(getNavLinkNext());
   477             Content subDiv = HtmlTree.DIV(HtmlStyle.subNav, ulNav);
   478             Content ulFrames = HtmlTree.UL(HtmlStyle.navList, getNavShowLists());
   479             ulFrames.addContent(getNavHideLists(filename));
   480             subDiv.addContent(ulFrames);
   481             HtmlTree ulAllClasses = HtmlTree.UL(HtmlStyle.navList, getNavLinkClassIndex());
   482             ulAllClasses.addAttr(HtmlAttr.ID, allClassesId.toString());
   483             subDiv.addContent(ulAllClasses);
   484             subDiv.addContent(getAllClassesLinkScript(allClassesId.toString()));
   485             addSummaryDetailLinks(subDiv);
   486             if (header) {
   487                 subDiv.addContent(getMarkerAnchor("skip-navbar_top"));
   488                 body.addContent(subDiv);
   489                 body.addContent(HtmlConstants.END_OF_TOP_NAVBAR);
   490             } else {
   491                 subDiv.addContent(getMarkerAnchor("skip-navbar_bottom"));
   492                 body.addContent(subDiv);
   493                 body.addContent(HtmlConstants.END_OF_BOTTOM_NAVBAR);
   494             }
   495         }
   496     }
   498     /**
   499      * Get the word "NEXT" to indicate that no link is available.  Override
   500      * this method to customize next link.
   501      *
   502      * @return a content tree for the link
   503      */
   504     protected Content getNavLinkNext() {
   505         return getNavLinkNext(null);
   506     }
   508     /**
   509      * Get the word "PREV" to indicate that no link is available.  Override
   510      * this method to customize prev link.
   511      *
   512      * @return a content tree for the link
   513      */
   514     protected Content getNavLinkPrevious() {
   515         return getNavLinkPrevious(null);
   516     }
   518     /**
   519      * Do nothing. This is the default method.
   520      */
   521     protected void addSummaryDetailLinks(Content navDiv) {
   522     }
   524     /**
   525      * Get link to the "overview-summary.html" page.
   526      *
   527      * @return a content tree for the link
   528      */
   529     protected Content getNavLinkContents() {
   530         Content linkContent = getHyperLink(pathToRoot.resolve(DocPaths.OVERVIEW_SUMMARY),
   531                 overviewLabel, "", "");
   532         Content li = HtmlTree.LI(linkContent);
   533         return li;
   534     }
   536     /**
   537      * Get link to the "package-summary.html" page for the package passed.
   538      *
   539      * @param pkg Package to which link will be generated
   540      * @return a content tree for the link
   541      */
   542     protected Content getNavLinkPackage(PackageDoc pkg) {
   543         Content linkContent = getPackageLink(pkg,
   544                 packageLabel);
   545         Content li = HtmlTree.LI(linkContent);
   546         return li;
   547     }
   549     /**
   550      * Get the word "Package" , to indicate that link is not available here.
   551      *
   552      * @return a content tree for the link
   553      */
   554     protected Content getNavLinkPackage() {
   555         Content li = HtmlTree.LI(packageLabel);
   556         return li;
   557     }
   559     /**
   560      * Get the word "Use", to indicate that link is not available.
   561      *
   562      * @return a content tree for the link
   563      */
   564     protected Content getNavLinkClassUse() {
   565         Content li = HtmlTree.LI(useLabel);
   566         return li;
   567     }
   569     /**
   570      * Get link for previous file.
   571      *
   572      * @param prev File name for the prev link
   573      * @return a content tree for the link
   574      */
   575     public Content getNavLinkPrevious(DocPath prev) {
   576         Content li;
   577         if (prev != null) {
   578             li = HtmlTree.LI(getHyperLink(prev, prevLabel, "", ""));
   579         }
   580         else
   581             li = HtmlTree.LI(prevLabel);
   582         return li;
   583     }
   585     /**
   586      * Get link for next file.  If next is null, just print the label
   587      * without linking it anywhere.
   588      *
   589      * @param next File name for the next link
   590      * @return a content tree for the link
   591      */
   592     public Content getNavLinkNext(DocPath next) {
   593         Content li;
   594         if (next != null) {
   595             li = HtmlTree.LI(getHyperLink(next, nextLabel, "", ""));
   596         }
   597         else
   598             li = HtmlTree.LI(nextLabel);
   599         return li;
   600     }
   602     /**
   603      * Get "FRAMES" link, to switch to the frame version of the output.
   604      *
   605      * @param link File to be linked, "index.html"
   606      * @return a content tree for the link
   607      */
   608     protected Content getNavShowLists(DocPath link) {
   609         DocLink dl = new DocLink(link, path.getPath(), null);
   610         Content framesContent = getHyperLink(dl, framesLabel, "", "_top");
   611         Content li = HtmlTree.LI(framesContent);
   612         return li;
   613     }
   615     /**
   616      * Get "FRAMES" link, to switch to the frame version of the output.
   617      *
   618      * @return a content tree for the link
   619      */
   620     protected Content getNavShowLists() {
   621         return getNavShowLists(pathToRoot.resolve(DocPaths.INDEX));
   622     }
   624     /**
   625      * Get "NO FRAMES" link, to switch to the non-frame version of the output.
   626      *
   627      * @param link File to be linked
   628      * @return a content tree for the link
   629      */
   630     protected Content getNavHideLists(DocPath link) {
   631         Content noFramesContent = getHyperLink(link, noframesLabel, "", "_top");
   632         Content li = HtmlTree.LI(noFramesContent);
   633         return li;
   634     }
   636     /**
   637      * Get "Tree" link in the navigation bar. If there is only one package
   638      * specified on the command line, then the "Tree" link will be to the
   639      * only "package-tree.html" file otherwise it will be to the
   640      * "overview-tree.html" file.
   641      *
   642      * @return a content tree for the link
   643      */
   644     protected Content getNavLinkTree() {
   645         Content treeLinkContent;
   646         PackageDoc[] packages = configuration.root.specifiedPackages();
   647         if (packages.length == 1 && configuration.root.specifiedClasses().length == 0) {
   648             treeLinkContent = getHyperLink(pathString(packages[0],
   649                     DocPaths.PACKAGE_TREE), treeLabel,
   650                     "", "");
   651         } else {
   652             treeLinkContent = getHyperLink(pathToRoot.resolve(DocPaths.OVERVIEW_TREE),
   653                     treeLabel, "", "");
   654         }
   655         Content li = HtmlTree.LI(treeLinkContent);
   656         return li;
   657     }
   659     /**
   660      * Get the overview tree link for the main tree.
   661      *
   662      * @param label the label for the link
   663      * @return a content tree for the link
   664      */
   665     protected Content getNavLinkMainTree(String label) {
   666         Content mainTreeContent = getHyperLink(pathToRoot.resolve(DocPaths.OVERVIEW_TREE),
   667                 new StringContent(label));
   668         Content li = HtmlTree.LI(mainTreeContent);
   669         return li;
   670     }
   672     /**
   673      * Get the word "Class", to indicate that class link is not available.
   674      *
   675      * @return a content tree for the link
   676      */
   677     protected Content getNavLinkClass() {
   678         Content li = HtmlTree.LI(classLabel);
   679         return li;
   680     }
   682     /**
   683      * Get "Deprecated" API link in the navigation bar.
   684      *
   685      * @return a content tree for the link
   686      */
   687     protected Content getNavLinkDeprecated() {
   688         Content linkContent = getHyperLink(pathToRoot.resolve(DocPaths.DEPRECATED_LIST),
   689                 deprecatedLabel, "", "");
   690         Content li = HtmlTree.LI(linkContent);
   691         return li;
   692     }
   694     /**
   695      * Get link for generated index. If the user has used "-splitindex"
   696      * command line option, then link to file "index-files/index-1.html" is
   697      * generated otherwise link to file "index-all.html" is generated.
   698      *
   699      * @return a content tree for the link
   700      */
   701     protected Content getNavLinkClassIndex() {
   702         Content allClassesContent = getHyperLink(pathToRoot.resolve(
   703                 DocPaths.ALLCLASSES_NOFRAME),
   704                 allclassesLabel, "", "");
   705         Content li = HtmlTree.LI(allClassesContent);
   706         return li;
   707     }
   709     /**
   710      * Get link for generated class index.
   711      *
   712      * @return a content tree for the link
   713      */
   714     protected Content getNavLinkIndex() {
   715         Content linkContent = getHyperLink(pathToRoot.resolve(
   716                 (configuration.splitindex
   717                     ? DocPaths.INDEX_FILES.resolve(DocPaths.indexN(1))
   718                     : DocPaths.INDEX_ALL)),
   719             indexLabel, "", "");
   720         Content li = HtmlTree.LI(linkContent);
   721         return li;
   722     }
   724     /**
   725      * Get help file link. If user has provided a help file, then generate a
   726      * link to the user given file, which is already copied to current or
   727      * destination directory.
   728      *
   729      * @return a content tree for the link
   730      */
   731     protected Content getNavLinkHelp() {
   732         String helpfile = configuration.helpfile;
   733         DocPath helpfilenm;
   734         if (helpfile.isEmpty()) {
   735             helpfilenm = DocPaths.HELP_DOC;
   736         } else {
   737             DocFile file = DocFile.createFileForInput(configuration, helpfile);
   738             helpfilenm = DocPath.create(file.getName());
   739         }
   740         Content linkContent = getHyperLink(pathToRoot.resolve(helpfilenm),
   741                 helpLabel, "", "");
   742         Content li = HtmlTree.LI(linkContent);
   743         return li;
   744     }
   746     /**
   747      * Get summary table header.
   748      *
   749      * @param header the header for the table
   750      * @param scope the scope of the headers
   751      * @return a content tree for the header
   752      */
   753     public Content getSummaryTableHeader(String[] header, String scope) {
   754         Content tr = new HtmlTree(HtmlTag.TR);
   755         int size = header.length;
   756         Content tableHeader;
   757         if (size == 1) {
   758             tableHeader = new StringContent(header[0]);
   759             tr.addContent(HtmlTree.TH(HtmlStyle.colOne, scope, tableHeader));
   760             return tr;
   761         }
   762         for (int i = 0; i < size; i++) {
   763             tableHeader = new StringContent(header[i]);
   764             if(i == 0)
   765                 tr.addContent(HtmlTree.TH(HtmlStyle.colFirst, scope, tableHeader));
   766             else if(i == (size - 1))
   767                 tr.addContent(HtmlTree.TH(HtmlStyle.colLast, scope, tableHeader));
   768             else
   769                 tr.addContent(HtmlTree.TH(scope, tableHeader));
   770         }
   771         return tr;
   772     }
   774     /**
   775      * Get table caption.
   776      *
   777      * @param rawText the caption for the table which could be raw Html
   778      * @return a content tree for the caption
   779      */
   780     public Content getTableCaption(String rawText) {
   781         Content title = new RawHtml(rawText);
   782         Content captionSpan = HtmlTree.SPAN(title);
   783         Content space = getSpace();
   784         Content tabSpan = HtmlTree.SPAN(HtmlStyle.tabEnd, space);
   785         Content caption = HtmlTree.CAPTION(captionSpan);
   786         caption.addContent(tabSpan);
   787         return caption;
   788     }
   790     /**
   791      * Get the marker anchor which will be added to the documentation tree.
   792      *
   793      * @param anchorName the anchor name attribute
   794      * @return a content tree for the marker anchor
   795      */
   796     public Content getMarkerAnchor(String anchorName) {
   797         return getMarkerAnchor(anchorName, null);
   798     }
   800     /**
   801      * Get the marker anchor which will be added to the documentation tree.
   802      *
   803      * @param anchorName the anchor name attribute
   804      * @param anchorContent the content that should be added to the anchor
   805      * @return a content tree for the marker anchor
   806      */
   807     public Content getMarkerAnchor(String anchorName, Content anchorContent) {
   808         if (anchorContent == null)
   809             anchorContent = new Comment(" ");
   810         Content markerAnchor = HtmlTree.A_NAME(anchorName, anchorContent);
   811         return markerAnchor;
   812     }
   814     /**
   815      * Returns a packagename content.
   816      *
   817      * @param packageDoc the package to check
   818      * @return package name content
   819      */
   820     public Content getPackageName(PackageDoc packageDoc) {
   821         return packageDoc == null || packageDoc.name().length() == 0 ?
   822             defaultPackageLabel :
   823             getPackageLabel(packageDoc.name());
   824     }
   826     /**
   827      * Returns a package name label.
   828      *
   829      * @param packageName the package name
   830      * @return the package name content
   831      */
   832     public Content getPackageLabel(String packageName) {
   833         return new StringContent(packageName);
   834     }
   836     /**
   837      * Add package deprecation information to the documentation tree
   838      *
   839      * @param deprPkgs list of deprecated packages
   840      * @param headingKey the caption for the deprecated package table
   841      * @param tableSummary the summary for the deprecated package table
   842      * @param tableHeader table headers for the deprecated package table
   843      * @param contentTree the content tree to which the deprecated package table will be added
   844      */
   845     protected void addPackageDeprecatedAPI(List<Doc> deprPkgs, String headingKey,
   846             String tableSummary, String[] tableHeader, Content contentTree) {
   847         if (deprPkgs.size() > 0) {
   848             Content table = HtmlTree.TABLE(0, 3, 0, tableSummary,
   849                     getTableCaption(configuration.getText(headingKey)));
   850             table.addContent(getSummaryTableHeader(tableHeader, "col"));
   851             Content tbody = new HtmlTree(HtmlTag.TBODY);
   852             for (int i = 0; i < deprPkgs.size(); i++) {
   853                 PackageDoc pkg = (PackageDoc) deprPkgs.get(i);
   854                 HtmlTree td = HtmlTree.TD(HtmlStyle.colOne,
   855                         getPackageLink(pkg, getPackageName(pkg)));
   856                 if (pkg.tags("deprecated").length > 0) {
   857                     addInlineDeprecatedComment(pkg, pkg.tags("deprecated")[0], td);
   858                 }
   859                 HtmlTree tr = HtmlTree.TR(td);
   860                 if (i % 2 == 0) {
   861                     tr.addStyle(HtmlStyle.altColor);
   862                 } else {
   863                     tr.addStyle(HtmlStyle.rowColor);
   864                 }
   865                 tbody.addContent(tr);
   866             }
   867             table.addContent(tbody);
   868             Content li = HtmlTree.LI(HtmlStyle.blockList, table);
   869             Content ul = HtmlTree.UL(HtmlStyle.blockList, li);
   870             contentTree.addContent(ul);
   871         }
   872     }
   874     /**
   875      * Return the path to the class page for a classdoc.
   876      *
   877      * @param cd   Class to which the path is requested.
   878      * @param name Name of the file(doesn't include path).
   879      */
   880     protected DocPath pathString(ClassDoc cd, DocPath name) {
   881         return pathString(cd.containingPackage(), name);
   882     }
   884     /**
   885      * Return path to the given file name in the given package. So if the name
   886      * passed is "Object.html" and the name of the package is "java.lang", and
   887      * if the relative path is "../.." then returned string will be
   888      * "../../java/lang/Object.html"
   889      *
   890      * @param pd Package in which the file name is assumed to be.
   891      * @param name File name, to which path string is.
   892      */
   893     protected DocPath pathString(PackageDoc pd, DocPath name) {
   894         return pathToRoot.resolve(DocPath.forPackage(pd).resolve(name));
   895     }
   897     /**
   898      * Return the link to the given package.
   899      *
   900      * @param pkg the package to link to.
   901      * @param label the label for the link.
   902      * @param isStrong true if the label should be strong.
   903      * @return the link to the given package.
   904      */
   905     public String getPackageLinkString(PackageDoc pkg, String label,
   906                                  boolean isStrong) {
   907         return getPackageLinkString(pkg, label, isStrong, "");
   908     }
   910     /**
   911      * Return the link to the given package.
   912      *
   913      * @param pkg the package to link to.
   914      * @param label the label for the link.
   915      * @param isStrong true if the label should be strong.
   916      * @param style  the font of the package link label.
   917      * @return the link to the given package.
   918      */
   919     public String getPackageLinkString(PackageDoc pkg, String label, boolean isStrong,
   920             String style) {
   921         boolean included = pkg != null && pkg.isIncluded();
   922         if (! included) {
   923             PackageDoc[] packages = configuration.packages;
   924             for (int i = 0; i < packages.length; i++) {
   925                 if (packages[i].equals(pkg)) {
   926                     included = true;
   927                     break;
   928                 }
   929             }
   930         }
   931         if (included || pkg == null) {
   932             return getHyperLinkString(pathString(pkg, DocPaths.PACKAGE_SUMMARY),
   933                                 label, isStrong, style);
   934         } else {
   935             DocLink crossPkgLink = getCrossPackageLink(Util.getPackageName(pkg));
   936             if (crossPkgLink != null) {
   937                 return getHyperLinkString(crossPkgLink, label, isStrong, style);
   938             } else {
   939                 return label;
   940             }
   941         }
   942     }
   944     /**
   945      * Return the link to the given package.
   946      *
   947      * @param pkg the package to link to.
   948      * @param label the label for the link.
   949      * @return a content tree for the package link.
   950      */
   951     public Content getPackageLink(PackageDoc pkg, Content label) {
   952         boolean included = pkg != null && pkg.isIncluded();
   953         if (! included) {
   954             PackageDoc[] packages = configuration.packages;
   955             for (int i = 0; i < packages.length; i++) {
   956                 if (packages[i].equals(pkg)) {
   957                     included = true;
   958                     break;
   959                 }
   960             }
   961         }
   962         if (included || pkg == null) {
   963             return getHyperLink(pathString(pkg, DocPaths.PACKAGE_SUMMARY),
   964                     label);
   965         } else {
   966             DocLink crossPkgLink = getCrossPackageLink(Util.getPackageName(pkg));
   967             if (crossPkgLink != null) {
   968                 return getHyperLink(crossPkgLink, label);
   969             } else {
   970                 return label;
   971             }
   972         }
   973     }
   975     public String italicsClassName(ClassDoc cd, boolean qual) {
   976         String name = (qual)? cd.qualifiedName(): cd.name();
   977         return (cd.isInterface())?  italicsText(name): name;
   978     }
   980     /**
   981      * Add the link to the content tree.
   982      *
   983      * @param doc program element doc for which the link will be added
   984      * @param label label for the link
   985      * @param htmltree the content tree to which the link will be added
   986      */
   987     public void addSrcLink(ProgramElementDoc doc, Content label, Content htmltree) {
   988         if (doc == null) {
   989             return;
   990         }
   991         ClassDoc cd = doc.containingClass();
   992         if (cd == null) {
   993             //d must be a class doc since in has no containing class.
   994             cd = (ClassDoc) doc;
   995         }
   996         DocPath href = pathToRoot
   997                 .resolve(DocPaths.SOURCE_OUTPUT)
   998                 .resolve(DocPath.forClass(cd));
   999         Content linkContent = getHyperLink(href.fragment(SourceToHTMLConverter.getAnchorName(doc)), label, "", "");
  1000         htmltree.addContent(linkContent);
  1003     /**
  1004      * Return the link to the given class.
  1006      * @param linkInfo the information about the link.
  1008      * @return the link for the given class.
  1009      */
  1010     public String getLink(LinkInfoImpl linkInfo) {
  1011         LinkFactoryImpl factory = new LinkFactoryImpl(this);
  1012         String link = factory.getLinkOutput(linkInfo).toString();
  1013         displayLength += linkInfo.displayLength;
  1014         return link;
  1017     /**
  1018      * Return the type parameters for the given class.
  1020      * @param linkInfo the information about the link.
  1021      * @return the type for the given class.
  1022      */
  1023     public String getTypeParameterLinks(LinkInfoImpl linkInfo) {
  1024         LinkFactoryImpl factory = new LinkFactoryImpl(this);
  1025         return factory.getTypeParameterLinks(linkInfo, false).toString();
  1028     /*************************************************************
  1029      * Return a class cross link to external class documentation.
  1030      * The name must be fully qualified to determine which package
  1031      * the class is in.  The -link option does not allow users to
  1032      * link to external classes in the "default" package.
  1034      * @param qualifiedClassName the qualified name of the external class.
  1035      * @param refMemName the name of the member being referenced.  This should
  1036      * be null or empty string if no member is being referenced.
  1037      * @param label the label for the external link.
  1038      * @param strong true if the link should be strong.
  1039      * @param style the style of the link.
  1040      * @param code true if the label should be code font.
  1041      */
  1042     public String getCrossClassLink(String qualifiedClassName, String refMemName,
  1043                                     String label, boolean strong, String style,
  1044                                     boolean code) {
  1045         String className = "";
  1046         String packageName = qualifiedClassName == null ? "" : qualifiedClassName;
  1047         int periodIndex;
  1048         while ((periodIndex = packageName.lastIndexOf('.')) != -1) {
  1049             className = packageName.substring(periodIndex + 1, packageName.length()) +
  1050                 (className.length() > 0 ? "." + className : "");
  1051             String defaultLabel = code ? codeText(className) : className;
  1052             packageName = packageName.substring(0, periodIndex);
  1053             if (getCrossPackageLink(packageName) != null) {
  1054                 //The package exists in external documentation, so link to the external
  1055                 //class (assuming that it exists).  This is definitely a limitation of
  1056                 //the -link option.  There are ways to determine if an external package
  1057                 //exists, but no way to determine if the external class exists.  We just
  1058                 //have to assume that it does.
  1059                 DocLink link = configuration.extern.getExternalLink(packageName, pathToRoot,
  1060                                 className + ".html", refMemName);
  1061                 return getHyperLinkString(link,
  1062                     (label == null) || label.length() == 0 ? defaultLabel : label,
  1065                     strong, style,
  1066                     configuration.getText("doclet.Href_Class_Or_Interface_Title", packageName),
  1067                     "");
  1070         return null;
  1073     public boolean isClassLinkable(ClassDoc cd) {
  1074         if (cd.isIncluded()) {
  1075             return configuration.isGeneratedDoc(cd);
  1077         return configuration.extern.isExternal(cd);
  1080     public DocLink getCrossPackageLink(String pkgName) {
  1081         return configuration.extern.getExternalLink(pkgName, pathToRoot,
  1082             DocPaths.PACKAGE_SUMMARY.getPath());
  1085     /**
  1086      * Get the class link.
  1088      * @param context the id of the context where the link will be added
  1089      * @param cd the class doc to link to
  1090      * @return a content tree for the link
  1091      */
  1092     public Content getQualifiedClassLink(int context, ClassDoc cd) {
  1093         return new RawHtml(getLink(new LinkInfoImpl(configuration, context, cd,
  1094                 configuration.getClassName(cd), "")));
  1097     /**
  1098      * Add the class link.
  1100      * @param context the id of the context where the link will be added
  1101      * @param cd the class doc to link to
  1102      * @param contentTree the content tree to which the link will be added
  1103      */
  1104     public void addPreQualifiedClassLink(int context, ClassDoc cd, Content contentTree) {
  1105         addPreQualifiedClassLink(context, cd, false, contentTree);
  1108     /**
  1109      * Retrieve the class link with the package portion of the label in
  1110      * plain text.  If the qualifier is excluded, it will not be included in the
  1111      * link label.
  1113      * @param cd the class to link to.
  1114      * @param isStrong true if the link should be strong.
  1115      * @return the link with the package portion of the label in plain text.
  1116      */
  1117     public String getPreQualifiedClassLink(int context,
  1118             ClassDoc cd, boolean isStrong) {
  1119         String classlink = "";
  1120         PackageDoc pd = cd.containingPackage();
  1121         if(pd != null && ! configuration.shouldExcludeQualifier(pd.name())) {
  1122             classlink = getPkgName(cd);
  1124         classlink += getLink(new LinkInfoImpl(configuration,
  1125                 context, cd, cd.name(), isStrong));
  1126         return classlink;
  1129     /**
  1130      * Add the class link with the package portion of the label in
  1131      * plain text. If the qualifier is excluded, it will not be included in the
  1132      * link label.
  1134      * @param context the id of the context where the link will be added
  1135      * @param cd the class to link to
  1136      * @param isStrong true if the link should be strong
  1137      * @param contentTree the content tree to which the link with be added
  1138      */
  1139     public void addPreQualifiedClassLink(int context,
  1140             ClassDoc cd, boolean isStrong, Content contentTree) {
  1141         PackageDoc pd = cd.containingPackage();
  1142         if(pd != null && ! configuration.shouldExcludeQualifier(pd.name())) {
  1143             contentTree.addContent(getPkgName(cd));
  1145         contentTree.addContent(new RawHtml(getLink(new LinkInfoImpl(configuration,
  1146                 context, cd, cd.name(), isStrong))));
  1149     /**
  1150      * Add the class link, with only class name as the strong link and prefixing
  1151      * plain package name.
  1153      * @param context the id of the context where the link will be added
  1154      * @param cd the class to link to
  1155      * @param contentTree the content tree to which the link with be added
  1156      */
  1157     public void addPreQualifiedStrongClassLink(int context, ClassDoc cd, Content contentTree) {
  1158         addPreQualifiedClassLink(context, cd, true, contentTree);
  1161     /**
  1162      * Get the link for the given member.
  1164      * @param context the id of the context where the link will be added
  1165      * @param doc the member being linked to
  1166      * @param label the label for the link
  1167      * @return a content tree for the doc link
  1168      */
  1169     public Content getDocLink(int context, MemberDoc doc, String label) {
  1170         return getDocLink(context, doc.containingClass(), doc, label);
  1173     /**
  1174      * Return the link for the given member.
  1176      * @param context the id of the context where the link will be printed.
  1177      * @param doc the member being linked to.
  1178      * @param label the label for the link.
  1179      * @param strong true if the link should be strong.
  1180      * @return the link for the given member.
  1181      */
  1182     public String getDocLink(int context, MemberDoc doc, String label,
  1183                 boolean strong) {
  1184         return getDocLink(context, doc.containingClass(), doc, label, strong);
  1187     /**
  1188      * Return the link for the given member.
  1190      * @param context the id of the context where the link will be printed.
  1191      * @param classDoc the classDoc that we should link to.  This is not
  1192      *                 necessarily equal to doc.containingClass().  We may be
  1193      *                 inheriting comments.
  1194      * @param doc the member being linked to.
  1195      * @param label the label for the link.
  1196      * @param strong true if the link should be strong.
  1197      * @return the link for the given member.
  1198      */
  1199     public String getDocLink(int context, ClassDoc classDoc, MemberDoc doc,
  1200         String label, boolean strong) {
  1201         if (! (doc.isIncluded() ||
  1202             Util.isLinkable(classDoc, configuration))) {
  1203             return label;
  1204         } else if (doc instanceof ExecutableMemberDoc) {
  1205             ExecutableMemberDoc emd = (ExecutableMemberDoc)doc;
  1206             return getLink(new LinkInfoImpl(configuration, context, classDoc,
  1207                 getAnchor(emd), label, strong));
  1208         } else if (doc instanceof MemberDoc) {
  1209             return getLink(new LinkInfoImpl(configuration, context, classDoc,
  1210                 doc.name(), label, strong));
  1211         } else {
  1212             return label;
  1216     /**
  1217      * Return the link for the given member.
  1219      * @param context the id of the context where the link will be added
  1220      * @param classDoc the classDoc that we should link to.  This is not
  1221      *                 necessarily equal to doc.containingClass().  We may be
  1222      *                 inheriting comments
  1223      * @param doc the member being linked to
  1224      * @param label the label for the link
  1225      * @return the link for the given member
  1226      */
  1227     public Content getDocLink(int context, ClassDoc classDoc, MemberDoc doc,
  1228         String label) {
  1229         if (! (doc.isIncluded() ||
  1230             Util.isLinkable(classDoc, configuration))) {
  1231             return new StringContent(label);
  1232         } else if (doc instanceof ExecutableMemberDoc) {
  1233             ExecutableMemberDoc emd = (ExecutableMemberDoc)doc;
  1234             return new RawHtml(getLink(new LinkInfoImpl(configuration, context, classDoc,
  1235                 getAnchor(emd), label, false)));
  1236         } else if (doc instanceof MemberDoc) {
  1237             return new RawHtml(getLink(new LinkInfoImpl(configuration, context, classDoc,
  1238                 doc.name(), label, false)));
  1239         } else {
  1240             return new StringContent(label);
  1244     public String getAnchor(ExecutableMemberDoc emd) {
  1245         StringBuilder signature = new StringBuilder(emd.signature());
  1246         StringBuilder signatureParsed = new StringBuilder();
  1247         int counter = 0;
  1248         for (int i = 0; i < signature.length(); i++) {
  1249             char c = signature.charAt(i);
  1250             if (c == '<') {
  1251                 counter++;
  1252             } else if (c == '>') {
  1253                 counter--;
  1254             } else if (counter == 0) {
  1255                 signatureParsed.append(c);
  1258         return emd.name() + signatureParsed.toString();
  1261     public String seeTagToString(SeeTag see) {
  1262         String tagName = see.name();
  1263         if (! (tagName.startsWith("@link") || tagName.equals("@see"))) {
  1264             return "";
  1267         String seetext = replaceDocRootDir(see.text());
  1269         //Check if @see is an href or "string"
  1270         if (seetext.startsWith("<") || seetext.startsWith("\"")) {
  1271             return seetext;
  1274         boolean plain = tagName.equalsIgnoreCase("@linkplain");
  1275         String label = plainOrCodeText(plain, see.label());
  1277         //The text from the @see tag.  We will output this text when a label is not specified.
  1278         String text = plainOrCodeText(plain, seetext);
  1280         ClassDoc refClass = see.referencedClass();
  1281         String refClassName = see.referencedClassName();
  1282         MemberDoc refMem = see.referencedMember();
  1283         String refMemName = see.referencedMemberName();
  1285         if (refClass == null) {
  1286             //@see is not referencing an included class
  1287             PackageDoc refPackage = see.referencedPackage();
  1288             if (refPackage != null && refPackage.isIncluded()) {
  1289                 //@see is referencing an included package
  1290                 if (label.isEmpty())
  1291                     label = plainOrCodeText(plain, refPackage.name());
  1292                 return getPackageLinkString(refPackage, label, false);
  1293             } else {
  1294                 //@see is not referencing an included class or package.  Check for cross links.
  1295                 String classCrossLink;
  1296                 DocLink packageCrossLink = getCrossPackageLink(refClassName);
  1297                 if (packageCrossLink != null) {
  1298                     //Package cross link found
  1299                     return getHyperLinkString(packageCrossLink,
  1300                         (label.isEmpty() ? text : label), false);
  1301                 } else if ((classCrossLink = getCrossClassLink(refClassName,
  1302                         refMemName, label, false, "", !plain)) != null) {
  1303                     //Class cross link found (possibly to a member in the class)
  1304                     return classCrossLink;
  1305                 } else {
  1306                     //No cross link found so print warning
  1307                     configuration.getDocletSpecificMsg().warning(see.position(), "doclet.see.class_or_package_not_found",
  1308                             tagName, seetext);
  1309                     return (label.isEmpty() ? text: label);
  1312         } else if (refMemName == null) {
  1313             // Must be a class reference since refClass is not null and refMemName is null.
  1314             if (label.isEmpty()) {
  1315                 label = plainOrCodeText(plain, refClass.name());
  1317             return getLink(new LinkInfoImpl(configuration, refClass, label));
  1318         } else if (refMem == null) {
  1319             // Must be a member reference since refClass is not null and refMemName is not null.
  1320             // However, refMem is null, so this referenced member does not exist.
  1321             return (label.isEmpty() ? text: label);
  1322         } else {
  1323             // Must be a member reference since refClass is not null and refMemName is not null.
  1324             // refMem is not null, so this @see tag must be referencing a valid member.
  1325             ClassDoc containing = refMem.containingClass();
  1326             if (see.text().trim().startsWith("#") &&
  1327                 ! (containing.isPublic() ||
  1328                 Util.isLinkable(containing, configuration))) {
  1329                 // Since the link is relative and the holder is not even being
  1330                 // documented, this must be an inherited link.  Redirect it.
  1331                 // The current class either overrides the referenced member or
  1332                 // inherits it automatically.
  1333                 if (this instanceof ClassWriterImpl) {
  1334                     containing = ((ClassWriterImpl) this).getClassDoc();
  1335                 } else if (!containing.isPublic()){
  1336                     configuration.getDocletSpecificMsg().warning(
  1337                         see.position(), "doclet.see.class_or_package_not_accessible",
  1338                         tagName, containing.qualifiedName());
  1339                 } else {
  1340                     configuration.getDocletSpecificMsg().warning(
  1341                         see.position(), "doclet.see.class_or_package_not_found",
  1342                         tagName, seetext);
  1345             if (configuration.currentcd != containing) {
  1346                 refMemName = containing.name() + "." + refMemName;
  1348             if (refMem instanceof ExecutableMemberDoc) {
  1349                 if (refMemName.indexOf('(') < 0) {
  1350                     refMemName += ((ExecutableMemberDoc)refMem).signature();
  1354             text = plainOrCodeText(plain, Util.escapeHtmlChars(refMemName));
  1356             return getDocLink(LinkInfoImpl.CONTEXT_SEE_TAG, containing,
  1357                 refMem, (label.isEmpty() ? text: label), false);
  1361     private String plainOrCodeText(boolean plain, String text) {
  1362         return (plain || text.isEmpty()) ? text : codeText(text);
  1365     /**
  1366      * Add the inline comment.
  1368      * @param doc the doc for which the inline comment will be added
  1369      * @param tag the inline tag to be added
  1370      * @param htmltree the content tree to which the comment will be added
  1371      */
  1372     public void addInlineComment(Doc doc, Tag tag, Content htmltree) {
  1373         addCommentTags(doc, tag.inlineTags(), false, false, htmltree);
  1376     /**
  1377      * Add the inline deprecated comment.
  1379      * @param doc the doc for which the inline deprecated comment will be added
  1380      * @param tag the inline tag to be added
  1381      * @param htmltree the content tree to which the comment will be added
  1382      */
  1383     public void addInlineDeprecatedComment(Doc doc, Tag tag, Content htmltree) {
  1384         addCommentTags(doc, tag.inlineTags(), true, false, htmltree);
  1387     /**
  1388      * Adds the summary content.
  1390      * @param doc the doc for which the summary will be generated
  1391      * @param htmltree the documentation tree to which the summary will be added
  1392      */
  1393     public void addSummaryComment(Doc doc, Content htmltree) {
  1394         addSummaryComment(doc, doc.firstSentenceTags(), htmltree);
  1397     /**
  1398      * Adds the summary content.
  1400      * @param doc the doc for which the summary will be generated
  1401      * @param firstSentenceTags the first sentence tags for the doc
  1402      * @param htmltree the documentation tree to which the summary will be added
  1403      */
  1404     public void addSummaryComment(Doc doc, Tag[] firstSentenceTags, Content htmltree) {
  1405         addCommentTags(doc, firstSentenceTags, false, true, htmltree);
  1408     public void addSummaryDeprecatedComment(Doc doc, Tag tag, Content htmltree) {
  1409         addCommentTags(doc, tag.firstSentenceTags(), true, true, htmltree);
  1412     /**
  1413      * Adds the inline comment.
  1415      * @param doc the doc for which the inline comments will be generated
  1416      * @param htmltree the documentation tree to which the inline comments will be added
  1417      */
  1418     public void addInlineComment(Doc doc, Content htmltree) {
  1419         addCommentTags(doc, doc.inlineTags(), false, false, htmltree);
  1422     /**
  1423      * Adds the comment tags.
  1425      * @param doc the doc for which the comment tags will be generated
  1426      * @param tags the first sentence tags for the doc
  1427      * @param depr true if it is deprecated
  1428      * @param first true if the first sentence tags should be added
  1429      * @param htmltree the documentation tree to which the comment tags will be added
  1430      */
  1431     private void addCommentTags(Doc doc, Tag[] tags, boolean depr,
  1432             boolean first, Content htmltree) {
  1433         if(configuration.nocomment){
  1434             return;
  1436         Content div;
  1437         Content result = new RawHtml(commentTagsToString(null, doc, tags, first));
  1438         if (depr) {
  1439             Content italic = HtmlTree.I(result);
  1440             div = HtmlTree.DIV(HtmlStyle.block, italic);
  1441             htmltree.addContent(div);
  1443         else {
  1444             div = HtmlTree.DIV(HtmlStyle.block, result);
  1445             htmltree.addContent(div);
  1447         if (tags.length == 0) {
  1448             htmltree.addContent(getSpace());
  1452     /**
  1453      * Converts inline tags and text to text strings, expanding the
  1454      * inline tags along the way.  Called wherever text can contain
  1455      * an inline tag, such as in comments or in free-form text arguments
  1456      * to non-inline tags.
  1458      * @param holderTag    specific tag where comment resides
  1459      * @param doc    specific doc where comment resides
  1460      * @param tags   array of text tags and inline tags (often alternating)
  1461      *               present in the text of interest for this doc
  1462      * @param isFirstSentence  true if text is first sentence
  1463      */
  1464     public String commentTagsToString(Tag holderTag, Doc doc, Tag[] tags,
  1465             boolean isFirstSentence) {
  1466         StringBuilder result = new StringBuilder();
  1467         boolean textTagChange = false;
  1468         // Array of all possible inline tags for this javadoc run
  1469         configuration.tagletManager.checkTags(doc, tags, true);
  1470         for (int i = 0; i < tags.length; i++) {
  1471             Tag tagelem = tags[i];
  1472             String tagName = tagelem.name();
  1473             if (tagelem instanceof SeeTag) {
  1474                 result.append(seeTagToString((SeeTag)tagelem));
  1475             } else if (! tagName.equals("Text")) {
  1476                 int originalLength = result.length();
  1477                 TagletOutput output = TagletWriter.getInlineTagOuput(
  1478                     configuration.tagletManager, holderTag,
  1479                     tagelem, getTagletWriterInstance(isFirstSentence));
  1480                 result.append(output == null ? "" : output.toString());
  1481                 if (originalLength == 0 && isFirstSentence && tagelem.name().equals("@inheritDoc") && result.length() > 0) {
  1482                     break;
  1483                 } else if (configuration.docrootparent.length() > 0 &&
  1484                         tagelem.name().equals("@docRoot") &&
  1485                         ((tags[i + 1]).text()).startsWith("/..")) {
  1486                     //If Xdocrootparent switch ON, set the flag to remove the /.. occurance after
  1487                     //{@docRoot} tag in the very next Text tag.
  1488                     textTagChange = true;
  1489                     continue;
  1490                 } else {
  1491                     continue;
  1493             } else {
  1494                 String text = tagelem.text();
  1495                 //If Xdocrootparent switch ON, remove the /.. occurance after {@docRoot} tag.
  1496                 if (textTagChange) {
  1497                     text = text.replaceFirst("/..", "");
  1498                     textTagChange = false;
  1500                 //This is just a regular text tag.  The text may contain html links (<a>)
  1501                 //or inline tag {@docRoot}, which will be handled as special cases.
  1502                 text = redirectRelativeLinks(tagelem.holder(), text);
  1504                 // Replace @docRoot only if not represented by an instance of DocRootTaglet,
  1505                 // that is, only if it was not present in a source file doc comment.
  1506                 // This happens when inserted by the doclet (a few lines
  1507                 // above in this method).  [It might also happen when passed in on the command
  1508                 // line as a text argument to an option (like -header).]
  1509                 text = replaceDocRootDir(text);
  1510                 if (isFirstSentence) {
  1511                     text = removeNonInlineHtmlTags(text);
  1513                 StringTokenizer lines = new StringTokenizer(text, "\r\n", true);
  1514                 StringBuilder textBuff = new StringBuilder();
  1515                 while (lines.hasMoreTokens()) {
  1516                     StringBuilder line = new StringBuilder(lines.nextToken());
  1517                     Util.replaceTabs(configuration, line);
  1518                     textBuff.append(line.toString());
  1520                 result.append(textBuff);
  1523         return result.toString();
  1526     /**
  1527      * Return true if relative links should not be redirected.
  1529      * @return Return true if a relative link should not be redirected.
  1530      */
  1531     private boolean shouldNotRedirectRelativeLinks() {
  1532         return  this instanceof AnnotationTypeWriter ||
  1533                 this instanceof ClassWriter ||
  1534                 this instanceof PackageSummaryWriter;
  1537     /**
  1538      * Suppose a piece of documentation has a relative link.  When you copy
  1539      * that documentation to another place such as the index or class-use page,
  1540      * that relative link will no longer work.  We should redirect those links
  1541      * so that they will work again.
  1542      * <p>
  1543      * Here is the algorithm used to fix the link:
  1544      * <p>
  1545      * {@literal <relative link> => docRoot + <relative path to file> + <relative link> }
  1546      * <p>
  1547      * For example, suppose com.sun.javadoc.RootDoc has this link:
  1548      * {@literal <a href="package-summary.html">The package Page</a> }
  1549      * <p>
  1550      * If this link appeared in the index, we would redirect
  1551      * the link like this:
  1553      * {@literal <a href="./com/sun/javadoc/package-summary.html">The package Page</a>}
  1555      * @param doc the Doc object whose documentation is being written.
  1556      * @param text the text being written.
  1558      * @return the text, with all the relative links redirected to work.
  1559      */
  1560     private String redirectRelativeLinks(Doc doc, String text) {
  1561         if (doc == null || shouldNotRedirectRelativeLinks()) {
  1562             return text;
  1565         DocPath redirectPathFromRoot;
  1566         if (doc instanceof ClassDoc) {
  1567             redirectPathFromRoot = DocPath.forPackage(((ClassDoc) doc).containingPackage());
  1568         } else if (doc instanceof MemberDoc) {
  1569             redirectPathFromRoot = DocPath.forPackage(((MemberDoc) doc).containingPackage());
  1570         } else if (doc instanceof PackageDoc) {
  1571             redirectPathFromRoot = DocPath.forPackage((PackageDoc) doc);
  1572         } else {
  1573             return text;
  1576         //Redirect all relative links.
  1577         int end, begin = text.toLowerCase().indexOf("<a");
  1578         if(begin >= 0){
  1579             StringBuilder textBuff = new StringBuilder(text);
  1581             while(begin >=0){
  1582                 if (textBuff.length() > begin + 2 && ! Character.isWhitespace(textBuff.charAt(begin+2))) {
  1583                     begin = textBuff.toString().toLowerCase().indexOf("<a", begin + 1);
  1584                     continue;
  1587                 begin = textBuff.indexOf("=", begin) + 1;
  1588                 end = textBuff.indexOf(">", begin +1);
  1589                 if(begin == 0){
  1590                     //Link has no equal symbol.
  1591                     configuration.root.printWarning(
  1592                         doc.position(),
  1593                         configuration.getText("doclet.malformed_html_link_tag", text));
  1594                     break;
  1596                 if (end == -1) {
  1597                     //Break without warning.  This <a> tag is not necessarily malformed.  The text
  1598                     //might be missing '>' character because the href has an inline tag.
  1599                     break;
  1601                 if (textBuff.substring(begin, end).indexOf("\"") != -1){
  1602                     begin = textBuff.indexOf("\"", begin) + 1;
  1603                     end = textBuff.indexOf("\"", begin +1);
  1604                     if (begin == 0 || end == -1){
  1605                         //Link is missing a quote.
  1606                         break;
  1609                 String relativeLink = textBuff.substring(begin, end);
  1610                 if (!(relativeLink.toLowerCase().startsWith("mailto:") ||
  1611                         relativeLink.toLowerCase().startsWith("http:") ||
  1612                         relativeLink.toLowerCase().startsWith("https:") ||
  1613                         relativeLink.toLowerCase().startsWith("file:"))) {
  1614                     relativeLink = "{@"+(new DocRootTaglet()).getName() + "}/"
  1615                         + redirectPathFromRoot.resolve(relativeLink).getPath();
  1616                     textBuff.replace(begin, end, relativeLink);
  1618                 begin = textBuff.toString().toLowerCase().indexOf("<a", begin + 1);
  1620             return textBuff.toString();
  1622         return text;
  1625     public String removeNonInlineHtmlTags(String text) {
  1626         if (text.indexOf('<') < 0) {
  1627             return text;
  1629         String noninlinetags[] = { "<ul>", "</ul>", "<ol>", "</ol>",
  1630                 "<dl>", "</dl>", "<table>", "</table>",
  1631                 "<tr>", "</tr>", "<td>", "</td>",
  1632                 "<th>", "</th>", "<p>", "</p>",
  1633                 "<li>", "</li>", "<dd>", "</dd>",
  1634                 "<dir>", "</dir>", "<dt>", "</dt>",
  1635                 "<h1>", "</h1>", "<h2>", "</h2>",
  1636                 "<h3>", "</h3>", "<h4>", "</h4>",
  1637                 "<h5>", "</h5>", "<h6>", "</h6>",
  1638                 "<pre>", "</pre>", "<menu>", "</menu>",
  1639                 "<listing>", "</listing>", "<hr>",
  1640                 "<blockquote>", "</blockquote>",
  1641                 "<center>", "</center>",
  1642                 "<UL>", "</UL>", "<OL>", "</OL>",
  1643                 "<DL>", "</DL>", "<TABLE>", "</TABLE>",
  1644                 "<TR>", "</TR>", "<TD>", "</TD>",
  1645                 "<TH>", "</TH>", "<P>", "</P>",
  1646                 "<LI>", "</LI>", "<DD>", "</DD>",
  1647                 "<DIR>", "</DIR>", "<DT>", "</DT>",
  1648                 "<H1>", "</H1>", "<H2>", "</H2>",
  1649                 "<H3>", "</H3>", "<H4>", "</H4>",
  1650                 "<H5>", "</H5>", "<H6>", "</H6>",
  1651                 "<PRE>", "</PRE>", "<MENU>", "</MENU>",
  1652                 "<LISTING>", "</LISTING>", "<HR>",
  1653                 "<BLOCKQUOTE>", "</BLOCKQUOTE>",
  1654                 "<CENTER>", "</CENTER>"
  1655         };
  1656         for (int i = 0; i < noninlinetags.length; i++) {
  1657             text = replace(text, noninlinetags[i], "");
  1659         return text;
  1662     public String replace(String text, String tobe, String by) {
  1663         while (true) {
  1664             int startindex = text.indexOf(tobe);
  1665             if (startindex < 0) {
  1666                 return text;
  1668             int endindex = startindex + tobe.length();
  1669             StringBuilder replaced = new StringBuilder();
  1670             if (startindex > 0) {
  1671                 replaced.append(text.substring(0, startindex));
  1673             replaced.append(by);
  1674             if (text.length() > endindex) {
  1675                 replaced.append(text.substring(endindex));
  1677             text = replaced.toString();
  1681     /**
  1682      * Returns a link to the stylesheet file.
  1684      * @return an HtmlTree for the lINK tag which provides the stylesheet location
  1685      */
  1686     public HtmlTree getStyleSheetProperties() {
  1687         String stylesheetfile = configuration.stylesheetfile;
  1688         DocPath stylesheet;
  1689         if (stylesheetfile.isEmpty()) {
  1690             stylesheet = DocPaths.STYLESHEET;
  1691         } else {
  1692             DocFile file = DocFile.createFileForInput(configuration, stylesheetfile);
  1693             stylesheet = DocPath.create(file.getName());
  1695         HtmlTree link = HtmlTree.LINK("stylesheet", "text/css",
  1696                 pathToRoot.resolve(stylesheet).getPath(),
  1697                 "Style");
  1698         return link;
  1701     /**
  1702      * Returns a link to the JavaScript file.
  1704      * @return an HtmlTree for the Script tag which provides the JavaScript location
  1705      */
  1706     public HtmlTree getScriptProperties() {
  1707         HtmlTree script = HtmlTree.SCRIPT("text/javascript",
  1708                 pathToRoot.resolve(DocPaths.JAVASCRIPT).getPath());
  1709         return script;
  1712     /**
  1713      * According to
  1714      * <cite>The Java&trade; Language Specification</cite>,
  1715      * all the outer classes and static nested classes are core classes.
  1716      */
  1717     public boolean isCoreClass(ClassDoc cd) {
  1718         return cd.containingClass() == null || cd.isStatic();
  1721     /**
  1722      * Adds the annotatation types for the given packageDoc.
  1724      * @param packageDoc the package to write annotations for.
  1725      * @param htmltree the documentation tree to which the annotation info will be
  1726      *        added
  1727      */
  1728     public void addAnnotationInfo(PackageDoc packageDoc, Content htmltree) {
  1729         addAnnotationInfo(packageDoc, packageDoc.annotations(), htmltree);
  1732     /**
  1733      * Adds the annotatation types for the given doc.
  1735      * @param doc the package to write annotations for
  1736      * @param htmltree the content tree to which the annotation types will be added
  1737      */
  1738     public void addAnnotationInfo(ProgramElementDoc doc, Content htmltree) {
  1739         addAnnotationInfo(doc, doc.annotations(), htmltree);
  1742     /**
  1743      * Add the annotatation types for the given doc and parameter.
  1745      * @param indent the number of spaces to indent the parameters.
  1746      * @param doc the doc to write annotations for.
  1747      * @param param the parameter to write annotations for.
  1748      * @param tree the content tree to which the annotation types will be added
  1749      */
  1750     public boolean addAnnotationInfo(int indent, Doc doc, Parameter param,
  1751             Content tree) {
  1752         return addAnnotationInfo(indent, doc, param.annotations(), false, tree);
  1755     /**
  1756      * Adds the annotatation types for the given doc.
  1758      * @param doc the doc to write annotations for.
  1759      * @param descList the array of {@link AnnotationDesc}.
  1760      * @param htmltree the documentation tree to which the annotation info will be
  1761      *        added
  1762      */
  1763     private void addAnnotationInfo(Doc doc, AnnotationDesc[] descList,
  1764             Content htmltree) {
  1765         addAnnotationInfo(0, doc, descList, true, htmltree);
  1768     /**
  1769      * Adds the annotatation types for the given doc.
  1771      * @param indent the number of extra spaces to indent the annotations.
  1772      * @param doc the doc to write annotations for.
  1773      * @param descList the array of {@link AnnotationDesc}.
  1774      * @param htmltree the documentation tree to which the annotation info will be
  1775      *        added
  1776      */
  1777     private boolean addAnnotationInfo(int indent, Doc doc,
  1778             AnnotationDesc[] descList, boolean lineBreak, Content htmltree) {
  1779         List<String> annotations = getAnnotations(indent, descList, lineBreak);
  1780         if (annotations.size() == 0) {
  1781             return false;
  1783         Content annotationContent;
  1784         for (Iterator<String> iter = annotations.iterator(); iter.hasNext();) {
  1785             annotationContent = new RawHtml(iter.next());
  1786             htmltree.addContent(annotationContent);
  1788         return true;
  1791    /**
  1792      * Return the string representations of the annotation types for
  1793      * the given doc.
  1795      * @param indent the number of extra spaces to indent the annotations.
  1796      * @param descList the array of {@link AnnotationDesc}.
  1797      * @param linkBreak if true, add new line between each member value.
  1798      * @return an array of strings representing the annotations being
  1799      *         documented.
  1800      */
  1801     private List<String> getAnnotations(int indent, AnnotationDesc[] descList, boolean linkBreak) {
  1802         List<String> results = new ArrayList<String>();
  1803         StringBuilder annotation;
  1804         for (int i = 0; i < descList.length; i++) {
  1805             AnnotationTypeDoc annotationDoc = descList[i].annotationType();
  1806             // If an annotation is not documented, do not add it to the list. If
  1807             // the annotation is of a repeatable type, and if it is not documented
  1808             // and also if its container annotation is not documented, do not add it
  1809             // to the list. If an annotation of a repeatable type is not documented
  1810             // but its container is documented, it will be added to the list.
  1811             if (! Util.isDocumentedAnnotation(annotationDoc) &&
  1812                     (!isAnnotationDocumented && !isContainerDocumented)) {
  1813                 continue;
  1815             annotation = new StringBuilder();
  1816             isAnnotationDocumented = false;
  1817             LinkInfoImpl linkInfo = new LinkInfoImpl(configuration,
  1818                 LinkInfoImpl.CONTEXT_ANNOTATION, annotationDoc);
  1819             AnnotationDesc.ElementValuePair[] pairs = descList[i].elementValues();
  1820             // If the annotation is synthesized, do not print the container.
  1821             if (descList[i].isSynthesized()) {
  1822                 for (int j = 0; j < pairs.length; j++) {
  1823                     AnnotationValue annotationValue = pairs[j].value();
  1824                     List<AnnotationValue> annotationTypeValues = new ArrayList<AnnotationValue>();
  1825                     if (annotationValue.value() instanceof AnnotationValue[]) {
  1826                         AnnotationValue[] annotationArray =
  1827                                 (AnnotationValue[]) annotationValue.value();
  1828                         annotationTypeValues.addAll(Arrays.asList(annotationArray));
  1829                     } else {
  1830                         annotationTypeValues.add(annotationValue);
  1832                     String sep = "";
  1833                     for (AnnotationValue av : annotationTypeValues) {
  1834                         annotation.append(sep);
  1835                         annotation.append(annotationValueToString(av));
  1836                         sep = " ";
  1840             else if (isAnnotationArray(pairs)) {
  1841                 // If the container has 1 or more value defined and if the
  1842                 // repeatable type annotation is not documented, do not print
  1843                 // the container.
  1844                 if (pairs.length == 1 && isAnnotationDocumented) {
  1845                     AnnotationValue[] annotationArray =
  1846                             (AnnotationValue[]) (pairs[0].value()).value();
  1847                     List<AnnotationValue> annotationTypeValues = new ArrayList<AnnotationValue>();
  1848                     annotationTypeValues.addAll(Arrays.asList(annotationArray));
  1849                     String sep = "";
  1850                     for (AnnotationValue av : annotationTypeValues) {
  1851                         annotation.append(sep);
  1852                         annotation.append(annotationValueToString(av));
  1853                         sep = " ";
  1856                 // If the container has 1 or more value defined and if the
  1857                 // repeatable type annotation is not documented, print the container.
  1858                 else {
  1859                     addAnnotations(annotationDoc, linkInfo, annotation, pairs,
  1860                         indent, false);
  1863             else {
  1864                 addAnnotations(annotationDoc, linkInfo, annotation, pairs,
  1865                         indent, linkBreak);
  1867             annotation.append(linkBreak ? DocletConstants.NL : "");
  1868             results.add(annotation.toString());
  1870         return results;
  1873     /**
  1874      * Add annotation to the annotation string.
  1876      * @param annotationDoc the annotation being documented
  1877      * @param linkInfo the information about the link
  1878      * @param annotation the annotation string to which the annotation will be added
  1879      * @param pairs annotation type element and value pairs
  1880      * @param indent the number of extra spaces to indent the annotations.
  1881      * @param linkBreak if true, add new line between each member value
  1882      */
  1883     private void addAnnotations(AnnotationTypeDoc annotationDoc, LinkInfoImpl linkInfo,
  1884             StringBuilder annotation, AnnotationDesc.ElementValuePair[] pairs,
  1885             int indent, boolean linkBreak) {
  1886         linkInfo.label = "@" + annotationDoc.name();
  1887         annotation.append(getLink(linkInfo));
  1888         if (pairs.length > 0) {
  1889             annotation.append('(');
  1890             for (int j = 0; j < pairs.length; j++) {
  1891                 if (j > 0) {
  1892                     annotation.append(",");
  1893                     if (linkBreak) {
  1894                         annotation.append(DocletConstants.NL);
  1895                         int spaces = annotationDoc.name().length() + 2;
  1896                         for (int k = 0; k < (spaces + indent); k++) {
  1897                             annotation.append(' ');
  1901                 annotation.append(getDocLink(LinkInfoImpl.CONTEXT_ANNOTATION,
  1902                         pairs[j].element(), pairs[j].element().name(), false));
  1903                 annotation.append('=');
  1904                 AnnotationValue annotationValue = pairs[j].value();
  1905                 List<AnnotationValue> annotationTypeValues = new ArrayList<AnnotationValue>();
  1906                 if (annotationValue.value() instanceof AnnotationValue[]) {
  1907                     AnnotationValue[] annotationArray =
  1908                             (AnnotationValue[]) annotationValue.value();
  1909                     annotationTypeValues.addAll(Arrays.asList(annotationArray));
  1910                 } else {
  1911                     annotationTypeValues.add(annotationValue);
  1913                 annotation.append(annotationTypeValues.size() == 1 ? "" : "{");
  1914                 String sep = "";
  1915                 for (AnnotationValue av : annotationTypeValues) {
  1916                     annotation.append(sep);
  1917                     annotation.append(annotationValueToString(av));
  1918                     sep = ",";
  1920                 annotation.append(annotationTypeValues.size() == 1 ? "" : "}");
  1921                 isContainerDocumented = false;
  1923             annotation.append(")");
  1927     /**
  1928      * Check if the annotation contains an array of annotation as a value. This
  1929      * check is to verify if a repeatable type annotation is present or not.
  1931      * @param pairs annotation type element and value pairs
  1933      * @return true if the annotation contains an array of annotation as a value.
  1934      */
  1935     private boolean isAnnotationArray(AnnotationDesc.ElementValuePair[] pairs) {
  1936         AnnotationValue annotationValue;
  1937         for (int j = 0; j < pairs.length; j++) {
  1938             annotationValue = pairs[j].value();
  1939             if (annotationValue.value() instanceof AnnotationValue[]) {
  1940                 AnnotationValue[] annotationArray =
  1941                         (AnnotationValue[]) annotationValue.value();
  1942                 if (annotationArray.length > 1) {
  1943                     if (annotationArray[0].value() instanceof AnnotationDesc) {
  1944                         AnnotationTypeDoc annotationDoc =
  1945                                 ((AnnotationDesc) annotationArray[0].value()).annotationType();
  1946                         isContainerDocumented = true;
  1947                         if (Util.isDocumentedAnnotation(annotationDoc)) {
  1948                             isAnnotationDocumented = true;
  1950                         return true;
  1955         return false;
  1958     private String annotationValueToString(AnnotationValue annotationValue) {
  1959         if (annotationValue.value() instanceof Type) {
  1960             Type type = (Type) annotationValue.value();
  1961             if (type.asClassDoc() != null) {
  1962                 LinkInfoImpl linkInfo = new LinkInfoImpl(configuration,
  1963                     LinkInfoImpl.CONTEXT_ANNOTATION, type);
  1964                     linkInfo.label = (type.asClassDoc().isIncluded() ?
  1965                         type.typeName() :
  1966                         type.qualifiedTypeName()) + type.dimension() + ".class";
  1967                 return getLink(linkInfo);
  1968             } else {
  1969                 return type.typeName() + type.dimension() + ".class";
  1971         } else if (annotationValue.value() instanceof AnnotationDesc) {
  1972             List<String> list = getAnnotations(0,
  1973                 new AnnotationDesc[]{(AnnotationDesc) annotationValue.value()},
  1974                     false);
  1975             StringBuilder buf = new StringBuilder();
  1976             for (String s: list) {
  1977                 buf.append(s);
  1979             return buf.toString();
  1980         } else if (annotationValue.value() instanceof MemberDoc) {
  1981             return getDocLink(LinkInfoImpl.CONTEXT_ANNOTATION,
  1982                 (MemberDoc) annotationValue.value(),
  1983                 ((MemberDoc) annotationValue.value()).name(), false);
  1984          } else {
  1985             return annotationValue.toString();
  1989     /**
  1990      * Return the configuation for this doclet.
  1992      * @return the configuration for this doclet.
  1993      */
  1994     public Configuration configuration() {
  1995         return configuration;

mercurial