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