HtmlDocletWriter.java revision 3793:5a2b9f22ba5d
1/* 2 * Copyright (c) 1998, 2016, 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 */ 25 26package jdk.javadoc.internal.doclets.formats.html; 27 28import java.text.SimpleDateFormat; 29import java.util.*; 30import java.util.regex.Matcher; 31import java.util.regex.Pattern; 32 33import javax.lang.model.element.AnnotationMirror; 34import javax.lang.model.element.AnnotationValue; 35import javax.lang.model.element.Element; 36import javax.lang.model.element.ExecutableElement; 37import javax.lang.model.element.ModuleElement; 38import javax.lang.model.element.Name; 39import javax.lang.model.element.PackageElement; 40import javax.lang.model.element.TypeElement; 41import javax.lang.model.element.VariableElement; 42import javax.lang.model.type.DeclaredType; 43import javax.lang.model.type.TypeMirror; 44import javax.lang.model.util.SimpleAnnotationValueVisitor9; 45import javax.lang.model.util.SimpleElementVisitor9; 46import javax.lang.model.util.SimpleTypeVisitor9; 47 48import com.sun.source.doctree.AttributeTree; 49import com.sun.source.doctree.AttributeTree.ValueKind; 50import com.sun.source.doctree.CommentTree; 51import com.sun.source.doctree.DocRootTree; 52import com.sun.source.doctree.DocTree; 53import com.sun.source.doctree.DocTree.Kind; 54import com.sun.source.doctree.EndElementTree; 55import com.sun.source.doctree.EntityTree; 56import com.sun.source.doctree.ErroneousTree; 57import com.sun.source.doctree.IndexTree; 58import com.sun.source.doctree.InheritDocTree; 59import com.sun.source.doctree.LinkTree; 60import com.sun.source.doctree.LiteralTree; 61import com.sun.source.doctree.SeeTree; 62import com.sun.source.doctree.StartElementTree; 63import com.sun.source.doctree.TextTree; 64import com.sun.source.util.SimpleDocTreeVisitor; 65 66import jdk.javadoc.internal.doclets.formats.html.markup.Comment; 67import jdk.javadoc.internal.doclets.formats.html.markup.ContentBuilder; 68import jdk.javadoc.internal.doclets.formats.html.markup.DocType; 69import jdk.javadoc.internal.doclets.formats.html.markup.HtmlAttr; 70import jdk.javadoc.internal.doclets.formats.html.markup.HtmlConstants; 71import jdk.javadoc.internal.doclets.formats.html.markup.HtmlDocWriter; 72import jdk.javadoc.internal.doclets.formats.html.markup.HtmlDocument; 73import jdk.javadoc.internal.doclets.formats.html.markup.HtmlStyle; 74import jdk.javadoc.internal.doclets.formats.html.markup.HtmlTag; 75import jdk.javadoc.internal.doclets.formats.html.markup.HtmlTree; 76import jdk.javadoc.internal.doclets.formats.html.markup.RawHtml; 77import jdk.javadoc.internal.doclets.formats.html.markup.StringContent; 78import jdk.javadoc.internal.doclets.toolkit.AnnotationTypeWriter; 79import jdk.javadoc.internal.doclets.toolkit.ClassWriter; 80import jdk.javadoc.internal.doclets.toolkit.Configuration; 81import jdk.javadoc.internal.doclets.toolkit.Content; 82import jdk.javadoc.internal.doclets.toolkit.Messages; 83import jdk.javadoc.internal.doclets.toolkit.PackageSummaryWriter; 84import jdk.javadoc.internal.doclets.toolkit.Resources; 85import jdk.javadoc.internal.doclets.toolkit.taglets.DocRootTaglet; 86import jdk.javadoc.internal.doclets.toolkit.taglets.TagletWriter; 87import jdk.javadoc.internal.doclets.toolkit.util.CommentHelper; 88import jdk.javadoc.internal.doclets.toolkit.util.DocFile; 89import jdk.javadoc.internal.doclets.toolkit.util.DocFileIOException; 90import jdk.javadoc.internal.doclets.toolkit.util.DocLink; 91import jdk.javadoc.internal.doclets.toolkit.util.DocPath; 92import jdk.javadoc.internal.doclets.toolkit.util.DocPaths; 93import jdk.javadoc.internal.doclets.toolkit.util.DocletConstants; 94import jdk.javadoc.internal.doclets.toolkit.util.ImplementedMethods; 95import jdk.javadoc.internal.doclets.toolkit.util.Utils; 96 97import static com.sun.source.doctree.AttributeTree.ValueKind.*; 98import static com.sun.source.doctree.DocTree.Kind.*; 99import static jdk.javadoc.internal.doclets.formats.html.markup.HtmlDocWriter.CONTENT_TYPE; 100import static jdk.javadoc.internal.doclets.toolkit.util.CommentHelper.SPACER; 101 102 103/** 104 * Class for the Html Format Code Generation specific to JavaDoc. 105 * This Class contains methods related to the Html Code Generation which 106 * are used extensively while generating the entire documentation. 107 * 108 * <p><b>This is NOT part of any supported API. 109 * If you write code that depends on this, you do so at your own risk. 110 * This code and its internal interfaces are subject to change or 111 * deletion without notice.</b> 112 * 113 * @author Atul M Dambalkar 114 * @author Robert Field 115 * @author Bhavesh Patel (Modified) 116 */ 117public class HtmlDocletWriter extends HtmlDocWriter { 118 119 /** 120 * Relative path from the file getting generated to the destination 121 * directory. For example, if the file getting generated is 122 * "java/lang/Object.html", then the path to the root is "../..". 123 * This string can be empty if the file getting generated is in 124 * the destination directory. 125 */ 126 public final DocPath pathToRoot; 127 128 /** 129 * Platform-independent path from the current or the 130 * destination directory to the file getting generated. 131 * Used when creating the file. 132 */ 133 public final DocPath path; 134 135 /** 136 * Name of the file getting generated. If the file getting generated is 137 * "java/lang/Object.html", then the filename is "Object.html". 138 */ 139 public final DocPath filename; 140 141 /** 142 * The global configuration information for this run. 143 */ 144 public final ConfigurationImpl configuration; 145 146 protected final Utils utils; 147 148 protected final Contents contents; 149 150 protected final Messages messages; 151 152 protected final Resources resources; 153 154 /** 155 * To check whether annotation heading is printed or not. 156 */ 157 protected boolean printedAnnotationHeading = false; 158 159 /** 160 * To check whether annotation field heading is printed or not. 161 */ 162 protected boolean printedAnnotationFieldHeading = false; 163 164 /** 165 * To check whether the repeated annotations is documented or not. 166 */ 167 private boolean isAnnotationDocumented = false; 168 169 /** 170 * To check whether the container annotations is documented or not. 171 */ 172 private boolean isContainerDocumented = false; 173 174 HtmlTree fixedNavDiv = new HtmlTree(HtmlTag.DIV); 175 176 final static Pattern IMPROPER_HTML_CHARS = Pattern.compile(".*[&<>].*"); 177 178 /** 179 * Constructor to construct the HtmlStandardWriter object. 180 * 181 * @param path File to be generated. 182 */ 183 public HtmlDocletWriter(ConfigurationImpl configuration, DocPath path) { 184 super(configuration, path); 185 this.configuration = configuration; 186 this.contents = configuration.contents; 187 this.messages = configuration.messages; 188 this.resources = configuration.resources; 189 this.utils = configuration.utils; 190 this.path = path; 191 this.pathToRoot = path.parent().invert(); 192 this.filename = path.basename(); 193 } 194 195 /** 196 * Replace {@docRoot} tag used in options that accept HTML text, such 197 * as -header, -footer, -top and -bottom, and when converting a relative 198 * HREF where commentTagsToString inserts a {@docRoot} where one was 199 * missing. (Also see DocRootTaglet for {@docRoot} tags in doc 200 * comments.) 201 * <p> 202 * Replace {@docRoot} tag in htmlstr with the relative path to the 203 * destination directory from the directory where the file is being 204 * written, looping to handle all such tags in htmlstr. 205 * <p> 206 * For example, for "-d docs" and -header containing {@docRoot}, when 207 * the HTML page for source file p/C1.java is being generated, the 208 * {@docRoot} tag would be inserted into the header as "../", 209 * the relative path from docs/p/ to docs/ (the document root). 210 * <p> 211 * Note: This doc comment was written with '&#064;' representing '@' 212 * to prevent the inline tag from being interpreted. 213 */ 214 public String replaceDocRootDir(String htmlstr) { 215 // Return if no inline tags exist 216 int index = htmlstr.indexOf("{@"); 217 if (index < 0) { 218 return htmlstr; 219 } 220 Matcher docrootMatcher = docrootPattern.matcher(htmlstr); 221 if (!docrootMatcher.find()) { 222 return htmlstr; 223 } 224 StringBuilder buf = new StringBuilder(); 225 int prevEnd = 0; 226 do { 227 int match = docrootMatcher.start(); 228 // append htmlstr up to start of next {@docroot} 229 buf.append(htmlstr.substring(prevEnd, match)); 230 prevEnd = docrootMatcher.end(); 231 if (configuration.docrootparent.length() > 0 && htmlstr.startsWith("/..", prevEnd)) { 232 // Insert the absolute link if {@docRoot} is followed by "/..". 233 buf.append(configuration.docrootparent); 234 prevEnd += 3; 235 } else { 236 // Insert relative path where {@docRoot} was located 237 buf.append(pathToRoot.isEmpty() ? "." : pathToRoot.getPath()); 238 } 239 // Append slash if next character is not a slash 240 if (prevEnd < htmlstr.length() && htmlstr.charAt(prevEnd) != '/') { 241 buf.append('/'); 242 } 243 } while (docrootMatcher.find()); 244 buf.append(htmlstr.substring(prevEnd)); 245 return buf.toString(); 246 } 247 //where: 248 // Note: {@docRoot} is not case sensitive when passed in w/command line option: 249 private static final Pattern docrootPattern = 250 Pattern.compile(Pattern.quote("{@docroot}"), Pattern.CASE_INSENSITIVE); 251 252 /** 253 * Get the script to show or hide the All classes link. 254 * 255 * @param id id of the element to show or hide 256 * @return a content tree for the script 257 */ 258 public Content getAllClassesLinkScript(String id) { 259 HtmlTree script = HtmlTree.SCRIPT(); 260 String scriptCode = "<!--\n" + 261 " allClassesLink = document.getElementById(\"" + id + "\");\n" + 262 " if(window==top) {\n" + 263 " allClassesLink.style.display = \"block\";\n" + 264 " }\n" + 265 " else {\n" + 266 " allClassesLink.style.display = \"none\";\n" + 267 " }\n" + 268 " //-->\n"; 269 Content scriptContent = new RawHtml(scriptCode.replace("\n", DocletConstants.NL)); 270 script.addContent(scriptContent); 271 Content div = HtmlTree.DIV(script); 272 Content div_noscript = HtmlTree.DIV(contents.noScriptMessage); 273 Content noScript = HtmlTree.NOSCRIPT(div_noscript); 274 div.addContent(noScript); 275 return div; 276 } 277 278 /** 279 * Add method information. 280 * 281 * @param method the method to be documented 282 * @param dl the content tree to which the method information will be added 283 */ 284 private void addMethodInfo(ExecutableElement method, Content dl) { 285 TypeElement enclosing = utils.getEnclosingTypeElement(method); 286 List<? extends TypeMirror> intfacs = enclosing.getInterfaces(); 287 ExecutableElement overriddenMethod = utils.overriddenMethod(method); 288 // Check whether there is any implementation or overridden info to be 289 // printed. If no overridden or implementation info needs to be 290 // printed, do not print this section. 291 if ((!intfacs.isEmpty() 292 && new ImplementedMethods(method, this.configuration).build().isEmpty() == false) 293 || overriddenMethod != null) { 294 MethodWriterImpl.addImplementsInfo(this, method, dl); 295 if (overriddenMethod != null) { 296 MethodWriterImpl.addOverridden(this, 297 utils.overriddenType(method), 298 overriddenMethod, 299 dl); 300 } 301 } 302 } 303 304 /** 305 * Adds the tags information. 306 * 307 * @param e the Element for which the tags will be generated 308 * @param htmltree the documentation tree to which the tags will be added 309 */ 310 protected void addTagsInfo(Element e, Content htmltree) { 311 if (configuration.nocomment) { 312 return; 313 } 314 Content dl = new HtmlTree(HtmlTag.DL); 315 if (utils.isExecutableElement(e) && !utils.isConstructor(e)) { 316 addMethodInfo((ExecutableElement)e, dl); 317 } 318 Content output = new ContentBuilder(); 319 TagletWriter.genTagOutput(configuration.tagletManager, e, 320 configuration.tagletManager.getCustomTaglets(e), 321 getTagletWriterInstance(false), output); 322 dl.addContent(output); 323 htmltree.addContent(dl); 324 } 325 326 /** 327 * Check whether there are any tags for Serialization Overview 328 * section to be printed. 329 * 330 * @param field the VariableElement object to check for tags. 331 * @return true if there are tags to be printed else return false. 332 */ 333 protected boolean hasSerializationOverviewTags(VariableElement field) { 334 Content output = new ContentBuilder(); 335 TagletWriter.genTagOutput(configuration.tagletManager, field, 336 configuration.tagletManager.getCustomTaglets(field), 337 getTagletWriterInstance(false), output); 338 return !output.isEmpty(); 339 } 340 341 /** 342 * Returns a TagletWriter that knows how to write HTML. 343 * 344 * @return a TagletWriter that knows how to write HTML. 345 */ 346 public TagletWriter getTagletWriterInstance(boolean isFirstSentence) { 347 return new TagletWriterImpl(this, isFirstSentence); 348 } 349 350 /** 351 * Get Package link, with target frame. 352 * 353 * @param pkg The link will be to the "package-summary.html" page for this package 354 * @param target name of the target frame 355 * @param label tag for the link 356 * @return a content for the target package link 357 */ 358 public Content getTargetPackageLink(PackageElement pkg, String target, 359 Content label) { 360 return getHyperLink(pathString(pkg, DocPaths.PACKAGE_SUMMARY), label, "", target); 361 } 362 363 /** 364 * Get Module Package link, with target frame. 365 * 366 * @param pkg the PackageElement 367 * @param target name of the target frame 368 * @param label tag for the link 369 * @param mdle the module being documented 370 * @return a content for the target module packages link 371 */ 372 public Content getTargetModulePackageLink(PackageElement pkg, String target, 373 Content label, ModuleElement mdle) { 374 return getHyperLink(pathString(pkg, DocPaths.PACKAGE_SUMMARY), 375 label, "", target); 376 } 377 378 /** 379 * Get Module link, with target frame. 380 * 381 * @param target name of the target frame 382 * @param label tag for the link 383 * @param mdle the module being documented 384 * @return a content for the target module link 385 */ 386 public Content getTargetModuleLink(String target, Content label, ModuleElement mdle) { 387 return getHyperLink(pathToRoot.resolve( 388 DocPaths.moduleSummary(mdle)), label, "", target); 389 } 390 391 public void addClassesSummary(SortedSet<TypeElement> classes, String label, 392 String tableSummary, List<String> tableHeader, Content summaryContentTree) { 393 if (!classes.isEmpty()) { 394 Content caption = getTableCaption(new RawHtml(label)); 395 Content table = (configuration.isOutputHtml5()) 396 ? HtmlTree.TABLE(HtmlStyle.typeSummary, caption) 397 : HtmlTree.TABLE(HtmlStyle.typeSummary, tableSummary, caption); 398 table.addContent(getSummaryTableHeader(tableHeader, "col")); 399 Content tbody = new HtmlTree(HtmlTag.TBODY); 400 boolean altColor = true; 401 for (TypeElement te : classes) { 402 if (!utils.isCoreClass(te) || 403 !configuration.isGeneratedDoc(te)) { 404 continue; 405 } 406 Content classContent = getLink(new LinkInfoImpl( 407 configuration, LinkInfoImpl.Kind.PACKAGE, te)); 408 Content tdClass = HtmlTree.TH_ROW_SCOPE(HtmlStyle.colFirst, classContent); 409 HtmlTree tr = HtmlTree.TR(tdClass); 410 tr.addStyle(altColor ? HtmlStyle.altColor : HtmlStyle.rowColor); 411 altColor = !altColor; 412 HtmlTree tdClassDescription = new HtmlTree(HtmlTag.TD); 413 tdClassDescription.addStyle(HtmlStyle.colLast); 414 if (utils.isDeprecated(te)) { 415 tdClassDescription.addContent(contents.deprecatedLabel); 416 List<? extends DocTree> tags = utils.getDeprecatedTrees(te); 417 if (!tags.isEmpty()) { 418 addSummaryDeprecatedComment(te, tags.get(0), tdClassDescription); 419 } 420 } else { 421 addSummaryComment(te, tdClassDescription); 422 } 423 tr.addContent(tdClassDescription); 424 tbody.addContent(tr); 425 } 426 table.addContent(tbody); 427 summaryContentTree.addContent(table); 428 } 429 } 430 431 /** 432 * Generates the HTML document tree and prints it out. 433 * 434 * @param metakeywords Array of String keywords for META tag. Each element 435 * of the array is assigned to a separate META tag. 436 * Pass in null for no array 437 * @param includeScript true if printing windowtitle script 438 * false for files that appear in the left-hand frames 439 * @param body the body htmltree to be included in the document 440 * @throws DocFileIOException if there is a problem writing the file 441 */ 442 public void printHtmlDocument(List<String> metakeywords, boolean includeScript, 443 Content body) throws DocFileIOException { 444 Content htmlDocType = configuration.isOutputHtml5() 445 ? DocType.HTML5 446 : DocType.TRANSITIONAL; 447 Content htmlComment = new Comment(configuration.getText("doclet.New_Page")); 448 Content head = new HtmlTree(HtmlTag.HEAD); 449 head.addContent(getGeneratedBy(!configuration.notimestamp)); 450 head.addContent(getTitle()); 451 Content meta = HtmlTree.META("Content-Type", CONTENT_TYPE, 452 (configuration.charset.length() > 0) ? 453 configuration.charset : HtmlConstants.HTML_DEFAULT_CHARSET); 454 head.addContent(meta); 455 if (!configuration.notimestamp) { 456 SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd"); 457 meta = HtmlTree.META(configuration.isOutputHtml5() 458 ? "dc.created" 459 : "date", dateFormat.format(new Date())); 460 head.addContent(meta); 461 } 462 if (metakeywords != null) { 463 for (String metakeyword : metakeywords) { 464 meta = HtmlTree.META("keywords", metakeyword); 465 head.addContent(meta); 466 } 467 } 468 addStyleSheetProperties(head); 469 addScriptProperties(head); 470 Content htmlTree = HtmlTree.HTML(configuration.getLocale().getLanguage(), 471 head, body); 472 Content htmlDocument = new HtmlDocument(htmlDocType, 473 htmlComment, htmlTree); 474 write(htmlDocument); 475 } 476 477 /** 478 * Get the window title. 479 * 480 * @param title the title string to construct the complete window title 481 * @return the window title string 482 */ 483 public String getWindowTitle(String title) { 484 if (configuration.windowtitle.length() > 0) { 485 title += " (" + configuration.windowtitle + ")"; 486 } 487 return title; 488 } 489 490 /** 491 * Get user specified header and the footer. 492 * 493 * @param header if true print the user provided header else print the 494 * user provided footer. 495 */ 496 public Content getUserHeaderFooter(boolean header) { 497 String content; 498 if (header) { 499 content = replaceDocRootDir(configuration.header); 500 } else { 501 if (configuration.footer.length() != 0) { 502 content = replaceDocRootDir(configuration.footer); 503 } else { 504 content = replaceDocRootDir(configuration.header); 505 } 506 } 507 Content rawContent = new RawHtml(content); 508 return rawContent; 509 } 510 511 /** 512 * Adds the user specified top. 513 * 514 * @param htmlTree the content tree to which user specified top will be added 515 */ 516 public void addTop(Content htmlTree) { 517 Content top = new RawHtml(replaceDocRootDir(configuration.top)); 518 fixedNavDiv.addContent(top); 519 } 520 521 /** 522 * Adds the user specified bottom. 523 * 524 * @param htmlTree the content tree to which user specified bottom will be added 525 */ 526 public void addBottom(Content htmlTree) { 527 Content bottom = new RawHtml(replaceDocRootDir(configuration.bottom)); 528 Content small = HtmlTree.SMALL(bottom); 529 Content p = HtmlTree.P(HtmlStyle.legalCopy, small); 530 htmlTree.addContent(p); 531 } 532 533 /** 534 * Adds the navigation bar for the Html page at the top and and the bottom. 535 * 536 * @param header If true print navigation bar at the top of the page else 537 * @param htmlTree the HtmlTree to which the nav links will be added 538 */ 539 protected void addNavLinks(boolean header, Content htmlTree) { 540 if (!configuration.nonavbar) { 541 Content tree = (configuration.allowTag(HtmlTag.NAV)) 542 ? HtmlTree.NAV() 543 : htmlTree; 544 String allClassesId = "allclasses_"; 545 HtmlTree navDiv = new HtmlTree(HtmlTag.DIV); 546 fixedNavDiv.addStyle(HtmlStyle.fixedNav); 547 Content skipNavLinks = configuration.getContent("doclet.Skip_navigation_links"); 548 if (header) { 549 fixedNavDiv.addContent(HtmlConstants.START_OF_TOP_NAVBAR); 550 navDiv.addStyle(HtmlStyle.topNav); 551 allClassesId += "navbar_top"; 552 Content a = getMarkerAnchor(SectionName.NAVBAR_TOP); 553 //WCAG - Hyperlinks should contain text or an image with alt text - for AT tools 554 navDiv.addContent(a); 555 Content skipLinkContent = HtmlTree.DIV(HtmlStyle.skipNav, getHyperLink( 556 getDocLink(SectionName.SKIP_NAVBAR_TOP), skipNavLinks, 557 skipNavLinks.toString(), "")); 558 navDiv.addContent(skipLinkContent); 559 } else { 560 tree.addContent(HtmlConstants.START_OF_BOTTOM_NAVBAR); 561 navDiv.addStyle(HtmlStyle.bottomNav); 562 allClassesId += "navbar_bottom"; 563 Content a = getMarkerAnchor(SectionName.NAVBAR_BOTTOM); 564 navDiv.addContent(a); 565 Content skipLinkContent = HtmlTree.DIV(HtmlStyle.skipNav, getHyperLink( 566 getDocLink(SectionName.SKIP_NAVBAR_BOTTOM), skipNavLinks, 567 skipNavLinks.toString(), "")); 568 navDiv.addContent(skipLinkContent); 569 } 570 if (header) { 571 navDiv.addContent(getMarkerAnchor(SectionName.NAVBAR_TOP_FIRSTROW)); 572 } else { 573 navDiv.addContent(getMarkerAnchor(SectionName.NAVBAR_BOTTOM_FIRSTROW)); 574 } 575 HtmlTree navList = new HtmlTree(HtmlTag.UL); 576 navList.addStyle(HtmlStyle.navList); 577 navList.addAttr(HtmlAttr.TITLE, 578 configuration.getText("doclet.Navigation")); 579 if (configuration.createoverview) { 580 navList.addContent(getNavLinkContents()); 581 } 582 if (configuration.showModules) { 583 if (configuration.modules.size() == 1) { 584 navList.addContent(getNavLinkModule(configuration.modules.first())); 585 } else if (!configuration.modules.isEmpty()) { 586 navList.addContent(getNavLinkModule()); 587 } 588 } 589 if (configuration.packages.size() == 1) { 590 navList.addContent(getNavLinkPackage(configuration.packages.first())); 591 } else if (!configuration.packages.isEmpty()) { 592 navList.addContent(getNavLinkPackage()); 593 } 594 navList.addContent(getNavLinkClass()); 595 if(configuration.classuse) { 596 navList.addContent(getNavLinkClassUse()); 597 } 598 if(configuration.createtree) { 599 navList.addContent(getNavLinkTree()); 600 } 601 if(!(configuration.nodeprecated || 602 configuration.nodeprecatedlist)) { 603 navList.addContent(getNavLinkDeprecated()); 604 } 605 if(configuration.createindex) { 606 navList.addContent(getNavLinkIndex()); 607 } 608 if (!configuration.nohelp) { 609 navList.addContent(getNavLinkHelp()); 610 } 611 navDiv.addContent(navList); 612 Content aboutDiv = HtmlTree.DIV(HtmlStyle.aboutLanguage, getUserHeaderFooter(header)); 613 navDiv.addContent(aboutDiv); 614 if (header) { 615 fixedNavDiv.addContent(navDiv); 616 } else { 617 tree.addContent(navDiv); 618 } 619 Content ulNav = HtmlTree.UL(HtmlStyle.navList, getNavLinkPrevious(), getNavLinkNext()); 620 Content subDiv = HtmlTree.DIV(HtmlStyle.subNav, ulNav); 621 if (configuration.frames) { 622 Content ulFrames = HtmlTree.UL(HtmlStyle.navList, 623 getNavShowLists(), getNavHideLists(filename)); 624 subDiv.addContent(ulFrames); 625 } 626 HtmlTree ulAllClasses = HtmlTree.UL(HtmlStyle.navList, getNavLinkClassIndex()); 627 ulAllClasses.addAttr(HtmlAttr.ID, allClassesId); 628 subDiv.addContent(ulAllClasses); 629 if (header && configuration.createindex) { 630 HtmlTree inputText = HtmlTree.INPUT("text", "search"); 631 HtmlTree inputReset = HtmlTree.INPUT("reset", "reset"); 632 Content searchTxt = new ContentBuilder(); 633 searchTxt.addContent(configuration.getContent("doclet.search")); 634 searchTxt.addContent(Contents.SPACE); 635 HtmlTree liInput = HtmlTree.LI(HtmlTree.SPAN(searchTxt)); 636 liInput.addContent(inputText); 637 liInput.addContent(inputReset); 638 HtmlTree ulSearch = HtmlTree.UL(HtmlStyle.navListSearch, liInput); 639 subDiv.addContent(ulSearch); 640 } 641 subDiv.addContent(getAllClassesLinkScript(allClassesId)); 642 addSummaryDetailLinks(subDiv); 643 if (header) { 644 subDiv.addContent(getMarkerAnchor(SectionName.SKIP_NAVBAR_TOP)); 645 fixedNavDiv.addContent(subDiv); 646 fixedNavDiv.addContent(HtmlConstants.END_OF_TOP_NAVBAR); 647 tree.addContent(fixedNavDiv); 648 HtmlTree paddingDiv = HtmlTree.DIV(HtmlStyle.navPadding, Contents.SPACE); 649 tree.addContent(paddingDiv); 650 } else { 651 subDiv.addContent(getMarkerAnchor(SectionName.SKIP_NAVBAR_BOTTOM)); 652 tree.addContent(subDiv); 653 tree.addContent(HtmlConstants.END_OF_BOTTOM_NAVBAR); 654 } 655 if (configuration.allowTag(HtmlTag.NAV)) { 656 htmlTree.addContent(tree); 657 } 658 } 659 } 660 661 /** 662 * Get the word "NEXT" to indicate that no link is available. Override 663 * this method to customize next link. 664 * 665 * @return a content tree for the link 666 */ 667 protected Content getNavLinkNext() { 668 return getNavLinkNext(null); 669 } 670 671 /** 672 * Get the word "PREV" to indicate that no link is available. Override 673 * this method to customize prev link. 674 * 675 * @return a content tree for the link 676 */ 677 protected Content getNavLinkPrevious() { 678 return getNavLinkPrevious(null); 679 } 680 681 /** 682 * Do nothing. This is the default method. 683 */ 684 protected void addSummaryDetailLinks(Content navDiv) { 685 } 686 687 /** 688 * Get link to the "overview-summary.html" page. 689 * 690 * @return a content tree for the link 691 */ 692 protected Content getNavLinkContents() { 693 Content linkContent = getHyperLink(pathToRoot.resolve(DocPaths.overviewSummary(configuration.frames)), 694 contents.overviewLabel, "", ""); 695 Content li = HtmlTree.LI(linkContent); 696 return li; 697 } 698 699 /** 700 * Get link to the module summary page for the module passed. 701 * 702 * @param mdle Module to which link will be generated 703 * @return a content tree for the link 704 */ 705 protected Content getNavLinkModule(ModuleElement mdle) { 706 Content linkContent = getModuleLink(mdle, contents.moduleLabel); 707 Content li = HtmlTree.LI(linkContent); 708 return li; 709 } 710 711 /** 712 * Get the word "Module", to indicate that link is not available here. 713 * 714 * @return a content tree for the link 715 */ 716 protected Content getNavLinkModule() { 717 Content li = HtmlTree.LI(contents.moduleLabel); 718 return li; 719 } 720 721 /** 722 * Get link to the "package-summary.html" page for the package passed. 723 * 724 * @param pkg Package to which link will be generated 725 * @return a content tree for the link 726 */ 727 protected Content getNavLinkPackage(PackageElement pkg) { 728 Content linkContent = getPackageLink(pkg, contents.packageLabel); 729 Content li = HtmlTree.LI(linkContent); 730 return li; 731 } 732 733 /** 734 * Get the word "Package" , to indicate that link is not available here. 735 * 736 * @return a content tree for the link 737 */ 738 protected Content getNavLinkPackage() { 739 Content li = HtmlTree.LI(contents.packageLabel); 740 return li; 741 } 742 743 /** 744 * Get the word "Use", to indicate that link is not available. 745 * 746 * @return a content tree for the link 747 */ 748 protected Content getNavLinkClassUse() { 749 Content li = HtmlTree.LI(contents.useLabel); 750 return li; 751 } 752 753 /** 754 * Get link for previous file. 755 * 756 * @param prev File name for the prev link 757 * @return a content tree for the link 758 */ 759 public Content getNavLinkPrevious(DocPath prev) { 760 Content li; 761 if (prev != null) { 762 li = HtmlTree.LI(getHyperLink(prev, contents.prevLabel, "", "")); 763 } 764 else 765 li = HtmlTree.LI(contents.prevLabel); 766 return li; 767 } 768 769 /** 770 * Get link for next file. If next is null, just print the label 771 * without linking it anywhere. 772 * 773 * @param next File name for the next link 774 * @return a content tree for the link 775 */ 776 public Content getNavLinkNext(DocPath next) { 777 Content li; 778 if (next != null) { 779 li = HtmlTree.LI(getHyperLink(next, contents.nextLabel, "", "")); 780 } 781 else 782 li = HtmlTree.LI(contents.nextLabel); 783 return li; 784 } 785 786 /** 787 * Get "FRAMES" link, to switch to the frame version of the output. 788 * 789 * @param link File to be linked, "index.html" 790 * @return a content tree for the link 791 */ 792 protected Content getNavShowLists(DocPath link) { 793 DocLink dl = new DocLink(link, path.getPath(), null); 794 Content framesContent = getHyperLink(dl, contents.framesLabel, "", "_top"); 795 Content li = HtmlTree.LI(framesContent); 796 return li; 797 } 798 799 /** 800 * Get "FRAMES" link, to switch to the frame version of the output. 801 * 802 * @return a content tree for the link 803 */ 804 protected Content getNavShowLists() { 805 return getNavShowLists(pathToRoot.resolve(DocPaths.INDEX)); 806 } 807 808 /** 809 * Get "NO FRAMES" link, to switch to the non-frame version of the output. 810 * 811 * @param link File to be linked 812 * @return a content tree for the link 813 */ 814 protected Content getNavHideLists(DocPath link) { 815 Content noFramesContent = getHyperLink(link, contents.noFramesLabel, "", "_top"); 816 Content li = HtmlTree.LI(noFramesContent); 817 return li; 818 } 819 820 /** 821 * Get "Tree" link in the navigation bar. If there is only one package 822 * specified on the command line, then the "Tree" link will be to the 823 * only "package-tree.html" file otherwise it will be to the 824 * "overview-tree.html" file. 825 * 826 * @return a content tree for the link 827 */ 828 protected Content getNavLinkTree() { 829 List<PackageElement> packages = new ArrayList<>(configuration.getSpecifiedPackageElements()); 830 DocPath docPath = packages.size() == 1 && configuration.getSpecifiedTypeElements().isEmpty() 831 ? pathString(packages.get(0), DocPaths.PACKAGE_TREE) 832 : pathToRoot.resolve(DocPaths.OVERVIEW_TREE); 833 return HtmlTree.LI(getHyperLink(docPath, contents.treeLabel, "", "")); 834 } 835 836 /** 837 * Get the overview tree link for the main tree. 838 * 839 * @param label the label for the link 840 * @return a content tree for the link 841 */ 842 protected Content getNavLinkMainTree(String label) { 843 Content mainTreeContent = getHyperLink(pathToRoot.resolve(DocPaths.OVERVIEW_TREE), 844 new StringContent(label)); 845 Content li = HtmlTree.LI(mainTreeContent); 846 return li; 847 } 848 849 /** 850 * Get the word "Class", to indicate that class link is not available. 851 * 852 * @return a content tree for the link 853 */ 854 protected Content getNavLinkClass() { 855 Content li = HtmlTree.LI(contents.classLabel); 856 return li; 857 } 858 859 /** 860 * Get "Deprecated" API link in the navigation bar. 861 * 862 * @return a content tree for the link 863 */ 864 protected Content getNavLinkDeprecated() { 865 Content linkContent = getHyperLink(pathToRoot.resolve(DocPaths.DEPRECATED_LIST), 866 contents.deprecatedLabel, "", ""); 867 Content li = HtmlTree.LI(linkContent); 868 return li; 869 } 870 871 /** 872 * Get link for generated index. If the user has used "-splitindex" 873 * command line option, then link to file "index-files/index-1.html" is 874 * generated otherwise link to file "index-all.html" is generated. 875 * 876 * @return a content tree for the link 877 */ 878 protected Content getNavLinkClassIndex() { 879 Content allClassesContent = getHyperLink(pathToRoot.resolve( 880 DocPaths.AllClasses(configuration.frames)), 881 contents.allClassesLabel, "", ""); 882 Content li = HtmlTree.LI(allClassesContent); 883 return li; 884 } 885 886 /** 887 * Get link for generated class index. 888 * 889 * @return a content tree for the link 890 */ 891 protected Content getNavLinkIndex() { 892 Content linkContent = getHyperLink(pathToRoot.resolve( 893 (configuration.splitindex 894 ? DocPaths.INDEX_FILES.resolve(DocPaths.indexN(1)) 895 : DocPaths.INDEX_ALL)), 896 contents.indexLabel, "", ""); 897 Content li = HtmlTree.LI(linkContent); 898 return li; 899 } 900 901 /** 902 * Get help file link. If user has provided a help file, then generate a 903 * link to the user given file, which is already copied to current or 904 * destination directory. 905 * 906 * @return a content tree for the link 907 */ 908 protected Content getNavLinkHelp() { 909 String helpfile = configuration.helpfile; 910 DocPath helpfilenm; 911 if (helpfile.isEmpty()) { 912 helpfilenm = DocPaths.HELP_DOC; 913 } else { 914 DocFile file = DocFile.createFileForInput(configuration, helpfile); 915 helpfilenm = DocPath.create(file.getName()); 916 } 917 Content linkContent = getHyperLink(pathToRoot.resolve(helpfilenm), 918 contents.helpLabel, "", ""); 919 Content li = HtmlTree.LI(linkContent); 920 return li; 921 } 922 923 /** 924 * Add gap between navigation bar elements. 925 * 926 * @param liNav the content tree to which the gap will be added 927 */ 928 protected void addNavGap(Content liNav) { 929 liNav.addContent(Contents.SPACE); 930 liNav.addContent("|"); 931 liNav.addContent(Contents.SPACE); 932 } 933 934 /** 935 * Get summary table header. 936 * 937 * @param header the header for the table 938 * @param scope the scope of the headers 939 * @return a content tree for the header 940 */ 941 public Content getSummaryTableHeader(List<String> header, String scope) { 942 Content tr = new HtmlTree(HtmlTag.TR); 943 final int size = header.size(); 944 Content tableHeader; 945 if (size == 2) { 946 tableHeader = new StringContent(header.get(0)); 947 tr.addContent(HtmlTree.TH(HtmlStyle.colFirst, scope, tableHeader)); 948 tableHeader = new StringContent(header.get(1)); 949 tr.addContent(HtmlTree.TH(HtmlStyle.colLast, scope, tableHeader)); 950 return tr; 951 } 952 for (int i = 0; i < size; i++) { 953 tableHeader = new StringContent(header.get(i)); 954 if (i == 0) 955 tr.addContent(HtmlTree.TH(HtmlStyle.colFirst, scope, tableHeader)); 956 else if (i == 1) 957 tr.addContent(HtmlTree.TH(HtmlStyle.colSecond, scope, tableHeader)); 958 else if (i == (size - 1)) 959 tr.addContent(HtmlTree.TH(HtmlStyle.colLast, scope, tableHeader)); 960 else 961 tr.addContent(HtmlTree.TH(scope, tableHeader)); 962 } 963 return tr; 964 } 965 966 /** 967 * Get table caption. 968 * 969 * @param rawText the caption for the table which could be raw Html 970 * @return a content tree for the caption 971 */ 972 public Content getTableCaption(Content title) { 973 Content captionSpan = HtmlTree.SPAN(title); 974 Content space = Contents.SPACE; 975 Content tabSpan = HtmlTree.SPAN(HtmlStyle.tabEnd, space); 976 Content caption = HtmlTree.CAPTION(captionSpan); 977 caption.addContent(tabSpan); 978 return caption; 979 } 980 981 /** 982 * Get the marker anchor which will be added to the documentation tree. 983 * 984 * @param anchorName the anchor name attribute 985 * @return a content tree for the marker anchor 986 */ 987 public Content getMarkerAnchor(String anchorName) { 988 return getMarkerAnchor(getName(anchorName), null); 989 } 990 991 /** 992 * Get the marker anchor which will be added to the documentation tree. 993 * 994 * @param sectionName the section name anchor attribute for page 995 * @return a content tree for the marker anchor 996 */ 997 public Content getMarkerAnchor(SectionName sectionName) { 998 return getMarkerAnchor(sectionName.getName(), null); 999 } 1000 1001 /** 1002 * Get the marker anchor which will be added to the documentation tree. 1003 * 1004 * @param sectionName the section name anchor attribute for page 1005 * @param anchorName the anchor name combined with section name attribute for the page 1006 * @return a content tree for the marker anchor 1007 */ 1008 public Content getMarkerAnchor(SectionName sectionName, String anchorName) { 1009 return getMarkerAnchor(sectionName.getName() + getName(anchorName), null); 1010 } 1011 1012 /** 1013 * Get the marker anchor which will be added to the documentation tree. 1014 * 1015 * @param anchorName the anchor name or id attribute 1016 * @param anchorContent the content that should be added to the anchor 1017 * @return a content tree for the marker anchor 1018 */ 1019 public Content getMarkerAnchor(String anchorName, Content anchorContent) { 1020 if (anchorContent == null) 1021 anchorContent = new Comment(" "); 1022 Content markerAnchor = HtmlTree.A(configuration.htmlVersion, anchorName, anchorContent); 1023 return markerAnchor; 1024 } 1025 1026 /** 1027 * Returns a packagename content. 1028 * 1029 * @param packageElement the package to check 1030 * @return package name content 1031 */ 1032 public Content getPackageName(PackageElement packageElement) { 1033 return packageElement == null || packageElement.isUnnamed() 1034 ? contents.defaultPackageLabel 1035 : getPackageLabel(packageElement.getQualifiedName()); 1036 } 1037 1038 /** 1039 * Returns a package name label. 1040 * 1041 * @param packageName the package name 1042 * @return the package name content 1043 */ 1044 public Content getPackageLabel(CharSequence packageName) { 1045 return new StringContent(packageName); 1046 } 1047 1048 /** 1049 * Return the path to the class page for a typeElement. 1050 * 1051 * @param te TypeElement for which the path is requested. 1052 * @param name Name of the file(doesn't include path). 1053 */ 1054 protected DocPath pathString(TypeElement te, DocPath name) { 1055 return pathString(utils.containingPackage(te), name); 1056 } 1057 1058 /** 1059 * Return path to the given file name in the given package. So if the name 1060 * passed is "Object.html" and the name of the package is "java.lang", and 1061 * if the relative path is "../.." then returned string will be 1062 * "../../java/lang/Object.html" 1063 * 1064 * @param packageElement Package in which the file name is assumed to be. 1065 * @param name File name, to which path string is. 1066 */ 1067 protected DocPath pathString(PackageElement packageElement, DocPath name) { 1068 return pathToRoot.resolve(DocPath.forPackage(packageElement).resolve(name)); 1069 } 1070 1071 /** 1072 * Given a package, return the name to be used in HTML anchor tag. 1073 * @param packageElement the package. 1074 * @return the name to be used in HTML anchor tag. 1075 */ 1076 public String getPackageAnchorName(PackageElement packageElement) { 1077 return packageElement == null || packageElement.isUnnamed() 1078 ? SectionName.UNNAMED_PACKAGE_ANCHOR.getName() 1079 : utils.getPackageName(packageElement); 1080 } 1081 1082 /** 1083 * Return the link to the given package. 1084 * 1085 * @param packageElement the package to link to. 1086 * @param label the label for the link. 1087 * @return a content tree for the package link. 1088 */ 1089 public Content getPackageLink(PackageElement packageElement, CharSequence label) { 1090 return getPackageLink(packageElement, new StringContent(label)); 1091 } 1092 1093 public Content getPackageLink(PackageElement packageElement) { 1094 StringContent content = packageElement.isUnnamed() 1095 ? new StringContent() 1096 : new StringContent(utils.getPackageName(packageElement)); 1097 return getPackageLink(packageElement, content); 1098 } 1099 1100 /** 1101 * Return the link to the given package. 1102 * 1103 * @param packageElement the package to link to. 1104 * @param label the label for the link. 1105 * @return a content tree for the package link. 1106 */ 1107 public Content getPackageLink(PackageElement packageElement, Content label) { 1108 boolean included = packageElement != null && utils.isIncluded(packageElement); 1109 if (!included) { 1110 for (PackageElement p : configuration.packages) { 1111 if (p.equals(packageElement)) { 1112 included = true; 1113 break; 1114 } 1115 } 1116 } 1117 if (included || packageElement == null) { 1118 return getHyperLink(pathString(packageElement, DocPaths.PACKAGE_SUMMARY), 1119 label); 1120 } else { 1121 DocLink crossPkgLink = getCrossPackageLink(utils.getPackageName(packageElement)); 1122 if (crossPkgLink != null) { 1123 return getHyperLink(crossPkgLink, label); 1124 } else { 1125 return label; 1126 } 1127 } 1128 } 1129 1130 /** 1131 * Get Module link. 1132 * 1133 * @param mdle the module being documented 1134 * @param label tag for the link 1135 * @return a content for the module link 1136 */ 1137 public Content getModuleLink(ModuleElement mdle, Content label) { 1138 return getHyperLink(pathToRoot.resolve( 1139 DocPaths.moduleSummary(mdle)), label, "", ""); 1140 } 1141 1142 public Content interfaceName(TypeElement typeElement, boolean qual) { 1143 Content name = new StringContent((qual) 1144 ? typeElement.getQualifiedName() 1145 : utils.getSimpleName(typeElement)); 1146 return (utils.isInterface(typeElement)) ? HtmlTree.SPAN(HtmlStyle.interfaceName, name) : name; 1147 } 1148 1149 /** 1150 * Add the link to the content tree. 1151 * 1152 * @param typeElement program element typeElement for which the link will be added 1153 * @param label label for the link 1154 * @param htmltree the content tree to which the link will be added 1155 */ 1156 public void addSrcLink(Element typeElement, Content label, Content htmltree) { 1157 if (typeElement == null) { 1158 return; 1159 } 1160 TypeElement te = utils.getEnclosingTypeElement(typeElement); 1161 if (te == null) { 1162 // must be a typeElement since in has no containing class. 1163 te = (TypeElement) typeElement; 1164 } 1165 DocPath href = pathToRoot 1166 .resolve(DocPaths.SOURCE_OUTPUT) 1167 .resolve(DocPath.forClass(utils, te)); 1168 Content linkContent = getHyperLink(href 1169 .fragment(SourceToHTMLConverter.getAnchorName(utils, typeElement)), label, "", ""); 1170 htmltree.addContent(linkContent); 1171 } 1172 1173 /** 1174 * Return the link to the given class. 1175 * 1176 * @param linkInfo the information about the link. 1177 * 1178 * @return the link for the given class. 1179 */ 1180 public Content getLink(LinkInfoImpl linkInfo) { 1181 LinkFactoryImpl factory = new LinkFactoryImpl(this); 1182 return factory.getLink(linkInfo); 1183 } 1184 1185 /** 1186 * Return the type parameters for the given class. 1187 * 1188 * @param linkInfo the information about the link. 1189 * @return the type for the given class. 1190 */ 1191 public Content getTypeParameterLinks(LinkInfoImpl linkInfo) { 1192 LinkFactoryImpl factory = new LinkFactoryImpl(this); 1193 return factory.getTypeParameterLinks(linkInfo, false); 1194 } 1195 1196 /************************************************************* 1197 * Return a class cross link to external class documentation. 1198 * The name must be fully qualified to determine which package 1199 * the class is in. The -link option does not allow users to 1200 * link to external classes in the "default" package. 1201 * 1202 * @param qualifiedClassName the qualified name of the external class. 1203 * @param refMemName the name of the member being referenced. This should 1204 * be null or empty string if no member is being referenced. 1205 * @param label the label for the external link. 1206 * @param strong true if the link should be strong. 1207 * @param style the style of the link. 1208 * @param code true if the label should be code font. 1209 */ 1210 public Content getCrossClassLink(String qualifiedClassName, String refMemName, 1211 Content label, boolean strong, String style, 1212 boolean code) { 1213 String className = ""; 1214 String packageName = qualifiedClassName == null ? "" : qualifiedClassName; 1215 int periodIndex; 1216 while ((periodIndex = packageName.lastIndexOf('.')) != -1) { 1217 className = packageName.substring(periodIndex + 1, packageName.length()) + 1218 (className.length() > 0 ? "." + className : ""); 1219 Content defaultLabel = new StringContent(className); 1220 if (code) 1221 defaultLabel = HtmlTree.CODE(defaultLabel); 1222 packageName = packageName.substring(0, periodIndex); 1223 if (getCrossPackageLink(packageName) != null) { 1224 /* 1225 The package exists in external documentation, so link to the external 1226 class (assuming that it exists). This is definitely a limitation of 1227 the -link option. There are ways to determine if an external package 1228 exists, but no way to determine if the external class exists. We just 1229 have to assume that it does. 1230 */ 1231 DocLink link = configuration.extern.getExternalLink(packageName, pathToRoot, 1232 className + ".html", refMemName); 1233 return getHyperLink(link, 1234 (label == null) || label.isEmpty() ? defaultLabel : label, 1235 strong, style, 1236 configuration.getText("doclet.Href_Class_Or_Interface_Title", packageName), 1237 ""); 1238 } 1239 } 1240 return null; 1241 } 1242 1243 public boolean isClassLinkable(TypeElement typeElement) { 1244 if (utils.isIncluded(typeElement)) { 1245 return configuration.isGeneratedDoc(typeElement); 1246 } 1247 return configuration.extern.isExternal(typeElement); 1248 } 1249 1250 public DocLink getCrossPackageLink(String pkgName) { 1251 return configuration.extern.getExternalLink(pkgName, pathToRoot, 1252 DocPaths.PACKAGE_SUMMARY.getPath()); 1253 } 1254 1255 /** 1256 * Get the class link. 1257 * 1258 * @param context the id of the context where the link will be added 1259 * @param element to link to 1260 * @return a content tree for the link 1261 */ 1262 public Content getQualifiedClassLink(LinkInfoImpl.Kind context, Element element) { 1263 LinkInfoImpl linkInfoImpl = new LinkInfoImpl(configuration, context, (TypeElement)element); 1264 return getLink(linkInfoImpl.label(utils.getFullyQualifiedName(element))); 1265 } 1266 1267 /** 1268 * Add the class link. 1269 * 1270 * @param context the id of the context where the link will be added 1271 * @param typeElement to link to 1272 * @param contentTree the content tree to which the link will be added 1273 */ 1274 public void addPreQualifiedClassLink(LinkInfoImpl.Kind context, TypeElement typeElement, Content contentTree) { 1275 addPreQualifiedClassLink(context, typeElement, false, contentTree); 1276 } 1277 1278 /** 1279 * Retrieve the class link with the package portion of the label in 1280 * plain text. If the qualifier is excluded, it will not be included in the 1281 * link label. 1282 * 1283 * @param typeElement the class to link to. 1284 * @param isStrong true if the link should be strong. 1285 * @return the link with the package portion of the label in plain text. 1286 */ 1287 public Content getPreQualifiedClassLink(LinkInfoImpl.Kind context, 1288 TypeElement typeElement, boolean isStrong) { 1289 ContentBuilder classlink = new ContentBuilder(); 1290 PackageElement pkg = utils.containingPackage(typeElement); 1291 if (pkg != null && ! configuration.shouldExcludeQualifier(pkg.getSimpleName().toString())) { 1292 classlink.addContent(getEnclosingPackageName(typeElement)); 1293 } 1294 classlink.addContent(getLink(new LinkInfoImpl(configuration, 1295 context, typeElement).label(utils.getSimpleName(typeElement)).strong(isStrong))); 1296 return classlink; 1297 } 1298 1299 /** 1300 * Add the class link with the package portion of the label in 1301 * plain text. If the qualifier is excluded, it will not be included in the 1302 * link label. 1303 * 1304 * @param context the id of the context where the link will be added 1305 * @param typeElement the class to link to 1306 * @param isStrong true if the link should be strong 1307 * @param contentTree the content tree to which the link with be added 1308 */ 1309 public void addPreQualifiedClassLink(LinkInfoImpl.Kind context, 1310 TypeElement typeElement, boolean isStrong, Content contentTree) { 1311 PackageElement pkg = utils.containingPackage(typeElement); 1312 if(pkg != null && ! configuration.shouldExcludeQualifier(pkg.getSimpleName().toString())) { 1313 contentTree.addContent(getEnclosingPackageName(typeElement)); 1314 } 1315 LinkInfoImpl linkinfo = new LinkInfoImpl(configuration, context, typeElement) 1316 .label(utils.getSimpleName(typeElement)) 1317 .strong(isStrong); 1318 Content link = getLink(linkinfo); 1319 contentTree.addContent(link); 1320 } 1321 1322 /** 1323 * Add the class link, with only class name as the strong link and prefixing 1324 * plain package name. 1325 * 1326 * @param context the id of the context where the link will be added 1327 * @param typeElement the class to link to 1328 * @param contentTree the content tree to which the link with be added 1329 */ 1330 public void addPreQualifiedStrongClassLink(LinkInfoImpl.Kind context, TypeElement typeElement, Content contentTree) { 1331 addPreQualifiedClassLink(context, typeElement, true, contentTree); 1332 } 1333 1334 /** 1335 * Get the link for the given member. 1336 * 1337 * @param context the id of the context where the link will be added 1338 * @param element the member being linked to 1339 * @param label the label for the link 1340 * @return a content tree for the element link 1341 */ 1342 public Content getDocLink(LinkInfoImpl.Kind context, Element element, CharSequence label) { 1343 return getDocLink(context, utils.getEnclosingTypeElement(element), element, 1344 new StringContent(label)); 1345 } 1346 1347 /** 1348 * Return the link for the given member. 1349 * 1350 * @param context the id of the context where the link will be printed. 1351 * @param element the member being linked to. 1352 * @param label the label for the link. 1353 * @param strong true if the link should be strong. 1354 * @return the link for the given member. 1355 */ 1356 public Content getDocLink(LinkInfoImpl.Kind context, Element element, CharSequence label, 1357 boolean strong) { 1358 return getDocLink(context, utils.getEnclosingTypeElement(element), element, label, strong); 1359 } 1360 1361 /** 1362 * Return the link for the given member. 1363 * 1364 * @param context the id of the context where the link will be printed. 1365 * @param typeElement the typeElement that we should link to. This is not 1366 necessarily equal to element.containingClass(). We may be 1367 inheriting comments. 1368 * @param element the member being linked to. 1369 * @param label the label for the link. 1370 * @param strong true if the link should be strong. 1371 * @return the link for the given member. 1372 */ 1373 public Content getDocLink(LinkInfoImpl.Kind context, TypeElement typeElement, Element element, 1374 CharSequence label, boolean strong) { 1375 return getDocLink(context, typeElement, element, label, strong, false); 1376 } 1377 1378 public Content getDocLink(LinkInfoImpl.Kind context, TypeElement typeElement, Element element, 1379 Content label, boolean strong) { 1380 return getDocLink(context, typeElement, element, label, strong, false); 1381 } 1382 1383 /** 1384 * Return the link for the given member. 1385 * 1386 * @param context the id of the context where the link will be printed. 1387 * @param typeElement the typeElement that we should link to. This is not 1388 necessarily equal to element.containingClass(). We may be 1389 inheriting comments. 1390 * @param element the member being linked to. 1391 * @param label the label for the link. 1392 * @param strong true if the link should be strong. 1393 * @param isProperty true if the element parameter is a JavaFX property. 1394 * @return the link for the given member. 1395 */ 1396 public Content getDocLink(LinkInfoImpl.Kind context, TypeElement typeElement, Element element, 1397 CharSequence label, boolean strong, boolean isProperty) { 1398 return getDocLink(context, typeElement, element, new StringContent(check(label)), strong, isProperty); 1399 } 1400 1401 CharSequence check(CharSequence s) { 1402 Matcher m = IMPROPER_HTML_CHARS.matcher(s); 1403 if (m.matches()) { 1404 throw new IllegalArgumentException(s.toString()); 1405 } 1406 return s; 1407 } 1408 1409 public Content getDocLink(LinkInfoImpl.Kind context, TypeElement typeElement, Element element, 1410 Content label, boolean strong, boolean isProperty) { 1411 if (! (utils.isIncluded(element) || utils.isLinkable(typeElement))) { 1412 return label; 1413 } else if (utils.isExecutableElement(element)) { 1414 ExecutableElement ee = (ExecutableElement)element; 1415 return getLink(new LinkInfoImpl(configuration, context, typeElement) 1416 .label(label) 1417 .where(getName(getAnchor(ee, isProperty))) 1418 .strong(strong)); 1419 } else if (utils.isVariableElement(element) || utils.isTypeElement(element)) { 1420 return getLink(new LinkInfoImpl(configuration, context, typeElement) 1421 .label(label) 1422 .where(getName(element.getSimpleName().toString())) 1423 .strong(strong)); 1424 } else { 1425 return label; 1426 } 1427 } 1428 1429 /** 1430 * Return the link for the given member. 1431 * 1432 * @param context the id of the context where the link will be added 1433 * @param typeElement the typeElement that we should link to. This is not 1434 necessarily equal to element.containingClass(). We may be 1435 inheriting comments 1436 * @param element the member being linked to 1437 * @param label the label for the link 1438 * @return the link for the given member 1439 */ 1440 public Content getDocLink(LinkInfoImpl.Kind context, TypeElement typeElement, Element element, 1441 Content label) { 1442 if (! (utils.isIncluded(element) || utils.isLinkable(typeElement))) { 1443 return label; 1444 } else if (utils.isExecutableElement(element)) { 1445 ExecutableElement emd = (ExecutableElement) element; 1446 return getLink(new LinkInfoImpl(configuration, context, typeElement) 1447 .label(label) 1448 .where(getName(getAnchor(emd)))); 1449 } else if (utils.isVariableElement(element) || utils.isTypeElement(element)) { 1450 return getLink(new LinkInfoImpl(configuration, context, typeElement) 1451 .label(label).where(getName(element.getSimpleName().toString()))); 1452 } else { 1453 return label; 1454 } 1455 } 1456 1457 public String getAnchor(ExecutableElement executableElement) { 1458 return getAnchor(executableElement, false); 1459 } 1460 1461 public String getAnchor(ExecutableElement executableElement, boolean isProperty) { 1462 if (isProperty) { 1463 return executableElement.getSimpleName().toString(); 1464 } 1465 String signature = utils.signature(executableElement); 1466 StringBuilder signatureParsed = new StringBuilder(); 1467 int counter = 0; 1468 for (int i = 0; i < signature.length(); i++) { 1469 char c = signature.charAt(i); 1470 if (c == '<') { 1471 counter++; 1472 } else if (c == '>') { 1473 counter--; 1474 } else if (counter == 0) { 1475 signatureParsed.append(c); 1476 } 1477 } 1478 return utils.getSimpleName(executableElement) + signatureParsed.toString(); 1479 } 1480 1481 public Content seeTagToContent(Element element, DocTree see) { 1482 1483 Kind kind = see.getKind(); 1484 if (!(kind == LINK || kind == SEE || kind == LINK_PLAIN)) { 1485 return new ContentBuilder(); 1486 } 1487 1488 CommentHelper ch = utils.getCommentHelper(element); 1489 String tagName = ch.getTagName(see); 1490 String seetext = replaceDocRootDir(utils.normalizeNewlines(ch.getText(see)).toString()); 1491 // Check if @see is an href or "string" 1492 if (seetext.startsWith("<") || seetext.startsWith("\"")) { 1493 return new RawHtml(seetext); 1494 } 1495 boolean isLinkPlain = kind == LINK_PLAIN; 1496 Content label = plainOrCode(isLinkPlain, new RawHtml(ch.getLabel(configuration, see))); 1497 1498 //The text from the @see tag. We will output this text when a label is not specified. 1499 Content text = plainOrCode(kind == LINK_PLAIN, new RawHtml(seetext)); 1500 1501 TypeElement refClass = ch.getReferencedClass(configuration, see); 1502 String refClassName = ch.getReferencedClassName(configuration, see); 1503 Element refMem = ch.getReferencedMember(configuration, see); 1504 String refMemName = ch.getReferencedMemberName(see); 1505 1506 if (refMemName == null && refMem != null) { 1507 refMemName = refMem.toString(); 1508 } 1509 if (refClass == null) { 1510 //@see is not referencing an included class 1511 PackageElement refPackage = ch.getReferencedPackage(configuration, see); 1512 if (refPackage != null && utils.isIncluded(refPackage)) { 1513 //@see is referencing an included package 1514 if (label.isEmpty()) 1515 label = plainOrCode(isLinkPlain, 1516 new StringContent(refPackage.getQualifiedName())); 1517 return getPackageLink(refPackage, label); 1518 } else { 1519 // @see is not referencing an included class or package. Check for cross links. 1520 Content classCrossLink; 1521 DocLink packageCrossLink = getCrossPackageLink(refClassName); 1522 if (packageCrossLink != null) { 1523 // Package cross link found 1524 return getHyperLink(packageCrossLink, 1525 (label.isEmpty() ? text : label)); 1526 } else if ((classCrossLink = getCrossClassLink(refClassName, 1527 refMemName, label, false, "", !isLinkPlain)) != null) { 1528 // Class cross link found (possibly to a member in the class) 1529 return classCrossLink; 1530 } else { 1531 // No cross link found so print warning 1532 messages.warning(ch.getDocTreePath(see), 1533 "doclet.see.class_or_package_not_found", 1534 "@" + tagName, 1535 seetext); 1536 return (label.isEmpty() ? text: label); 1537 } 1538 } 1539 } else if (refMemName == null) { 1540 // Must be a class reference since refClass is not null and refMemName is null. 1541 if (label.isEmpty()) { 1542 /* 1543 * it seems to me this is the right thing to do, but it causes comparator failures. 1544 */ 1545 if (!configuration.backwardCompatibility) { 1546 StringContent content = utils.isEnclosingPackageIncluded(refClass) 1547 ? new StringContent(utils.getSimpleName(refClass)) 1548 : new StringContent(utils.getFullyQualifiedName(refClass)); 1549 label = plainOrCode(isLinkPlain, content); 1550 } else { 1551 label = plainOrCode(isLinkPlain, 1552 new StringContent(utils.getSimpleName(refClass))); 1553 } 1554 1555 } 1556 return getLink(new LinkInfoImpl(configuration, LinkInfoImpl.Kind.DEFAULT, refClass) 1557 .label(label)); 1558 } else if (refMem == null) { 1559 // Must be a member reference since refClass is not null and refMemName is not null. 1560 // However, refMem is null, so this referenced member does not exist. 1561 return (label.isEmpty() ? text: label); 1562 } else { 1563 // Must be a member reference since refClass is not null and refMemName is not null. 1564 // refMem is not null, so this @see tag must be referencing a valid member. 1565 TypeElement containing = utils.getEnclosingTypeElement(refMem); 1566 if (ch.getText(see).trim().startsWith("#") && 1567 ! (utils.isPublic(containing) || utils.isLinkable(containing))) { 1568 // Since the link is relative and the holder is not even being 1569 // documented, this must be an inherited link. Redirect it. 1570 // The current class either overrides the referenced member or 1571 // inherits it automatically. 1572 if (this instanceof ClassWriterImpl) { 1573 containing = ((ClassWriterImpl) this).getTypeElement(); 1574 } else if (!utils.isPublic(containing)) { 1575 messages.warning( 1576 ch.getDocTreePath(see), "doclet.see.class_or_package_not_accessible", 1577 tagName, utils.getFullyQualifiedName(containing)); 1578 } else { 1579 messages.warning( 1580 ch.getDocTreePath(see), "doclet.see.class_or_package_not_found", 1581 tagName, seetext); 1582 } 1583 } 1584 if (configuration.currentTypeElement != containing) { 1585 refMemName = (utils.isConstructor(refMem)) 1586 ? refMemName 1587 : utils.getSimpleName(containing) + "." + refMemName; 1588 } 1589 if (utils.isExecutableElement(refMem)) { 1590 if (refMemName.indexOf('(') < 0) { 1591 refMemName += utils.makeSignature((ExecutableElement)refMem, true); 1592 } 1593 } 1594 1595 text = plainOrCode(kind == LINK_PLAIN, new StringContent(refMemName)); 1596 1597 return getDocLink(LinkInfoImpl.Kind.SEE_TAG, containing, 1598 refMem, (label.isEmpty() ? text: label), false); 1599 } 1600 } 1601 1602 private Content plainOrCode(boolean plain, Content body) { 1603 return (plain || body.isEmpty()) ? body : HtmlTree.CODE(body); 1604 } 1605 1606 /** 1607 * Add the inline comment. 1608 * 1609 * @param element the Element for which the inline comment will be added 1610 * @param tag the inline tag to be added 1611 * @param htmltree the content tree to which the comment will be added 1612 */ 1613 public void addInlineComment(Element element, DocTree tag, Content htmltree) { 1614 CommentHelper ch = utils.getCommentHelper(element); 1615 List<? extends DocTree> description = ch.getDescription(configuration, tag); 1616 addCommentTags(element, tag, description, false, false, htmltree); 1617 } 1618 1619 /** 1620 * Add the inline deprecated comment. 1621 * 1622 * @param e the Element for which the inline deprecated comment will be added 1623 * @param tag the inline tag to be added 1624 * @param htmltree the content tree to which the comment will be added 1625 */ 1626 public void addInlineDeprecatedComment(Element e, DocTree tag, Content htmltree) { 1627 CommentHelper ch = utils.getCommentHelper(e); 1628 addCommentTags(e, ch.getBody(configuration, tag), true, false, htmltree); 1629 } 1630 1631 /** 1632 * Adds the summary content. 1633 * 1634 * @param element the Element for which the summary will be generated 1635 * @param htmltree the documentation tree to which the summary will be added 1636 */ 1637 public void addSummaryComment(Element element, Content htmltree) { 1638 addSummaryComment(element, utils.getFirstSentenceTrees(element), htmltree); 1639 } 1640 1641 /** 1642 * Adds the summary content. 1643 * 1644 * @param element the Element for which the summary will be generated 1645 * @param firstSentenceTags the first sentence tags for the doc 1646 * @param htmltree the documentation tree to which the summary will be added 1647 */ 1648 public void addSummaryComment(Element element, List<? extends DocTree> firstSentenceTags, Content htmltree) { 1649 addCommentTags(element, firstSentenceTags, false, true, htmltree); 1650 } 1651 1652 public void addSummaryDeprecatedComment(Element element, DocTree tag, Content htmltree) { 1653 CommentHelper ch = utils.getCommentHelper(element); 1654 List<? extends DocTree> body = ch.getBody(configuration, tag); 1655 addCommentTags(element, ch.getFirstSentenceTrees(configuration, body), true, true, htmltree); 1656 } 1657 1658 /** 1659 * Adds the inline comment. 1660 * 1661 * @param element the Element for which the inline comments will be generated 1662 * @param htmltree the documentation tree to which the inline comments will be added 1663 */ 1664 public void addInlineComment(Element element, Content htmltree) { 1665 addCommentTags(element, utils.getFullBody(element), false, false, htmltree); 1666 } 1667 1668 /** 1669 * Adds the comment tags. 1670 * 1671 * @param element the Element for which the comment tags will be generated 1672 * @param tags the first sentence tags for the doc 1673 * @param depr true if it is deprecated 1674 * @param first true if the first sentence tags should be added 1675 * @param htmltree the documentation tree to which the comment tags will be added 1676 */ 1677 private void addCommentTags(Element element, List<? extends DocTree> tags, boolean depr, 1678 boolean first, Content htmltree) { 1679 addCommentTags(element, null, tags, depr, first, htmltree); 1680 } 1681 1682 /** 1683 * Adds the comment tags. 1684 * 1685 * @param element for which the comment tags will be generated 1686 * @param holderTag the block tag context for the inline tags 1687 * @param tags the first sentence tags for the doc 1688 * @param depr true if it is deprecated 1689 * @param first true if the first sentence tags should be added 1690 * @param htmltree the documentation tree to which the comment tags will be added 1691 */ 1692 private void addCommentTags(Element element, DocTree holderTag, List<? extends DocTree> tags, boolean depr, 1693 boolean first, Content htmltree) { 1694 if(configuration.nocomment){ 1695 return; 1696 } 1697 Content div; 1698 Content result = commentTagsToContent(null, element, tags, first); 1699 if (depr) { 1700 Content italic = HtmlTree.SPAN(HtmlStyle.deprecationComment, result); 1701 div = HtmlTree.DIV(HtmlStyle.block, italic); 1702 htmltree.addContent(div); 1703 } 1704 else { 1705 div = HtmlTree.DIV(HtmlStyle.block, result); 1706 htmltree.addContent(div); 1707 } 1708 if (tags.isEmpty()) { 1709 htmltree.addContent(Contents.SPACE); 1710 } 1711 } 1712 1713 boolean ignoreNonInlineTag(DocTree dtree) { 1714 Name name = null; 1715 if (dtree.getKind() == Kind.START_ELEMENT) { 1716 StartElementTree setree = (StartElementTree)dtree; 1717 name = setree.getName(); 1718 } else if (dtree.getKind() == Kind.END_ELEMENT) { 1719 EndElementTree eetree = (EndElementTree)dtree; 1720 name = eetree.getName(); 1721 } 1722 1723 if (name != null) { 1724 com.sun.tools.doclint.HtmlTag htmlTag = com.sun.tools.doclint.HtmlTag.get(name); 1725 if (htmlTag != null && 1726 htmlTag.blockType != com.sun.tools.doclint.HtmlTag.BlockType.INLINE) { 1727 return true; 1728 } 1729 } 1730 return false; 1731 } 1732 1733 boolean isAllWhiteSpace(String body) { 1734 for (int i = 0 ; i < body.length(); i++) { 1735 if (!Character.isWhitespace(body.charAt(i))) 1736 return false; 1737 } 1738 return true; 1739 } 1740 1741 /** 1742 * Converts inline tags and text to text strings, expanding the 1743 * inline tags along the way. Called wherever text can contain 1744 * an inline tag, such as in comments or in free-form text arguments 1745 * to non-inline tags. 1746 * 1747 * @param holderTag specific tag where comment resides 1748 * @param element specific element where comment resides 1749 * @param tags array of text tags and inline tags (often alternating) 1750 present in the text of interest for this element 1751 * @param isFirstSentence true if text is first sentence 1752 * @return a Content object 1753 */ 1754 public Content commentTagsToContent(DocTree holderTag, Element element, 1755 List<? extends DocTree> tags, boolean isFirstSentence) { 1756 1757 final Content result = new ContentBuilder() { 1758 @Override 1759 public void addContent(CharSequence text) { 1760 super.addContent(utils.normalizeNewlines(text)); 1761 } 1762 }; 1763 CommentHelper ch = utils.getCommentHelper(element); 1764 // Array of all possible inline tags for this javadoc run 1765 configuration.tagletManager.checkTags(utils, element, tags, true); 1766 for (ListIterator<? extends DocTree> iterator = tags.listIterator(); iterator.hasNext();) { 1767 DocTree tag = iterator.next(); 1768 // zap block tags 1769 if (isFirstSentence && ignoreNonInlineTag(tag)) 1770 continue; 1771 1772 if (isFirstSentence && iterator.nextIndex() == tags.size() && 1773 (tag.getKind() == TEXT && isAllWhiteSpace(ch.getText(tag)))) 1774 continue; 1775 1776 boolean allDone = new SimpleDocTreeVisitor<Boolean, Content>() { 1777 // notify the next DocTree handler to take necessary action 1778 boolean commentRemoved = false; 1779 1780 private boolean isLast(DocTree node) { 1781 return node.equals(tags.get(tags.size() - 1)); 1782 } 1783 1784 private boolean isFirst(DocTree node) { 1785 return node.equals(tags.get(0)); 1786 } 1787 1788 private boolean inAnAtag() { 1789 if (utils.isStartElement(tag)) { 1790 StartElementTree st = (StartElementTree)tag; 1791 Name name = st.getName(); 1792 if (name != null) { 1793 com.sun.tools.doclint.HtmlTag htag = 1794 com.sun.tools.doclint.HtmlTag.get(name); 1795 return htag != null && htag.equals(com.sun.tools.doclint.HtmlTag.A); 1796 } 1797 } 1798 return false; 1799 } 1800 1801 @Override 1802 public Boolean visitAttribute(AttributeTree node, Content c) { 1803 StringBuilder sb = new StringBuilder(SPACER).append(node.getName()); 1804 if (node.getValueKind() == ValueKind.EMPTY) { 1805 result.addContent(sb); 1806 return false; 1807 } 1808 sb.append("="); 1809 String quote; 1810 switch (node.getValueKind()) { 1811 case DOUBLE: 1812 quote = "\""; 1813 break; 1814 case SINGLE: 1815 quote = "\'"; 1816 break; 1817 default: 1818 quote = ""; 1819 break; 1820 } 1821 sb.append(quote); 1822 result.addContent(sb); 1823 Content docRootContent = new ContentBuilder(); 1824 1825 for (DocTree dt : node.getValue()) { 1826 if (utils.isText(dt) && inAnAtag()) { 1827 String text = ((TextTree) dt).getBody(); 1828 if (text.startsWith("/..") && !configuration.docrootparent.isEmpty()) { 1829 result.addContent(configuration.docrootparent); 1830 docRootContent = new ContentBuilder(); 1831 result.addContent(textCleanup(text.substring(3), isLast(node))); 1832 } else { 1833 if (!docRootContent.isEmpty()) { 1834 docRootContent = copyDocRootContent(docRootContent); 1835 } else { 1836 text = redirectRelativeLinks(element, (TextTree) dt); 1837 } 1838 result.addContent(textCleanup(text, isLast(node))); 1839 } 1840 } else { 1841 docRootContent = copyDocRootContent(docRootContent); 1842 dt.accept(this, docRootContent); 1843 } 1844 } 1845 copyDocRootContent(docRootContent); 1846 result.addContent(quote); 1847 return false; 1848 } 1849 1850 @Override 1851 public Boolean visitComment(CommentTree node, Content c) { 1852 if (isFirstSentence && isFirst(node)) { 1853 commentRemoved = true; 1854 return this.visit(iterator.next(), c); 1855 } 1856 result.addContent(new RawHtml(node.getBody())); 1857 return false; 1858 } 1859 1860 private Content copyDocRootContent(Content content) { 1861 if (!content.isEmpty()) { 1862 result.addContent(content); 1863 return new ContentBuilder(); 1864 } 1865 return content; 1866 } 1867 1868 @Override 1869 public Boolean visitDocRoot(DocRootTree node, Content c) { 1870 Content docRootContent = TagletWriter.getInlineTagOutput(element, 1871 configuration.tagletManager, 1872 holderTag, 1873 node, 1874 getTagletWriterInstance(isFirstSentence)); 1875 if (c != null) { 1876 c.addContent(docRootContent); 1877 } else { 1878 result.addContent(docRootContent); 1879 } 1880 return false; 1881 } 1882 1883 @Override 1884 public Boolean visitEndElement(EndElementTree node, Content c) { 1885 RawHtml rawHtml = new RawHtml("</" + node.getName() + ">"); 1886 result.addContent(rawHtml); 1887 return false; 1888 } 1889 1890 @Override 1891 public Boolean visitEntity(EntityTree node, Content c) { 1892 result.addContent(new RawHtml(node.toString())); 1893 return false; 1894 } 1895 1896 @Override 1897 public Boolean visitErroneous(ErroneousTree node, Content c) { 1898 messages.warning(ch.getDocTreePath(node), 1899 "doclet.tag.invalid_usage", node); 1900 result.addContent(new RawHtml(node.toString())); 1901 return false; 1902 } 1903 1904 @Override 1905 public Boolean visitInheritDoc(InheritDocTree node, Content c) { 1906 Content output = TagletWriter.getInlineTagOutput(element, 1907 configuration.tagletManager, holderTag, 1908 tag, getTagletWriterInstance(isFirstSentence)); 1909 result.addContent(output); 1910 // if we obtained the first sentence successfully, nothing more to do 1911 return (isFirstSentence && !output.isEmpty()); 1912 } 1913 1914 @Override 1915 public Boolean visitIndex(IndexTree node, Content p) { 1916 Content output = TagletWriter.getInlineTagOutput(element, 1917 configuration.tagletManager, holderTag, tag, 1918 getTagletWriterInstance(isFirstSentence)); 1919 if (output != null) { 1920 result.addContent(output); 1921 } 1922 return false; 1923 } 1924 1925 @Override 1926 public Boolean visitLink(LinkTree node, Content c) { 1927 // we need to pass the DocTreeImpl here, so ignore node 1928 result.addContent(seeTagToContent(element, tag)); 1929 return false; 1930 } 1931 1932 @Override 1933 public Boolean visitLiteral(LiteralTree node, Content c) { 1934 String s = node.getBody().toString(); 1935 Content content = new StringContent(utils.normalizeNewlines(s)); 1936 if (node.getKind() == CODE) 1937 content = HtmlTree.CODE(content); 1938 result.addContent(content); 1939 return false; 1940 } 1941 1942 @Override 1943 public Boolean visitSee(SeeTree node, Content c) { 1944 // we need to pass the DocTreeImpl here, so ignore node 1945 result.addContent(seeTagToContent(element, tag)); 1946 return false; 1947 } 1948 1949 @Override 1950 public Boolean visitStartElement(StartElementTree node, Content c) { 1951 String text = "<" + node.getName(); 1952 RawHtml rawHtml = new RawHtml(utils.normalizeNewlines(text)); 1953 result.addContent(rawHtml); 1954 1955 for (DocTree dt : node.getAttributes()) { 1956 dt.accept(this, null); 1957 } 1958 result.addContent(new RawHtml(node.isSelfClosing() ? "/>" : ">")); 1959 return false; 1960 } 1961 1962 private CharSequence textCleanup(String text, boolean isLast) { 1963 return textCleanup(text, isLast, false); 1964 } 1965 1966 private CharSequence textCleanup(String text, boolean isLast, boolean trimLeader) { 1967 if (trimLeader) { 1968 text = removeLeadingWhitespace(text); 1969 } 1970 if (isFirstSentence && isLast) { 1971 text = removeTrailingWhitespace(text); 1972 } 1973 text = utils.replaceTabs(text); 1974 return utils.normalizeNewlines(text); 1975 } 1976 1977 @Override 1978 public Boolean visitText(TextTree node, Content c) { 1979 String text = node.getBody(); 1980 result.addContent(new RawHtml(textCleanup(text, isLast(node), commentRemoved))); 1981 commentRemoved = false; 1982 return false; 1983 } 1984 1985 @Override 1986 protected Boolean defaultAction(DocTree node, Content c) { 1987 Content output = TagletWriter.getInlineTagOutput(element, 1988 configuration.tagletManager, holderTag, tag, 1989 getTagletWriterInstance(isFirstSentence)); 1990 if (output != null) { 1991 result.addContent(output); 1992 } 1993 return false; 1994 } 1995 1996 }.visit(tag, null); 1997 if (allDone) 1998 break; 1999 } 2000 return result; 2001 } 2002 2003 private String removeTrailingWhitespace(String text) { 2004 char[] buf = text.toCharArray(); 2005 for (int i = buf.length - 1; i > 0 ; i--) { 2006 if (!Character.isWhitespace(buf[i])) 2007 return text.substring(0, i + 1); 2008 } 2009 return text; 2010 } 2011 2012 private String removeLeadingWhitespace(String text) { 2013 char[] buf = text.toCharArray(); 2014 for (int i = 0; i < buf.length; i++) { 2015 if (!Character.isWhitespace(buf[i])) { 2016 return text.substring(i); 2017 } 2018 } 2019 return text; 2020 } 2021 2022 /** 2023 * Return true if relative links should not be redirected. 2024 * 2025 * @return Return true if a relative link should not be redirected. 2026 */ 2027 private boolean shouldNotRedirectRelativeLinks() { 2028 return this instanceof AnnotationTypeWriter || 2029 this instanceof ClassWriter || 2030 this instanceof PackageSummaryWriter; 2031 } 2032 2033 /** 2034 * Suppose a piece of documentation has a relative link. When you copy 2035 * that documentation to another place such as the index or class-use page, 2036 * that relative link will no longer work. We should redirect those links 2037 * so that they will work again. 2038 * <p> 2039 * Here is the algorithm used to fix the link: 2040 * <p> 2041 * {@literal <relative link> => docRoot + <relative path to file> + <relative link> } 2042 * <p> 2043 * For example, suppose DocletEnvironment has this link: 2044 * {@literal <a href="package-summary.html">The package Page</a> } 2045 * <p> 2046 * If this link appeared in the index, we would redirect 2047 * the link like this: 2048 * 2049 * {@literal <a href="./com/sun/javadoc/package-summary.html">The package Page</a>} 2050 * 2051 * @param element the Element object whose documentation is being written. 2052 * @param text the text being written. 2053 * 2054 * @return the text, with all the relative links redirected to work. 2055 */ 2056 private String redirectRelativeLinks(Element element, TextTree tt) { 2057 String text = tt.getBody(); 2058 if (element == null || utils.isOverviewElement(element) || shouldNotRedirectRelativeLinks()) { 2059 return text; 2060 } 2061 2062 DocPath redirectPathFromRoot = new SimpleElementVisitor9<DocPath, Void>() { 2063 @Override 2064 public DocPath visitType(TypeElement e, Void p) { 2065 return DocPath.forPackage(utils.containingPackage(e)); 2066 } 2067 2068 @Override 2069 public DocPath visitPackage(PackageElement e, Void p) { 2070 return DocPath.forPackage(e); 2071 } 2072 2073 @Override 2074 public DocPath visitVariable(VariableElement e, Void p) { 2075 return DocPath.forPackage(utils.containingPackage(e)); 2076 } 2077 2078 @Override 2079 public DocPath visitExecutable(ExecutableElement e, Void p) { 2080 return DocPath.forPackage(utils.containingPackage(e)); 2081 } 2082 2083 @Override 2084 protected DocPath defaultAction(Element e, Void p) { 2085 return null; 2086 } 2087 }.visit(element); 2088 if (redirectPathFromRoot == null) { 2089 return text; 2090 } 2091 String lower = Utils.toLowerCase(text); 2092 if (!(lower.startsWith("mailto:") 2093 || lower.startsWith("http:") 2094 || lower.startsWith("https:") 2095 || lower.startsWith("file:"))) { 2096 text = "{@" + (new DocRootTaglet()).getName() + "}/" 2097 + redirectPathFromRoot.resolve(text).getPath(); 2098 text = replaceDocRootDir(text); 2099 } 2100 return text; 2101 } 2102 2103 static final Set<String> blockTags = new HashSet<>(); 2104 static { 2105 for (HtmlTag t: HtmlTag.values()) { 2106 if (t.blockType == HtmlTag.BlockType.BLOCK) 2107 blockTags.add(t.value); 2108 } 2109 } 2110 2111 /** 2112 * Add a link to the stylesheet file. 2113 * 2114 * @param head the content tree to which the files will be added 2115 */ 2116 public void addStyleSheetProperties(Content head) { 2117 String stylesheetfile = configuration.stylesheetfile; 2118 DocPath stylesheet; 2119 if (stylesheetfile.isEmpty()) { 2120 stylesheet = DocPaths.STYLESHEET; 2121 } else { 2122 DocFile file = DocFile.createFileForInput(configuration, stylesheetfile); 2123 stylesheet = DocPath.create(file.getName()); 2124 } 2125 HtmlTree link = HtmlTree.LINK("stylesheet", "text/css", 2126 pathToRoot.resolve(stylesheet).getPath(), 2127 "Style"); 2128 head.addContent(link); 2129 if (configuration.createindex) { 2130 HtmlTree jq_link = HtmlTree.LINK("stylesheet", "text/css", 2131 pathToRoot.resolve(DocPaths.JQUERY_FILES.resolve(DocPaths.JQUERY_STYLESHEET_FILE)).getPath(), 2132 "Style"); 2133 head.addContent(jq_link); 2134 } 2135 } 2136 2137 /** 2138 * Add a link to the JavaScript file. 2139 * 2140 * @param head the content tree to which the files will be added 2141 */ 2142 public void addScriptProperties(Content head) { 2143 HtmlTree javascript = HtmlTree.SCRIPT(pathToRoot.resolve(DocPaths.JAVASCRIPT).getPath()); 2144 head.addContent(javascript); 2145 if (configuration.createindex) { 2146 if (pathToRoot != null && script != null) { 2147 String ptrPath = pathToRoot.isEmpty() ? "." : pathToRoot.getPath(); 2148 script.addContent(new RawHtml("var pathtoroot = \"" + ptrPath + "/\";loadScripts(document, \'script\');")); 2149 } 2150 addJQueryFile(head, DocPaths.JSZIP_MIN); 2151 addJQueryFile(head, DocPaths.JSZIPUTILS_MIN); 2152 head.addContent(new RawHtml("<!--[if IE]>")); 2153 addJQueryFile(head, DocPaths.JSZIPUTILS_IE_MIN); 2154 head.addContent(new RawHtml("<![endif]-->")); 2155 addJQueryFile(head, DocPaths.JQUERY_JS_1_10); 2156 addJQueryFile(head, DocPaths.JQUERY_JS); 2157 } 2158 } 2159 2160 /** 2161 * Add a link to the JQuery javascript file. 2162 * 2163 * @param head the content tree to which the files will be added 2164 * @param filePath the DocPath of the file that needs to be added 2165 */ 2166 private void addJQueryFile(Content head, DocPath filePath) { 2167 HtmlTree jqyeryScriptFile = HtmlTree.SCRIPT( 2168 pathToRoot.resolve(DocPaths.JQUERY_FILES.resolve(filePath)).getPath()); 2169 head.addContent(jqyeryScriptFile); 2170 } 2171 2172 /** 2173 * According to 2174 * <cite>The Java™ Language Specification</cite>, 2175 * all the outer classes and static nested classes are core classes. 2176 */ 2177 public boolean isCoreClass(TypeElement typeElement) { 2178 return utils.getEnclosingTypeElement(typeElement) == null || utils.isStatic(typeElement); 2179 } 2180 2181 /** 2182 * Adds the annotation types for the given packageElement. 2183 * 2184 * @param packageElement the package to write annotations for. 2185 * @param htmltree the documentation tree to which the annotation info will be 2186 * added 2187 */ 2188 public void addAnnotationInfo(PackageElement packageElement, Content htmltree) { 2189 addAnnotationInfo(packageElement, packageElement.getAnnotationMirrors(), htmltree); 2190 } 2191 2192 /** 2193 * Add the annotation types of the executable receiver. 2194 * 2195 * @param method the executable to write the receiver annotations for. 2196 * @param descList list of annotation description. 2197 * @param htmltree the documentation tree to which the annotation info will be 2198 * added 2199 */ 2200 public void addReceiverAnnotationInfo(ExecutableElement method, List<AnnotationMirror> descList, 2201 Content htmltree) { 2202 addAnnotationInfo(0, method, descList, false, htmltree); 2203 } 2204 2205 /* 2206 * this is a hack to delay dealing with Annotations in the writers, the assumption 2207 * is that all necessary checks have been made to get here. 2208 */ 2209 public void addReceiverAnnotationInfo(ExecutableElement method, TypeMirror rcvrTypeMirror, 2210 List<? extends AnnotationMirror> annotationMirrors, Content htmltree) { 2211 TypeMirror rcvrType = method.getReceiverType(); 2212 List<? extends AnnotationMirror> annotationMirrors1 = rcvrType.getAnnotationMirrors(); 2213 addAnnotationInfo(0, method, annotationMirrors1, false, htmltree); 2214 } 2215 2216 /** 2217 * Adds the annotatation types for the given element. 2218 * 2219 * @param element the package to write annotations for 2220 * @param htmltree the content tree to which the annotation types will be added 2221 */ 2222 public void addAnnotationInfo(Element element, Content htmltree) { 2223 addAnnotationInfo(element, element.getAnnotationMirrors(), htmltree); 2224 } 2225 2226 /** 2227 * Add the annotatation types for the given element and parameter. 2228 * 2229 * @param indent the number of spaces to indent the parameters. 2230 * @param element the element to write annotations for. 2231 * @param param the parameter to write annotations for. 2232 * @param tree the content tree to which the annotation types will be added 2233 */ 2234 public boolean addAnnotationInfo(int indent, Element element, VariableElement param, 2235 Content tree) { 2236 return addAnnotationInfo(indent, element, param.getAnnotationMirrors(), false, tree); 2237 } 2238 2239 /** 2240 * Adds the annotatation types for the given Element. 2241 * 2242 * @param element the element to write annotations for. 2243 * @param descList the array of {@link AnnotationDesc}. 2244 * @param htmltree the documentation tree to which the annotation info will be 2245 * added 2246 */ 2247 private void addAnnotationInfo(Element element, List<? extends AnnotationMirror> descList, 2248 Content htmltree) { 2249 addAnnotationInfo(0, element, descList, true, htmltree); 2250 } 2251 2252 /** 2253 * Adds the annotation types for the given element. 2254 * 2255 * @param indent the number of extra spaces to indent the annotations. 2256 * @param element the element to write annotations for. 2257 * @param descList the array of {@link AnnotationDesc}. 2258 * @param htmltree the documentation tree to which the annotation info will be 2259 * added 2260 */ 2261 private boolean addAnnotationInfo(int indent, Element element, 2262 List<? extends AnnotationMirror> descList, boolean lineBreak, Content htmltree) { 2263 List<Content> annotations = getAnnotations(indent, descList, lineBreak); 2264 String sep = ""; 2265 if (annotations.isEmpty()) { 2266 return false; 2267 } 2268 for (Content annotation: annotations) { 2269 htmltree.addContent(sep); 2270 htmltree.addContent(annotation); 2271 if (!lineBreak) { 2272 sep = " "; 2273 } 2274 } 2275 return true; 2276 } 2277 2278 /** 2279 * Return the string representations of the annotation types for 2280 * the given doc. 2281 * 2282 * @param indent the number of extra spaces to indent the annotations. 2283 * @param descList the array of {@link AnnotationDesc}. 2284 * @param linkBreak if true, add new line between each member value. 2285 * @return an array of strings representing the annotations being 2286 * documented. 2287 */ 2288 private List<Content> getAnnotations(int indent, List<? extends AnnotationMirror> descList, boolean linkBreak) { 2289 return getAnnotations(indent, descList, linkBreak, true); 2290 } 2291 2292 private List<Content> getAnnotations(int indent, AnnotationMirror amirror, boolean linkBreak) { 2293 List<AnnotationMirror> descList = new ArrayList<>(); 2294 descList.add(amirror); 2295 return getAnnotations(indent, descList, linkBreak, true); 2296 } 2297 2298 /** 2299 * Return the string representations of the annotation types for 2300 * the given doc. 2301 * 2302 * A {@code null} {@code elementType} indicates that all the 2303 * annotations should be returned without any filtering. 2304 * 2305 * @param indent the number of extra spaces to indent the annotations. 2306 * @param descList the array of {@link AnnotationDesc}. 2307 * @param linkBreak if true, add new line between each member value. 2308 * @param isJava5DeclarationLocation 2309 * @return an array of strings representing the annotations being 2310 * documented. 2311 */ 2312 public List<Content> getAnnotations(int indent, List<? extends AnnotationMirror> descList, 2313 boolean linkBreak, boolean isJava5DeclarationLocation) { 2314 List<Content> results = new ArrayList<>(); 2315 ContentBuilder annotation; 2316 for (AnnotationMirror aDesc : descList) { 2317 TypeElement annotationElement = (TypeElement)aDesc.getAnnotationType().asElement(); 2318 // If an annotation is not documented, do not add it to the list. If 2319 // the annotation is of a repeatable type, and if it is not documented 2320 // and also if its container annotation is not documented, do not add it 2321 // to the list. If an annotation of a repeatable type is not documented 2322 // but its container is documented, it will be added to the list. 2323 if (!utils.isDocumentedAnnotation(annotationElement) && 2324 (!isAnnotationDocumented && !isContainerDocumented)) { 2325 continue; 2326 } 2327 /* TODO: check logic here to correctly handle declaration 2328 * and type annotations. 2329 if (utils.isDeclarationAnnotation(annotationElement, isJava5DeclarationLocation)) { 2330 continue; 2331 }*/ 2332 annotation = new ContentBuilder(); 2333 isAnnotationDocumented = false; 2334 LinkInfoImpl linkInfo = new LinkInfoImpl(configuration, 2335 LinkInfoImpl.Kind.ANNOTATION, annotationElement); 2336 Map<? extends ExecutableElement, ? extends AnnotationValue> pairs = aDesc.getElementValues(); 2337 // If the annotation is synthesized, do not print the container. 2338 if (utils.configuration.workArounds.isSynthesized(aDesc)) { 2339 for (ExecutableElement ee : pairs.keySet()) { 2340 AnnotationValue annotationValue = pairs.get(ee); 2341 List<AnnotationValue> annotationTypeValues = new ArrayList<>(); 2342 2343 new SimpleAnnotationValueVisitor9<Void, List<AnnotationValue>>() { 2344 @Override 2345 public Void visitArray(List<? extends AnnotationValue> vals, List<AnnotationValue> p) { 2346 p.addAll(vals); 2347 return null; 2348 } 2349 2350 @Override 2351 protected Void defaultAction(Object o, List<AnnotationValue> p) { 2352 p.add(annotationValue); 2353 return null; 2354 } 2355 }.visit(annotationValue, annotationTypeValues); 2356 2357 String sep = ""; 2358 for (AnnotationValue av : annotationTypeValues) { 2359 annotation.addContent(sep); 2360 annotation.addContent(annotationValueToContent(av)); 2361 sep = " "; 2362 } 2363 } 2364 } else if (isAnnotationArray(pairs)) { 2365 // If the container has 1 or more value defined and if the 2366 // repeatable type annotation is not documented, do not print 2367 // the container. 2368 if (pairs.size() == 1 && isAnnotationDocumented) { 2369 List<AnnotationValue> annotationTypeValues = new ArrayList<>(); 2370 for (AnnotationValue a : pairs.values()) { 2371 new SimpleAnnotationValueVisitor9<Void, List<AnnotationValue>>() { 2372 @Override 2373 public Void visitArray(List<? extends AnnotationValue> vals, List<AnnotationValue> annotationTypeValues) { 2374 for (AnnotationValue av : vals) { 2375 annotationTypeValues.add(av); 2376 } 2377 return null; 2378 } 2379 }.visit(a, annotationTypeValues); 2380 } 2381 String sep = ""; 2382 for (AnnotationValue av : annotationTypeValues) { 2383 annotation.addContent(sep); 2384 annotation.addContent(annotationValueToContent(av)); 2385 sep = " "; 2386 } 2387 } 2388 // If the container has 1 or more value defined and if the 2389 // repeatable type annotation is not documented, print the container. 2390 else { 2391 addAnnotations(annotationElement, linkInfo, annotation, pairs, 2392 indent, false); 2393 } 2394 } 2395 else { 2396 addAnnotations(annotationElement, linkInfo, annotation, pairs, 2397 indent, linkBreak); 2398 } 2399 annotation.addContent(linkBreak ? DocletConstants.NL : ""); 2400 results.add(annotation); 2401 } 2402 return results; 2403 } 2404 2405 /** 2406 * Add annotation to the annotation string. 2407 * 2408 * @param annotationDoc the annotation being documented 2409 * @param linkInfo the information about the link 2410 * @param annotation the annotation string to which the annotation will be added 2411 * @param pairs annotation type element and value pairs 2412 * @param indent the number of extra spaces to indent the annotations. 2413 * @param linkBreak if true, add new line between each member value 2414 */ 2415 private void addAnnotations(TypeElement annotationDoc, LinkInfoImpl linkInfo, 2416 ContentBuilder annotation, Map<? extends ExecutableElement,? extends AnnotationValue>map, 2417 int indent, boolean linkBreak) { 2418 linkInfo.label = new StringContent("@"); 2419 linkInfo.label.addContent(annotationDoc.getSimpleName()); 2420 annotation.addContent(getLink(linkInfo)); 2421 if (!map.isEmpty()) { 2422 annotation.addContent("("); 2423 boolean isFirst = true; 2424 Set<? extends ExecutableElement> keys = map.keySet(); 2425 boolean multipleValues = keys.size() > 1; 2426 for (ExecutableElement element : keys) { 2427 if (isFirst) { 2428 isFirst = false; 2429 } else { 2430 annotation.addContent(","); 2431 if (linkBreak) { 2432 annotation.addContent(DocletConstants.NL); 2433 int spaces = annotationDoc.getSimpleName().length() + 2; 2434 for (int k = 0; k < (spaces + indent); k++) { 2435 annotation.addContent(" "); 2436 } 2437 } 2438 } 2439 String simpleName = element.getSimpleName().toString(); 2440 if (multipleValues || !"value".equals(simpleName)) { // Omit "value=" where unnecessary 2441 annotation.addContent(getDocLink(LinkInfoImpl.Kind.ANNOTATION, 2442 element, simpleName, false)); 2443 annotation.addContent("="); 2444 } 2445 AnnotationValue annotationValue = map.get(element); 2446 List<AnnotationValue> annotationTypeValues = new ArrayList<>(); 2447 new SimpleAnnotationValueVisitor9<Void, AnnotationValue>() { 2448 @Override 2449 public Void visitArray(List<? extends AnnotationValue> vals, AnnotationValue p) { 2450 annotationTypeValues.addAll(vals); 2451 return null; 2452 } 2453 @Override 2454 protected Void defaultAction(Object o, AnnotationValue p) { 2455 annotationTypeValues.add(p); 2456 return null; 2457 } 2458 }.visit(annotationValue, annotationValue); 2459 annotation.addContent(annotationTypeValues.size() == 1 ? "" : "{"); 2460 String sep = ""; 2461 for (AnnotationValue av : annotationTypeValues) { 2462 annotation.addContent(sep); 2463 annotation.addContent(annotationValueToContent(av)); 2464 sep = ","; 2465 } 2466 annotation.addContent(annotationTypeValues.size() == 1 ? "" : "}"); 2467 isContainerDocumented = false; 2468 } 2469 annotation.addContent(")"); 2470 } 2471 } 2472 2473 /** 2474 * Check if the annotation contains an array of annotation as a value. This 2475 * check is to verify if a repeatable type annotation is present or not. 2476 * 2477 * @param pairs annotation type element and value pairs 2478 * 2479 * @return true if the annotation contains an array of annotation as a value. 2480 */ 2481 private boolean isAnnotationArray(Map<? extends ExecutableElement, ? extends AnnotationValue> pairs) { 2482 AnnotationValue annotationValue; 2483 for (ExecutableElement ee : pairs.keySet()) { 2484 annotationValue = pairs.get(ee); 2485 boolean rvalue = new SimpleAnnotationValueVisitor9<Boolean, Void>() { 2486 @Override 2487 public Boolean visitArray(List<? extends AnnotationValue> vals, Void p) { 2488 if (vals.size() > 1) { 2489 if (vals.get(0) instanceof AnnotationMirror) { 2490 isContainerDocumented = true; 2491 return new SimpleAnnotationValueVisitor9<Boolean, Void>() { 2492 @Override 2493 public Boolean visitAnnotation(AnnotationMirror a, Void p) { 2494 isContainerDocumented = true; 2495 Element asElement = a.getAnnotationType().asElement(); 2496 if (utils.isDocumentedAnnotation((TypeElement)asElement)) { 2497 isAnnotationDocumented = true; 2498 } 2499 return true; 2500 } 2501 @Override 2502 protected Boolean defaultAction(Object o, Void p) { 2503 return false; 2504 } 2505 }.visit(vals.get(0)); 2506 } 2507 } 2508 return false; 2509 } 2510 2511 @Override 2512 protected Boolean defaultAction(Object o, Void p) { 2513 return false; 2514 } 2515 }.visit(annotationValue); 2516 if (rvalue) { 2517 return true; 2518 } 2519 } 2520 return false; 2521 } 2522 2523 private Content annotationValueToContent(AnnotationValue annotationValue) { 2524 return new SimpleAnnotationValueVisitor9<Content, Void>() { 2525 2526 @Override 2527 public Content visitType(TypeMirror t, Void p) { 2528 return new SimpleTypeVisitor9<Content, Void>() { 2529 @Override 2530 public Content visitDeclared(DeclaredType t, Void p) { 2531 LinkInfoImpl linkInfo = new LinkInfoImpl(configuration, 2532 LinkInfoImpl.Kind.ANNOTATION, t); 2533 String name = utils.isIncluded(t.asElement()) 2534 ? t.asElement().getSimpleName().toString() 2535 : utils.getFullyQualifiedName(t.asElement()); 2536 linkInfo.label = new StringContent(name + utils.getDimension(t) + ".class"); 2537 return getLink(linkInfo); 2538 } 2539 @Override 2540 protected Content defaultAction(TypeMirror e, Void p) { 2541 return new StringContent(t + utils.getDimension(t) + ".class"); 2542 } 2543 }.visit(t); 2544 } 2545 @Override 2546 public Content visitAnnotation(AnnotationMirror a, Void p) { 2547 List<Content> list = getAnnotations(0, a, false); 2548 ContentBuilder buf = new ContentBuilder(); 2549 for (Content c : list) { 2550 buf.addContent(c); 2551 } 2552 return buf; 2553 } 2554 @Override 2555 public Content visitEnumConstant(VariableElement c, Void p) { 2556 return getDocLink(LinkInfoImpl.Kind.ANNOTATION, 2557 c, c.getSimpleName(), false); 2558 } 2559 @Override 2560 public Content visitArray(List<? extends AnnotationValue> vals, Void p) { 2561 ContentBuilder buf = new ContentBuilder(); 2562 String sep = ""; 2563 for (AnnotationValue av : vals) { 2564 buf.addContent(sep); 2565 buf.addContent(visit(av)); 2566 sep = " "; 2567 } 2568 return buf; 2569 } 2570 @Override 2571 protected Content defaultAction(Object o, Void p) { 2572 return new StringContent(annotationValue.toString()); 2573 } 2574 }.visit(annotationValue); 2575 } 2576 2577 /** 2578 * Return the configuration for this doclet. 2579 * 2580 * @return the configuration for this doclet. 2581 */ 2582 @Override 2583 public Configuration configuration() { 2584 return configuration; 2585 } 2586} 2587