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