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