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