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