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.ElementKind; 37 import javax.lang.model.element.ExecutableElement; 38 import javax.lang.model.element.ModuleElement; 39 import javax.lang.model.element.Name; 40 import javax.lang.model.element.PackageElement; 41 import javax.lang.model.element.TypeElement; 42 import javax.lang.model.element.VariableElement; 43 import javax.lang.model.type.DeclaredType; 44 import javax.lang.model.type.TypeMirror; 45 import javax.lang.model.util.SimpleAnnotationValueVisitor9; 46 import javax.lang.model.util.SimpleElementVisitor9; 47 import javax.lang.model.util.SimpleTypeVisitor9; 48 49 import com.sun.source.doctree.AttributeTree; 50 import com.sun.source.doctree.AttributeTree.ValueKind; 51 import com.sun.source.doctree.CommentTree; 52 import com.sun.source.doctree.DocRootTree; 53 import com.sun.source.doctree.DocTree; 54 import com.sun.source.doctree.DocTree.Kind; 55 import com.sun.source.doctree.EndElementTree; 56 import com.sun.source.doctree.EntityTree; 57 import com.sun.source.doctree.ErroneousTree; 58 import com.sun.source.doctree.IndexTree; 59 import com.sun.source.doctree.InheritDocTree; 60 import com.sun.source.doctree.LinkTree; 61 import com.sun.source.doctree.LiteralTree; 62 import com.sun.source.doctree.SeeTree; 63 import com.sun.source.doctree.StartElementTree; 64 import com.sun.source.doctree.SummaryTree; 65 import com.sun.source.doctree.TextTree; 66 import com.sun.source.util.SimpleDocTreeVisitor; 67 68 import jdk.javadoc.internal.doclets.formats.html.markup.Comment; 69 import jdk.javadoc.internal.doclets.formats.html.markup.ContentBuilder; 70 import jdk.javadoc.internal.doclets.formats.html.markup.DocType; 71 import jdk.javadoc.internal.doclets.formats.html.markup.HtmlAttr; 72 import jdk.javadoc.internal.doclets.formats.html.markup.HtmlConstants; 73 import jdk.javadoc.internal.doclets.formats.html.markup.HtmlDocWriter; 74 import jdk.javadoc.internal.doclets.formats.html.markup.HtmlDocument; 75 import jdk.javadoc.internal.doclets.formats.html.markup.HtmlStyle; 76 import jdk.javadoc.internal.doclets.formats.html.markup.HtmlTag; 77 import jdk.javadoc.internal.doclets.formats.html.markup.HtmlTree; 78 import jdk.javadoc.internal.doclets.formats.html.markup.HtmlVersion; 79 import jdk.javadoc.internal.doclets.formats.html.markup.RawHtml; 80 import jdk.javadoc.internal.doclets.formats.html.markup.StringContent; 81 import jdk.javadoc.internal.doclets.toolkit.AnnotationTypeWriter; 82 import jdk.javadoc.internal.doclets.toolkit.ClassWriter; 83 import jdk.javadoc.internal.doclets.toolkit.BaseConfiguration; 84 import jdk.javadoc.internal.doclets.toolkit.Content; 85 import jdk.javadoc.internal.doclets.toolkit.Messages; 86 import jdk.javadoc.internal.doclets.toolkit.PackageSummaryWriter; 87 import jdk.javadoc.internal.doclets.toolkit.Resources; 88 import jdk.javadoc.internal.doclets.toolkit.taglets.DocRootTaglet; 89 import jdk.javadoc.internal.doclets.toolkit.taglets.TagletWriter; 90 import jdk.javadoc.internal.doclets.toolkit.util.CommentHelper; 91 import jdk.javadoc.internal.doclets.toolkit.util.DocFile; 92 import jdk.javadoc.internal.doclets.toolkit.util.DocFileIOException; 93 import jdk.javadoc.internal.doclets.toolkit.util.DocLink; 94 import jdk.javadoc.internal.doclets.toolkit.util.DocPath; 95 import jdk.javadoc.internal.doclets.toolkit.util.DocPaths; 96 import jdk.javadoc.internal.doclets.toolkit.util.DocletConstants; 97 import jdk.javadoc.internal.doclets.toolkit.util.ImplementedMethods; 98 import jdk.javadoc.internal.doclets.toolkit.util.Utils; 99 100 import static com.sun.source.doctree.DocTree.Kind.*; 101 import static jdk.javadoc.internal.doclets.toolkit.util.CommentHelper.SPACER; 102 103 104 /** 105 * Class for the Html Format Code Generation specific to JavaDoc. 106 * This Class contains methods related to the Html Code Generation which 107 * are used extensively while generating the entire documentation. 108 * 109 * <p><b>This is NOT part of any supported API. 110 * If you write code that depends on this, you do so at your own risk. 111 * This code and its internal interfaces are subject to change or 112 * deletion without notice.</b> 113 * 114 * @author Atul M Dambalkar 115 * @author Robert Field 116 * @author Bhavesh Patel (Modified) 117 */ 118 public class HtmlDocletWriter extends HtmlDocWriter { 119 120 /** 121 * Relative path from the file getting generated to the destination 122 * directory. For example, if the file getting generated is 123 * "java/lang/Object.html", then the path to the root is "../..". 124 * This string can be empty if the file getting generated is in 125 * the destination directory. 126 */ 127 public final DocPath pathToRoot; 128 129 /** 130 * Platform-independent path from the current or the 131 * destination directory to the file getting generated. 132 * Used when creating the file. 133 */ 134 public final DocPath path; 135 136 /** 137 * Name of the file getting generated. If the file getting generated is 138 * "java/lang/Object.html", then the filename is "Object.html". 139 */ 140 public final DocPath filename; 141 142 /** 143 * The global configuration information for this run. 144 */ 145 public final HtmlConfiguration configuration; 146 147 protected final Utils utils; 148 149 protected final Contents contents; 150 151 protected final Messages messages; 152 153 protected final Resources resources; 154 155 /** 156 * To check whether annotation heading is printed or not. 157 */ 158 protected boolean printedAnnotationHeading = false; 159 160 /** 161 * To check whether annotation field heading is printed or not. 162 */ 163 protected boolean printedAnnotationFieldHeading = false; 164 165 /** 166 * To check whether the repeated annotations is documented or not. 167 */ 168 private boolean isAnnotationDocumented = false; 169 170 /** 171 * To check whether the container annotations is documented or not. 172 */ 173 private boolean isContainerDocumented = false; 174 175 HtmlTree fixedNavDiv = new HtmlTree(HtmlTag.DIV); 176 177 final static Pattern IMPROPER_HTML_CHARS = Pattern.compile(".*[&<>].*"); 178 179 /** 180 * Constructor to construct the HtmlStandardWriter object. 181 * 182 * @param path File to be generated. 183 */ 184 public HtmlDocletWriter(HtmlConfiguration configuration, DocPath path) { 185 super(configuration, path); 186 this.configuration = configuration; 187 this.contents = configuration.contents; 188 this.messages = configuration.messages; 189 this.resources = configuration.resources; 190 this.utils = configuration.utils; 191 this.path = path; 192 this.pathToRoot = path.parent().invert(); 193 this.filename = path.basename(); 194 } 195 196 /** 197 * Replace {@docRoot} tag used in options that accept HTML text, such 198 * as -header, -footer, -top and -bottom, and when converting a relative 199 * HREF where commentTagsToString inserts a {@docRoot} where one was 200 * missing. (Also see DocRootTaglet for {@docRoot} tags in doc 201 * comments.) 202 * <p> 203 * Replace {@docRoot} tag in htmlstr with the relative path to the 204 * destination directory from the directory where the file is being 205 * written, looping to handle all such tags in htmlstr. 206 * <p> 207 * For example, for "-d docs" and -header containing {@docRoot}, when 208 * the HTML page for source file p/C1.java is being generated, the 209 * {@docRoot} tag would be inserted into the header as "../", 210 * the relative path from docs/p/ to docs/ (the document root). 211 * <p> 212 * Note: This doc comment was written with '&#064;' representing '@' 213 * to prevent the inline tag from being interpreted. 214 */ 215 public String replaceDocRootDir(String htmlstr) { 216 // Return if no inline tags exist 217 int index = htmlstr.indexOf("{@"); 218 if (index < 0) { 219 return htmlstr; 220 } 221 Matcher docrootMatcher = docrootPattern.matcher(htmlstr); 222 if (!docrootMatcher.find()) { 223 return htmlstr; 224 } 225 StringBuilder buf = new StringBuilder(); 226 int prevEnd = 0; 227 do { 228 int match = docrootMatcher.start(); 229 // append htmlstr up to start of next {@docroot} 230 buf.append(htmlstr.substring(prevEnd, match)); 231 prevEnd = docrootMatcher.end(); 232 if (configuration.docrootparent.length() > 0 && htmlstr.startsWith("/..", prevEnd)) { 233 // Insert the absolute link if {@docRoot} is followed by "/..". 234 buf.append(configuration.docrootparent); 235 prevEnd += 3; 236 } else { 237 // Insert relative path where {@docRoot} was located 238 buf.append(pathToRoot.isEmpty() ? "." : pathToRoot.getPath()); 239 } 240 // Append slash if next character is not a slash 241 if (prevEnd < htmlstr.length() && htmlstr.charAt(prevEnd) != '/') { 242 buf.append('/'); 243 } 244 } while (docrootMatcher.find()); 245 buf.append(htmlstr.substring(prevEnd)); 246 return buf.toString(); 247 } 248 //where: 249 // Note: {@docRoot} is not case sensitive when passed in w/command line option: 250 private static final Pattern docrootPattern = 251 Pattern.compile(Pattern.quote("{@docroot}"), Pattern.CASE_INSENSITIVE); 252 253 /** 254 * Get the script to show or hide the All classes link. 255 * 256 * @param id id of the element to show or hide 257 * @return a content tree for the script 258 */ 259 public Content getAllClassesLinkScript(String id) { 260 HtmlTree script = HtmlTree.SCRIPT(); 261 String scriptCode = "<!--\n" + 262 " allClassesLink = document.getElementById(\"" + id + "\");\n" + 263 " if(window==top) {\n" + 264 " allClassesLink.style.display = \"block\";\n" + 265 " }\n" + 266 " else {\n" + 267 " allClassesLink.style.display = \"none\";\n" + 268 " }\n" + 269 " //-->\n"; 270 Content scriptContent = new RawHtml(scriptCode.replace("\n", DocletConstants.NL)); 271 script.addContent(scriptContent); 272 Content div = HtmlTree.DIV(script); 273 Content div_noscript = HtmlTree.DIV(contents.noScriptMessage); 274 Content noScript = HtmlTree.NOSCRIPT(div_noscript); 275 div.addContent(noScript); 276 return div; 277 } 278 279 /** 280 * Add method information. 281 * 282 * @param method the method to be documented 283 * @param dl the content tree to which the method information will be added 284 */ 285 private void addMethodInfo(ExecutableElement method, Content dl) { 286 TypeElement enclosing = utils.getEnclosingTypeElement(method); 287 List<? extends TypeMirror> intfacs = enclosing.getInterfaces(); 288 ExecutableElement overriddenMethod = utils.overriddenMethod(method); 289 // Check whether there is any implementation or overridden info to be 290 // printed. If no overridden or implementation info needs to be 291 // printed, do not print this section. 292 if ((!intfacs.isEmpty() 293 && new ImplementedMethods(method, this.configuration).build().isEmpty() == false) 294 || overriddenMethod != null) { 295 MethodWriterImpl.addImplementsInfo(this, method, dl); 296 if (overriddenMethod != null) { 297 MethodWriterImpl.addOverridden(this, 298 utils.overriddenType(method), 299 overriddenMethod, 300 dl); 301 } 302 } 303 } 304 305 /** 306 * Adds the tags information. 307 * 308 * @param e the Element for which the tags will be generated 309 * @param htmltree the documentation tree to which the tags will be added 310 */ 311 protected void addTagsInfo(Element e, Content htmltree) { 312 if (configuration.nocomment) { 313 return; 314 } 315 Content dl = new HtmlTree(HtmlTag.DL); 316 if (utils.isExecutableElement(e) && !utils.isConstructor(e)) { 317 addMethodInfo((ExecutableElement)e, dl); 318 } 319 Content output = new ContentBuilder(); 320 TagletWriter.genTagOutput(configuration.tagletManager, e, 321 configuration.tagletManager.getCustomTaglets(e), 322 getTagletWriterInstance(false), output); 323 dl.addContent(output); 324 htmltree.addContent(dl); 325 } 326 327 /** 328 * Check whether there are any tags for Serialization Overview 329 * section to be printed. 330 * 331 * @param field the VariableElement object to check for tags. 332 * @return true if there are tags to be printed else return false. 333 */ 334 protected boolean hasSerializationOverviewTags(VariableElement field) { 335 Content output = new ContentBuilder(); 336 TagletWriter.genTagOutput(configuration.tagletManager, field, 337 configuration.tagletManager.getCustomTaglets(field), 338 getTagletWriterInstance(false), output); 339 return !output.isEmpty(); 340 } 341 342 /** 343 * Returns a TagletWriter that knows how to write HTML. 344 * 345 * @return a TagletWriter that knows how to write HTML. 346 */ 347 public TagletWriter getTagletWriterInstance(boolean isFirstSentence) { 348 return new TagletWriterImpl(this, isFirstSentence); 349 } 350 351 /** 352 * Get Package link, with target frame. 353 * 354 * @param pkg The link will be to the "package-summary.html" page for this package 355 * @param target name of the target frame 356 * @param label tag for the link 357 * @return a content for the target package link 358 */ 359 public Content getTargetPackageLink(PackageElement pkg, String target, 360 Content label) { 361 return getHyperLink(pathString(pkg, DocPaths.PACKAGE_SUMMARY), label, "", target); 362 } 363 364 /** 365 * Get Module Package link, with target frame. 366 * 367 * @param pkg the PackageElement 368 * @param target name of the target frame 369 * @param label tag for the link 370 * @param mdle the module being documented 371 * @return a content for the target module packages link 372 */ 373 public Content getTargetModulePackageLink(PackageElement pkg, String target, 374 Content label, ModuleElement mdle) { 375 return getHyperLink(pathString(pkg, DocPaths.PACKAGE_SUMMARY), 376 label, "", target); 377 } 378 379 /** 380 * Get Module link, with target frame. 381 * 382 * @param target name of the target frame 383 * @param label tag for the link 384 * @param mdle the module being documented 385 * @return a content for the target module link 386 */ 387 public Content getTargetModuleLink(String target, Content label, ModuleElement mdle) { 388 return getHyperLink(pathToRoot.resolve( 389 DocPaths.moduleSummary(mdle)), label, "", target); 390 } 391 392 public void addClassesSummary(SortedSet<TypeElement> classes, String label, 393 String tableSummary, List<String> tableHeader, Content summaryContentTree) { 394 if (!classes.isEmpty()) { 395 Content caption = getTableCaption(new RawHtml(label)); 396 Content table = (configuration.isOutputHtml5()) 397 ? HtmlTree.TABLE(HtmlStyle.typeSummary, caption) 398 : HtmlTree.TABLE(HtmlStyle.typeSummary, tableSummary, caption); 399 table.addContent(getSummaryTableHeader(tableHeader, "col")); 400 Content tbody = new HtmlTree(HtmlTag.TBODY); 401 boolean altColor = true; 402 for (TypeElement te : classes) { 403 if (!utils.isCoreClass(te) || 404 !configuration.isGeneratedDoc(te)) { 405 continue; 406 } 407 Content classContent = getLink(new LinkInfoImpl( 408 configuration, LinkInfoImpl.Kind.PACKAGE, te)); 409 Content tdClass = HtmlTree.TH_ROW_SCOPE(HtmlStyle.colFirst, classContent); 410 HtmlTree tr = HtmlTree.TR(tdClass); 411 tr.addStyle(altColor ? HtmlStyle.altColor : HtmlStyle.rowColor); 412 altColor = !altColor; 413 HtmlTree tdClassDescription = new HtmlTree(HtmlTag.TD); 414 tdClassDescription.addStyle(HtmlStyle.colLast); 415 if (utils.isDeprecated(te)) { 416 tdClassDescription.addContent(getDeprecatedPhrase(te)); 417 List<? extends DocTree> tags = utils.getDeprecatedTrees(te); 418 if (!tags.isEmpty()) { 419 addSummaryDeprecatedComment(te, tags.get(0), tdClassDescription); 420 } 421 } else { 422 addSummaryComment(te, tdClassDescription); 423 } 424 tr.addContent(tdClassDescription); 425 tbody.addContent(tr); 426 } 427 table.addContent(tbody); 428 summaryContentTree.addContent(table); 429 } 430 } 431 432 /** 433 * Generates the HTML document tree and prints it out. 434 * 435 * @param metakeywords Array of String keywords for META tag. Each element 436 * of the array is assigned to a separate META tag. 437 * Pass in null for no array 438 * @param includeScript true if printing windowtitle script 439 * false for files that appear in the left-hand frames 440 * @param body the body htmltree to be included in the document 441 * @throws DocFileIOException if there is a problem writing the file 442 */ 443 public void printHtmlDocument(List<String> metakeywords, boolean includeScript, 444 Content body) throws DocFileIOException { 445 Content htmlDocType = configuration.isOutputHtml5() 446 ? DocType.HTML5 447 : DocType.TRANSITIONAL; 448 Content htmlComment = new Comment(configuration.getText("doclet.New_Page")); 449 Content head = new HtmlTree(HtmlTag.HEAD); 450 head.addContent(getGeneratedBy(!configuration.notimestamp)); 451 head.addContent(getTitle()); 452 Content meta = HtmlTree.META("Content-Type", CONTENT_TYPE, configuration.charset); 453 head.addContent(meta); 454 if (!configuration.notimestamp) { 455 SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd"); 456 meta = HtmlTree.META(configuration.isOutputHtml5() 457 ? "dc.created" 458 : "date", dateFormat.format(new Date())); 459 head.addContent(meta); 460 } 461 if (metakeywords != null) { 462 for (String metakeyword : metakeywords) { 463 meta = HtmlTree.META("keywords", metakeyword); 464 head.addContent(meta); 465 } 466 } 467 addStyleSheetProperties(head); 468 addScriptProperties(head); 469 Content htmlTree = HtmlTree.HTML(configuration.getLocale().getLanguage(), 470 head, body); 471 Content htmlDocument = new HtmlDocument(htmlDocType, 472 htmlComment, htmlTree); 473 write(htmlDocument); 474 } 475 476 /** 477 * Get the window title. 478 * 479 * @param title the title string to construct the complete window title 480 * @return the window title string 481 */ 482 public String getWindowTitle(String title) { 483 if (configuration.windowtitle.length() > 0) { 484 title += " (" + configuration.windowtitle + ")"; 485 } 486 return title; 487 } 488 489 /** 490 * Get user specified header and the footer. 491 * 492 * @param header if true print the user provided header else print the 493 * user provided footer. 494 */ 495 public Content getUserHeaderFooter(boolean header) { 496 String content; 497 if (header) { 498 content = replaceDocRootDir(configuration.header); 499 } else { 500 if (configuration.footer.length() != 0) { 501 content = replaceDocRootDir(configuration.footer); 502 } else { 503 content = replaceDocRootDir(configuration.header); 504 } 505 } 506 Content rawContent = new RawHtml(content); 507 return rawContent; 508 } 509 510 /** 511 * Adds the user specified top. 512 * 513 * @param htmlTree the content tree to which user specified top will be added 514 */ 515 public void addTop(Content htmlTree) { 516 Content top = new RawHtml(replaceDocRootDir(configuration.top)); 517 fixedNavDiv.addContent(top); 518 } 519 520 /** 521 * Adds the user specified bottom. 522 * 523 * @param htmlTree the content tree to which user specified bottom will be added 524 */ 525 public void addBottom(Content htmlTree) { 526 Content bottom = new RawHtml(replaceDocRootDir(configuration.bottom)); 527 Content small = HtmlTree.SMALL(bottom); 528 Content p = HtmlTree.P(HtmlStyle.legalCopy, small); 529 htmlTree.addContent(p); 530 } 531 532 /** 533 * Adds the navigation bar for the Html page at the top and and the bottom. 534 * 535 * @param header If true print navigation bar at the top of the page else 536 * @param htmlTree the HtmlTree to which the nav links will be added 537 */ 538 protected void addNavLinks(boolean header, Content htmlTree) { 539 if (!configuration.nonavbar) { 540 Content tree = (configuration.allowTag(HtmlTag.NAV)) 541 ? HtmlTree.NAV() 542 : htmlTree; 543 String allClassesId = "allclasses_"; 544 HtmlTree navDiv = new HtmlTree(HtmlTag.DIV); 545 fixedNavDiv.addStyle(HtmlStyle.fixedNav); 546 Content skipNavLinks = configuration.getContent("doclet.Skip_navigation_links"); 547 if (header) { 548 fixedNavDiv.addContent(HtmlConstants.START_OF_TOP_NAVBAR); 549 navDiv.addStyle(HtmlStyle.topNav); 550 allClassesId += "navbar_top"; 551 Content a = getMarkerAnchor(SectionName.NAVBAR_TOP); 552 //WCAG - Hyperlinks should contain text or an image with alt text - for AT tools 553 navDiv.addContent(a); 554 Content skipLinkContent = HtmlTree.DIV(HtmlStyle.skipNav, getHyperLink( 555 getDocLink(SectionName.SKIP_NAVBAR_TOP), skipNavLinks, 556 skipNavLinks.toString(), "")); 557 navDiv.addContent(skipLinkContent); 558 } else { 559 tree.addContent(HtmlConstants.START_OF_BOTTOM_NAVBAR); 560 navDiv.addStyle(HtmlStyle.bottomNav); 561 allClassesId += "navbar_bottom"; 562 Content a = getMarkerAnchor(SectionName.NAVBAR_BOTTOM); 563 navDiv.addContent(a); 564 Content skipLinkContent = HtmlTree.DIV(HtmlStyle.skipNav, getHyperLink( 565 getDocLink(SectionName.SKIP_NAVBAR_BOTTOM), skipNavLinks, 566 skipNavLinks.toString(), "")); 567 navDiv.addContent(skipLinkContent); 568 } 569 if (header) { 570 navDiv.addContent(getMarkerAnchor(SectionName.NAVBAR_TOP_FIRSTROW)); 571 } else { 572 navDiv.addContent(getMarkerAnchor(SectionName.NAVBAR_BOTTOM_FIRSTROW)); 573 } 574 HtmlTree navList = new HtmlTree(HtmlTag.UL); 575 navList.addStyle(HtmlStyle.navList); 576 navList.addAttr(HtmlAttr.TITLE, 577 configuration.getText("doclet.Navigation")); 578 if (configuration.createoverview) { 579 navList.addContent(getNavLinkContents()); 580 } 581 if (configuration.showModules) { 582 if (configuration.modules.size() == 1) { 583 navList.addContent(getNavLinkModule(configuration.modules.first())); 584 } else if (!configuration.modules.isEmpty()) { 585 navList.addContent(getNavLinkModule()); 586 } 587 } 588 if (configuration.packages.size() == 1) { 589 navList.addContent(getNavLinkPackage(configuration.packages.first())); 590 } else if (!configuration.packages.isEmpty()) { 591 navList.addContent(getNavLinkPackage()); 592 } 593 navList.addContent(getNavLinkClass()); 594 if(configuration.classuse) { 595 navList.addContent(getNavLinkClassUse()); 596 } 597 if(configuration.createtree) { 598 navList.addContent(getNavLinkTree()); 599 } 600 if(!(configuration.nodeprecated || 601 configuration.nodeprecatedlist)) { 602 navList.addContent(getNavLinkDeprecated()); 603 } 604 if(configuration.createindex) { 605 navList.addContent(getNavLinkIndex()); 606 } 607 if (!configuration.nohelp) { 608 navList.addContent(getNavLinkHelp()); 609 } 610 navDiv.addContent(navList); 611 Content aboutDiv = HtmlTree.DIV(HtmlStyle.aboutLanguage, getUserHeaderFooter(header)); 612 navDiv.addContent(aboutDiv); 613 if (header) { 614 fixedNavDiv.addContent(navDiv); 615 } else { 616 tree.addContent(navDiv); 617 } 618 Content ulNav = HtmlTree.UL(HtmlStyle.navList, getNavLinkPrevious(), getNavLinkNext()); 619 Content subDiv = HtmlTree.DIV(HtmlStyle.subNav, ulNav); 620 if (configuration.frames) { 621 Content ulFrames = HtmlTree.UL(HtmlStyle.navList, 622 getNavShowLists(), getNavHideLists(filename)); 623 subDiv.addContent(ulFrames); 624 } 625 HtmlTree ulAllClasses = HtmlTree.UL(HtmlStyle.navList, getNavLinkClassIndex()); 626 ulAllClasses.addAttr(HtmlAttr.ID, allClassesId); 627 subDiv.addContent(ulAllClasses); 628 if (header && configuration.createindex) { 629 String searchValueId = "search"; 630 String reset = "reset"; 631 HtmlTree inputText = HtmlTree.INPUT("text", searchValueId, searchValueId); 632 HtmlTree inputReset = HtmlTree.INPUT(reset, reset, reset); 633 Content searchTxt = configuration.getContent("doclet.search"); 634 HtmlTree liInput = HtmlTree.LI(HtmlTree.LABEL(searchValueId, searchTxt)); 635 liInput.addContent(inputText); 636 liInput.addContent(inputReset); 637 HtmlTree ulSearch = HtmlTree.UL(HtmlStyle.navListSearch, liInput); 638 subDiv.addContent(ulSearch); 639 } 640 subDiv.addContent(getAllClassesLinkScript(allClassesId)); 641 addSummaryDetailLinks(subDiv); 642 if (header) { 643 subDiv.addContent(getMarkerAnchor(SectionName.SKIP_NAVBAR_TOP)); 644 fixedNavDiv.addContent(subDiv); 645 fixedNavDiv.addContent(HtmlConstants.END_OF_TOP_NAVBAR); 646 tree.addContent(fixedNavDiv); 647 HtmlTree paddingDiv = HtmlTree.DIV(HtmlStyle.navPadding, Contents.SPACE); 648 tree.addContent(paddingDiv); 649 HtmlTree scriptTree = HtmlTree.SCRIPT(); 650 String scriptCode = "<!--\n" 651 + "$('.navPadding').css('padding-top', $('.fixedNav').css(\"height\"));\n" 652 + "//-->\n"; 653 RawHtml scriptContent = new RawHtml(scriptCode.replace("\n", DocletConstants.NL)); 654 scriptTree.addContent(scriptContent); 655 tree.addContent(scriptTree); 656 } else { 657 subDiv.addContent(getMarkerAnchor(SectionName.SKIP_NAVBAR_BOTTOM)); 658 tree.addContent(subDiv); 659 tree.addContent(HtmlConstants.END_OF_BOTTOM_NAVBAR); 660 } 661 if (configuration.allowTag(HtmlTag.NAV)) { 662 htmlTree.addContent(tree); 663 } 664 } 665 } 666 667 /** 668 * Get the word "NEXT" to indicate that no link is available. Override 669 * this method to customize next link. 670 * 671 * @return a content tree for the link 672 */ 673 protected Content getNavLinkNext() { 674 return getNavLinkNext(null); 675 } 676 677 /** 678 * Get the word "PREV" to indicate that no link is available. Override 679 * this method to customize prev link. 680 * 681 * @return a content tree for the link 682 */ 683 protected Content getNavLinkPrevious() { 684 return getNavLinkPrevious(null); 685 } 686 687 /** 688 * Do nothing. This is the default method. 689 */ 690 protected void addSummaryDetailLinks(Content navDiv) { 691 } 692 693 /** 694 * Get link to the "overview-summary.html" page. 695 * 696 * @return a content tree for the link 697 */ 698 protected Content getNavLinkContents() { 699 Content linkContent = getHyperLink(pathToRoot.resolve(DocPaths.overviewSummary(configuration.frames)), 700 contents.overviewLabel, "", ""); 701 Content li = HtmlTree.LI(linkContent); 702 return li; 703 } 704 705 /** 706 * Get link to the module summary page for the module passed. 707 * 708 * @param mdle Module to which link will be generated 709 * @return a content tree for the link 710 */ 711 protected Content getNavLinkModule(ModuleElement mdle) { 712 Content linkContent = getModuleLink(mdle, contents.moduleLabel); 713 Content li = HtmlTree.LI(linkContent); 714 return li; 715 } 716 717 /** 718 * Get the word "Module", to indicate that link is not available here. 719 * 720 * @return a content tree for the link 721 */ 722 protected Content getNavLinkModule() { 723 Content li = HtmlTree.LI(contents.moduleLabel); 724 return li; 725 } 726 727 /** 728 * Get link to the "package-summary.html" page for the package passed. 729 * 730 * @param pkg Package to which link will be generated 731 * @return a content tree for the link 732 */ 733 protected Content getNavLinkPackage(PackageElement pkg) { 734 Content linkContent = getPackageLink(pkg, contents.packageLabel); 735 Content li = HtmlTree.LI(linkContent); 736 return li; 737 } 738 739 /** 740 * Get the word "Package" , to indicate that link is not available here. 741 * 742 * @return a content tree for the link 743 */ 744 protected Content getNavLinkPackage() { 745 Content li = HtmlTree.LI(contents.packageLabel); 746 return li; 747 } 748 749 /** 750 * Get the word "Use", to indicate that link is not available. 751 * 752 * @return a content tree for the link 753 */ 754 protected Content getNavLinkClassUse() { 755 Content li = HtmlTree.LI(contents.useLabel); 756 return li; 757 } 758 759 /** 760 * Get link for previous file. 761 * 762 * @param prev File name for the prev link 763 * @return a content tree for the link 764 */ 765 public Content getNavLinkPrevious(DocPath prev) { 766 Content li; 767 if (prev != null) { 768 li = HtmlTree.LI(getHyperLink(prev, contents.prevLabel, "", "")); 769 } 770 else 771 li = HtmlTree.LI(contents.prevLabel); 772 return li; 773 } 774 775 /** 776 * Get link for next file. If next is null, just print the label 777 * without linking it anywhere. 778 * 779 * @param next File name for the next link 780 * @return a content tree for the link 781 */ 782 public Content getNavLinkNext(DocPath next) { 783 Content li; 784 if (next != null) { 785 li = HtmlTree.LI(getHyperLink(next, contents.nextLabel, "", "")); 786 } 787 else 788 li = HtmlTree.LI(contents.nextLabel); 789 return li; 790 } 791 792 /** 793 * Get "FRAMES" link, to switch to the frame version of the output. 794 * 795 * @param link File to be linked, "index.html" 796 * @return a content tree for the link 797 */ 798 protected Content getNavShowLists(DocPath link) { 799 DocLink dl = new DocLink(link, path.getPath(), null); 800 Content framesContent = getHyperLink(dl, contents.framesLabel, "", "_top"); 801 Content li = HtmlTree.LI(framesContent); 802 return li; 803 } 804 805 /** 806 * Get "FRAMES" link, to switch to the frame version of the output. 807 * 808 * @return a content tree for the link 809 */ 810 protected Content getNavShowLists() { 811 return getNavShowLists(pathToRoot.resolve(DocPaths.INDEX)); 812 } 813 814 /** 815 * Get "NO FRAMES" link, to switch to the non-frame version of the output. 816 * 817 * @param link File to be linked 818 * @return a content tree for the link 819 */ 820 protected Content getNavHideLists(DocPath link) { 821 Content noFramesContent = getHyperLink(link, contents.noFramesLabel, "", "_top"); 822 Content li = HtmlTree.LI(noFramesContent); 823 return li; 824 } 825 826 /** 827 * Get "Tree" link in the navigation bar. If there is only one package 828 * specified on the command line, then the "Tree" link will be to the 829 * only "package-tree.html" file otherwise it will be to the 830 * "overview-tree.html" file. 831 * 832 * @return a content tree for the link 833 */ 834 protected Content getNavLinkTree() { 835 List<PackageElement> packages = new ArrayList<>(configuration.getSpecifiedPackageElements()); 836 DocPath docPath = packages.size() == 1 && configuration.getSpecifiedTypeElements().isEmpty() 837 ? pathString(packages.get(0), DocPaths.PACKAGE_TREE) 838 : pathToRoot.resolve(DocPaths.OVERVIEW_TREE); 839 return HtmlTree.LI(getHyperLink(docPath, contents.treeLabel, "", "")); 840 } 841 842 /** 843 * Get the overview tree link for the main tree. 844 * 845 * @param label the label for the link 846 * @return a content tree for the link 847 */ 848 protected Content getNavLinkMainTree(String label) { 849 Content mainTreeContent = getHyperLink(pathToRoot.resolve(DocPaths.OVERVIEW_TREE), 850 new StringContent(label)); 851 Content li = HtmlTree.LI(mainTreeContent); 852 return li; 853 } 854 855 /** 856 * Get the word "Class", to indicate that class link is not available. 857 * 858 * @return a content tree for the link 859 */ 860 protected Content getNavLinkClass() { 861 Content li = HtmlTree.LI(contents.classLabel); 862 return li; 863 } 864 865 /** 866 * Get "Deprecated" API link in the navigation bar. 867 * 868 * @return a content tree for the link 869 */ 870 protected Content getNavLinkDeprecated() { 871 Content linkContent = getHyperLink(pathToRoot.resolve(DocPaths.DEPRECATED_LIST), 872 contents.deprecatedLabel, "", ""); 873 Content li = HtmlTree.LI(linkContent); 874 return li; 875 } 876 877 /** 878 * Get link for generated index. If the user has used "-splitindex" 879 * command line option, then link to file "index-files/index-1.html" is 880 * generated otherwise link to file "index-all.html" is generated. 881 * 882 * @return a content tree for the link 883 */ 884 protected Content getNavLinkClassIndex() { 885 Content allClassesContent = getHyperLink(pathToRoot.resolve( 886 DocPaths.AllClasses(configuration.frames)), 887 contents.allClassesLabel, "", ""); 888 Content li = HtmlTree.LI(allClassesContent); 889 return li; 890 } 891 892 /** 893 * Get link for generated class index. 894 * 895 * @return a content tree for the link 896 */ 897 protected Content getNavLinkIndex() { 898 Content linkContent = getHyperLink(pathToRoot.resolve( 899 (configuration.splitindex 900 ? DocPaths.INDEX_FILES.resolve(DocPaths.indexN(1)) 901 : DocPaths.INDEX_ALL)), 902 contents.indexLabel, "", ""); 903 Content li = HtmlTree.LI(linkContent); 904 return li; 905 } 906 907 /** 908 * Get help file link. If user has provided a help file, then generate a 909 * link to the user given file, which is already copied to current or 910 * destination directory. 911 * 912 * @return a content tree for the link 913 */ 914 protected Content getNavLinkHelp() { 915 String helpfile = configuration.helpfile; 916 DocPath helpfilenm; 917 if (helpfile.isEmpty()) { 918 helpfilenm = DocPaths.HELP_DOC; 919 } else { 920 DocFile file = DocFile.createFileForInput(configuration, helpfile); 921 helpfilenm = DocPath.create(file.getName()); 922 } 923 Content linkContent = getHyperLink(pathToRoot.resolve(helpfilenm), 924 contents.helpLabel, "", ""); 925 Content li = HtmlTree.LI(linkContent); 926 return li; 927 } 928 929 /** 930 * Add gap between navigation bar elements. 931 * 932 * @param liNav the content tree to which the gap will be added 933 */ 934 protected void addNavGap(Content liNav) { 935 liNav.addContent(Contents.SPACE); 936 liNav.addContent("|"); 937 liNav.addContent(Contents.SPACE); 938 } 939 940 /** 941 * Get summary table header. 942 * 943 * @param header the header for the table 944 * @param scope the scope of the headers 945 * @return a content tree for the header 946 */ 947 public Content getSummaryTableHeader(List<String> header, String scope) { 948 Content tr = new HtmlTree(HtmlTag.TR); 949 final int size = header.size(); 950 Content tableHeader; 951 if (size == 2) { 952 tableHeader = new StringContent(header.get(0)); 953 tr.addContent(HtmlTree.TH(HtmlStyle.colFirst, scope, tableHeader)); 954 tableHeader = new StringContent(header.get(1)); 955 tr.addContent(HtmlTree.TH(HtmlStyle.colLast, scope, tableHeader)); 956 return tr; 957 } 958 for (int i = 0; i < size; i++) { 959 tableHeader = new StringContent(header.get(i)); 960 if (i == 0) 961 tr.addContent(HtmlTree.TH(HtmlStyle.colFirst, scope, tableHeader)); 962 else if (i == 1) 963 tr.addContent(HtmlTree.TH(HtmlStyle.colSecond, scope, tableHeader)); 964 else if (i == (size - 1)) 965 tr.addContent(HtmlTree.TH(HtmlStyle.colLast, scope, tableHeader)); 966 else 967 tr.addContent(HtmlTree.TH(scope, tableHeader)); 968 } 969 return tr; 970 } 971 972 /** 973 * Get table caption. 974 * 975 * @param rawText the caption for the table which could be raw Html 976 * @return a content tree for the caption 977 */ 978 public Content getTableCaption(Content title) { 979 Content captionSpan = HtmlTree.SPAN(title); 980 Content space = Contents.SPACE; 981 Content tabSpan = HtmlTree.SPAN(HtmlStyle.tabEnd, space); 982 Content caption = HtmlTree.CAPTION(captionSpan); 983 caption.addContent(tabSpan); 984 return caption; 985 } 986 987 /** 988 * Get the marker anchor which will be added to the documentation tree. 989 * 990 * @param anchorName the anchor name attribute 991 * @return a content tree for the marker anchor 992 */ 993 public Content getMarkerAnchor(String anchorName) { 994 return getMarkerAnchor(getName(anchorName), null); 995 } 996 997 /** 998 * Get the marker anchor which will be added to the documentation tree. 999 * 1000 * @param sectionName the section name anchor attribute for page 1001 * @return a content tree for the marker anchor 1002 */ 1003 public Content getMarkerAnchor(SectionName sectionName) { 1004 return getMarkerAnchor(sectionName.getName(), null); 1005 } 1006 1007 /** 1008 * Get the marker anchor which will be added to the documentation tree. 1009 * 1010 * @param sectionName the section name anchor attribute for page 1011 * @param anchorName the anchor name combined with section name attribute for the page 1012 * @return a content tree for the marker anchor 1013 */ 1014 public Content getMarkerAnchor(SectionName sectionName, String anchorName) { 1015 return getMarkerAnchor(sectionName.getName() + getName(anchorName), null); 1016 } 1017 1018 /** 1019 * Get the marker anchor which will be added to the documentation tree. 1020 * 1021 * @param anchorName the anchor name or id attribute 1022 * @param anchorContent the content that should be added to the anchor 1023 * @return a content tree for the marker anchor 1024 */ 1025 public Content getMarkerAnchor(String anchorName, Content anchorContent) { 1026 if (anchorContent == null) 1027 anchorContent = new Comment(" "); 1028 Content markerAnchor = HtmlTree.A(configuration.htmlVersion, anchorName, anchorContent); 1029 return markerAnchor; 1030 } 1031 1032 /** 1033 * Returns a packagename content. 1034 * 1035 * @param packageElement the package to check 1036 * @return package name content 1037 */ 1038 public Content getPackageName(PackageElement packageElement) { 1039 return packageElement == null || packageElement.isUnnamed() 1040 ? contents.defaultPackageLabel 1041 : getPackageLabel(packageElement.getQualifiedName()); 1042 } 1043 1044 /** 1045 * Returns a package name label. 1046 * 1047 * @param packageName the package name 1048 * @return the package name content 1049 */ 1050 public Content getPackageLabel(CharSequence packageName) { 1051 return new StringContent(packageName); 1052 } 1053 1054 /** 1055 * Return the path to the class page for a typeElement. 1056 * 1057 * @param te TypeElement for which the path is requested. 1058 * @param name Name of the file(doesn't include path). 1059 */ 1060 protected DocPath pathString(TypeElement te, DocPath name) { 1061 return pathString(utils.containingPackage(te), name); 1062 } 1063 1064 /** 1065 * Return path to the given file name in the given package. So if the name 1066 * passed is "Object.html" and the name of the package is "java.lang", and 1067 * if the relative path is "../.." then returned string will be 1068 * "../../java/lang/Object.html" 1069 * 1070 * @param packageElement Package in which the file name is assumed to be. 1071 * @param name File name, to which path string is. 1072 */ 1073 protected DocPath pathString(PackageElement packageElement, DocPath name) { 1074 return pathToRoot.resolve(DocPath.forPackage(packageElement).resolve(name)); 1075 } 1076 1077 /** 1078 * Given a package, return the name to be used in HTML anchor tag. 1079 * @param packageElement the package. 1080 * @return the name to be used in HTML anchor tag. 1081 */ 1082 public String getPackageAnchorName(PackageElement packageElement) { 1083 return packageElement == null || packageElement.isUnnamed() 1084 ? SectionName.UNNAMED_PACKAGE_ANCHOR.getName() 1085 : utils.getPackageName(packageElement); 1086 } 1087 1088 /** 1089 * Return the link to the given package. 1090 * 1091 * @param packageElement the package to link to. 1092 * @param label the label for the link. 1093 * @return a content tree for the package link. 1094 */ 1095 public Content getPackageLink(PackageElement packageElement, CharSequence label) { 1096 return getPackageLink(packageElement, new StringContent(label)); 1097 } 1098 1099 public Content getPackageLink(PackageElement packageElement) { 1100 StringContent content = packageElement.isUnnamed() 1101 ? new StringContent() 1102 : new StringContent(utils.getPackageName(packageElement)); 1103 return getPackageLink(packageElement, content); 1104 } 1105 1106 /** 1107 * Return the link to the given package. 1108 * 1109 * @param packageElement the package to link to. 1110 * @param label the label for the link. 1111 * @return a content tree for the package link. 1112 */ 1113 public Content getPackageLink(PackageElement packageElement, Content label) { 1114 boolean included = packageElement != null && utils.isIncluded(packageElement); 1115 if (!included) { 1116 for (PackageElement p : configuration.packages) { 1117 if (p.equals(packageElement)) { 1118 included = true; 1119 break; 1120 } 1121 } 1122 } 1123 if (included || packageElement == null) { 1124 return getHyperLink(pathString(packageElement, DocPaths.PACKAGE_SUMMARY), 1125 label); 1126 } else { 1127 DocLink crossPkgLink = getCrossPackageLink(utils.getPackageName(packageElement)); 1128 if (crossPkgLink != null) { 1129 return getHyperLink(crossPkgLink, label); 1130 } else { 1131 return label; 1132 } 1133 } 1134 } 1135 1136 /** 1137 * Get Module link. 1138 * 1139 * @param mdle the module being documented 1140 * @param label tag for the link 1141 * @return a content for the module link 1142 */ 1143 public Content getModuleLink(ModuleElement mdle, Content label) { 1144 boolean included = utils.isIncluded(mdle); 1145 return (included) 1146 ? getHyperLink(pathToRoot.resolve(DocPaths.moduleSummary(mdle)), label, "", "") 1147 : label; 1148 } 1149 1150 public Content interfaceName(TypeElement typeElement, boolean qual) { 1151 Content name = new StringContent((qual) 1152 ? typeElement.getQualifiedName() 1153 : utils.getSimpleName(typeElement)); 1154 return (utils.isInterface(typeElement)) ? HtmlTree.SPAN(HtmlStyle.interfaceName, name) : name; 1155 } 1156 1157 /** 1158 * Add the link to the content tree. 1159 * 1160 * @param typeElement program element typeElement for which the link will be added 1161 * @param label label for the link 1162 * @param htmltree the content tree to which the link will be added 1163 */ 1164 public void addSrcLink(Element typeElement, Content label, Content htmltree) { 1165 if (typeElement == null) { 1166 return; 1167 } 1168 TypeElement te = utils.getEnclosingTypeElement(typeElement); 1169 if (te == null) { 1170 // must be a typeElement since in has no containing class. 1171 te = (TypeElement) typeElement; 1172 } 1173 DocPath href = pathToRoot 1174 .resolve(DocPaths.SOURCE_OUTPUT) 1175 .resolve(DocPath.forClass(utils, te)); 1176 Content linkContent = getHyperLink(href 1177 .fragment(SourceToHTMLConverter.getAnchorName(utils, typeElement)), label, "", ""); 1178 htmltree.addContent(linkContent); 1179 } 1180 1181 /** 1182 * Return the link to the given class. 1183 * 1184 * @param linkInfo the information about the link. 1185 * 1186 * @return the link for the given class. 1187 */ 1188 public Content getLink(LinkInfoImpl linkInfo) { 1189 LinkFactoryImpl factory = new LinkFactoryImpl(this); 1190 return factory.getLink(linkInfo); 1191 } 1192 1193 /** 1194 * Return the type parameters for the given class. 1195 * 1196 * @param linkInfo the information about the link. 1197 * @return the type for the given class. 1198 */ 1199 public Content getTypeParameterLinks(LinkInfoImpl linkInfo) { 1200 LinkFactoryImpl factory = new LinkFactoryImpl(this); 1201 return factory.getTypeParameterLinks(linkInfo, false); 1202 } 1203 1204 /************************************************************* 1205 * Return a class cross link to external class documentation. 1206 * The name must be fully qualified to determine which package 1207 * the class is in. The -link option does not allow users to 1208 * link to external classes in the "default" package. 1209 * 1210 * @param qualifiedClassName the qualified name of the external class. 1211 * @param refMemName the name of the member being referenced. This should 1212 * be null or empty string if no member is being referenced. 1213 * @param label the label for the external link. 1214 * @param strong true if the link should be strong. 1215 * @param style the style of the link. 1216 * @param code true if the label should be code font. 1217 */ 1218 public Content getCrossClassLink(String qualifiedClassName, String refMemName, 1219 Content label, boolean strong, String style, 1220 boolean code) { 1221 String className = ""; 1222 String packageName = qualifiedClassName == null ? "" : qualifiedClassName; 1223 int periodIndex; 1224 while ((periodIndex = packageName.lastIndexOf('.')) != -1) { 1225 className = packageName.substring(periodIndex + 1, packageName.length()) + 1226 (className.length() > 0 ? "." + className : ""); 1227 Content defaultLabel = new StringContent(className); 1228 if (code) 1229 defaultLabel = HtmlTree.CODE(defaultLabel); 1230 packageName = packageName.substring(0, periodIndex); 1231 if (getCrossPackageLink(packageName) != null) { 1232 /* 1233 The package exists in external documentation, so link to the external 1234 class (assuming that it exists). This is definitely a limitation of 1235 the -link option. There are ways to determine if an external package 1236 exists, but no way to determine if the external class exists. We just 1237 have to assume that it does. 1238 */ 1239 DocLink link = configuration.extern.getExternalLink(packageName, pathToRoot, 1240 className + ".html", refMemName); 1241 return getHyperLink(link, 1242 (label == null) || label.isEmpty() ? defaultLabel : label, 1243 strong, style, 1244 configuration.getText("doclet.Href_Class_Or_Interface_Title", packageName), 1245 ""); 1246 } 1247 } 1248 return null; 1249 } 1250 1251 public boolean isClassLinkable(TypeElement typeElement) { 1252 if (utils.isIncluded(typeElement)) { 1253 return configuration.isGeneratedDoc(typeElement); 1254 } 1255 return configuration.extern.isExternal(typeElement); 1256 } 1257 1258 public DocLink getCrossPackageLink(String pkgName) { 1259 return configuration.extern.getExternalLink(pkgName, pathToRoot, 1260 DocPaths.PACKAGE_SUMMARY.getPath()); 1261 } 1262 1263 /** 1264 * Get the class link. 1265 * 1266 * @param context the id of the context where the link will be added 1267 * @param element to link to 1268 * @return a content tree for the link 1269 */ 1270 public Content getQualifiedClassLink(LinkInfoImpl.Kind context, Element element) { 1271 LinkInfoImpl linkInfoImpl = new LinkInfoImpl(configuration, context, (TypeElement)element); 1272 return getLink(linkInfoImpl.label(utils.getFullyQualifiedName(element))); 1273 } 1274 1275 /** 1276 * Add the class link. 1277 * 1278 * @param context the id of the context where the link will be added 1279 * @param typeElement to link to 1280 * @param contentTree the content tree to which the link will be added 1281 */ 1282 public void addPreQualifiedClassLink(LinkInfoImpl.Kind context, TypeElement typeElement, Content contentTree) { 1283 addPreQualifiedClassLink(context, typeElement, false, contentTree); 1284 } 1285 1286 /** 1287 * Retrieve the class link with the package portion of the label in 1288 * plain text. If the qualifier is excluded, it will not be included in the 1289 * link label. 1290 * 1291 * @param typeElement the class to link to. 1292 * @param isStrong true if the link should be strong. 1293 * @return the link with the package portion of the label in plain text. 1294 */ 1295 public Content getPreQualifiedClassLink(LinkInfoImpl.Kind context, 1296 TypeElement typeElement, boolean isStrong) { 1297 ContentBuilder classlink = new ContentBuilder(); 1298 PackageElement pkg = utils.containingPackage(typeElement); 1299 if (pkg != null && ! configuration.shouldExcludeQualifier(pkg.getSimpleName().toString())) { 1300 classlink.addContent(getEnclosingPackageName(typeElement)); 1301 } 1302 classlink.addContent(getLink(new LinkInfoImpl(configuration, 1303 context, typeElement).label(utils.getSimpleName(typeElement)).strong(isStrong))); 1304 return classlink; 1305 } 1306 1307 /** 1308 * Add the class link with the package portion of the label in 1309 * plain text. If the qualifier is excluded, it will not be included in the 1310 * link label. 1311 * 1312 * @param context the id of the context where the link will be added 1313 * @param typeElement the class to link to 1314 * @param isStrong true if the link should be strong 1315 * @param contentTree the content tree to which the link with be added 1316 */ 1317 public void addPreQualifiedClassLink(LinkInfoImpl.Kind context, 1318 TypeElement typeElement, boolean isStrong, Content contentTree) { 1319 PackageElement pkg = utils.containingPackage(typeElement); 1320 if(pkg != null && ! configuration.shouldExcludeQualifier(pkg.getSimpleName().toString())) { 1321 contentTree.addContent(getEnclosingPackageName(typeElement)); 1322 } 1323 LinkInfoImpl linkinfo = new LinkInfoImpl(configuration, context, typeElement) 1324 .label(utils.getSimpleName(typeElement)) 1325 .strong(isStrong); 1326 Content link = getLink(linkinfo); 1327 contentTree.addContent(link); 1328 } 1329 1330 /** 1331 * Add the class link, with only class name as the strong link and prefixing 1332 * plain package name. 1333 * 1334 * @param context the id of the context where the link will be added 1335 * @param typeElement the class to link to 1336 * @param contentTree the content tree to which the link with be added 1337 */ 1338 public void addPreQualifiedStrongClassLink(LinkInfoImpl.Kind context, TypeElement typeElement, Content contentTree) { 1339 addPreQualifiedClassLink(context, typeElement, true, contentTree); 1340 } 1341 1342 /** 1343 * Get the link for the given member. 1344 * 1345 * @param context the id of the context where the link will be added 1346 * @param element the member being linked to 1347 * @param label the label for the link 1348 * @return a content tree for the element link 1349 */ 1350 public Content getDocLink(LinkInfoImpl.Kind context, Element element, CharSequence label) { 1351 return getDocLink(context, utils.getEnclosingTypeElement(element), element, 1352 new StringContent(label)); 1353 } 1354 1355 /** 1356 * Return the link for the given member. 1357 * 1358 * @param context the id of the context where the link will be printed. 1359 * @param element the member being linked to. 1360 * @param label the label for the link. 1361 * @param strong true if the link should be strong. 1362 * @return the link for the given member. 1363 */ 1364 public Content getDocLink(LinkInfoImpl.Kind context, Element element, CharSequence label, 1365 boolean strong) { 1366 return getDocLink(context, utils.getEnclosingTypeElement(element), element, label, strong); 1367 } 1368 1369 /** 1370 * Return the link for the given member. 1371 * 1372 * @param context the id of the context where the link will be printed. 1373 * @param typeElement the typeElement that we should link to. This is not 1374 necessarily equal to element.containingClass(). We may be 1375 inheriting comments. 1376 * @param element the member being linked to. 1377 * @param label the label for the link. 1378 * @param strong true if the link should be strong. 1379 * @return the link for the given member. 1380 */ 1381 public Content getDocLink(LinkInfoImpl.Kind context, TypeElement typeElement, Element element, 1382 CharSequence label, boolean strong) { 1383 return getDocLink(context, typeElement, element, label, strong, false); 1384 } 1385 1386 public Content getDocLink(LinkInfoImpl.Kind context, TypeElement typeElement, Element element, 1387 Content label, boolean strong) { 1388 return getDocLink(context, typeElement, element, label, strong, false); 1389 } 1390 1391 /** 1392 * Return the link for the given member. 1393 * 1394 * @param context the id of the context where the link will be printed. 1395 * @param typeElement the typeElement that we should link to. This is not 1396 necessarily equal to element.containingClass(). We may be 1397 inheriting comments. 1398 * @param element the member being linked to. 1399 * @param label the label for the link. 1400 * @param strong true if the link should be strong. 1401 * @param isProperty true if the element parameter is a JavaFX property. 1402 * @return the link for the given member. 1403 */ 1404 public Content getDocLink(LinkInfoImpl.Kind context, TypeElement typeElement, Element element, 1405 CharSequence label, boolean strong, boolean isProperty) { 1406 return getDocLink(context, typeElement, element, new StringContent(check(label)), strong, isProperty); 1407 } 1408 1409 CharSequence check(CharSequence s) { 1410 Matcher m = IMPROPER_HTML_CHARS.matcher(s); 1411 if (m.matches()) { 1412 throw new IllegalArgumentException(s.toString()); 1413 } 1414 return s; 1415 } 1416 1417 public Content getDocLink(LinkInfoImpl.Kind context, TypeElement typeElement, Element element, 1418 Content label, boolean strong, boolean isProperty) { 1419 if (! (utils.isIncluded(element) || utils.isLinkable(typeElement))) { 1420 return label; 1421 } else if (utils.isExecutableElement(element)) { 1422 ExecutableElement ee = (ExecutableElement)element; 1423 return getLink(new LinkInfoImpl(configuration, context, typeElement) 1424 .label(label) 1425 .where(getName(getAnchor(ee, isProperty))) 1426 .strong(strong)); 1427 } else if (utils.isVariableElement(element) || utils.isTypeElement(element)) { 1428 return getLink(new LinkInfoImpl(configuration, context, typeElement) 1429 .label(label) 1430 .where(getName(element.getSimpleName().toString())) 1431 .strong(strong)); 1432 } else { 1433 return label; 1434 } 1435 } 1436 1437 /** 1438 * Return the link for the given member. 1439 * 1440 * @param context the id of the context where the link will be added 1441 * @param typeElement the typeElement that we should link to. This is not 1442 necessarily equal to element.containingClass(). We may be 1443 inheriting comments 1444 * @param element the member being linked to 1445 * @param label the label for the link 1446 * @return the link for the given member 1447 */ 1448 public Content getDocLink(LinkInfoImpl.Kind context, TypeElement typeElement, Element element, 1449 Content label) { 1450 if (! (utils.isIncluded(element) || utils.isLinkable(typeElement))) { 1451 return label; 1452 } else if (utils.isExecutableElement(element)) { 1453 ExecutableElement emd = (ExecutableElement) element; 1454 return getLink(new LinkInfoImpl(configuration, context, typeElement) 1455 .label(label) 1456 .where(getName(getAnchor(emd)))); 1457 } else if (utils.isVariableElement(element) || utils.isTypeElement(element)) { 1458 return getLink(new LinkInfoImpl(configuration, context, typeElement) 1459 .label(label).where(getName(element.getSimpleName().toString()))); 1460 } else { 1461 return label; 1462 } 1463 } 1464 1465 public String getAnchor(ExecutableElement executableElement) { 1466 return getAnchor(executableElement, false); 1467 } 1468 1469 public String getAnchor(ExecutableElement executableElement, boolean isProperty) { 1470 if (isProperty) { 1471 return executableElement.getSimpleName().toString(); 1472 } 1473 String member = anchorName(executableElement); 1474 String erasedSignature = utils.makeSignature(executableElement, true, true); 1475 return member + erasedSignature; 1476 } 1477 1478 public String anchorName(Element member) { 1479 if (member.getKind() == ElementKind.CONSTRUCTOR 1480 && configuration.isOutputHtml5()) { 1481 return "<init>"; 1482 } else { 1483 return utils.getSimpleName(member); 1484 } 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 }