1 /* 2 * Copyright (c) 1998, 2012, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package com.sun.tools.doclets.formats.html; 27 28 import java.io.*; 29 import java.text.SimpleDateFormat; 30 import java.util.*; 31 32 import com.sun.javadoc.*; 33 import com.sun.tools.doclets.formats.html.markup.*; 34 import com.sun.tools.doclets.internal.toolkit.*; 35 import com.sun.tools.doclets.internal.toolkit.taglets.*; 36 import com.sun.tools.doclets.internal.toolkit.util.*; 37 38 /** 39 * Class for the Html Format Code Generation specific to JavaDoc. 40 * This Class contains methods related to the Html Code Generation which 41 * are used extensively while generating the entire documentation. 42 * 43 * <p><b>This is NOT part of any supported API. 44 * If you write code that depends on this, you do so at your own risk. 45 * This code and its internal interfaces are subject to change or 46 * deletion without notice.</b> 47 * 48 * @since 1.2 49 * @author Atul M Dambalkar 50 * @author Robert Field 51 * @author Bhavesh Patel (Modified) 52 */ 53 public class HtmlDocletWriter extends HtmlDocWriter { 54 55 /** 56 * Relative path from the file getting generated to the destination 57 * directory. For example, if the file getting generated is 58 * "java/lang/Object.html", then the path to the root is "../..". 59 * This string can be empty if the file getting generated is in 60 * the destination directory. 61 */ 62 public final DocPath pathToRoot; 63 64 /** 65 * Platform-independent path from the current or the 66 * destination directory to the file getting generated. 67 * Used when creating the file. 68 */ 69 public final DocPath path; 70 71 /** 72 * Name of the file getting generated. If the file getting generated is 73 * "java/lang/Object.html", then the filename is "Object.html". 74 */ 75 public final DocPath filename; 76 77 /** 78 * The display length used for indentation while generating the class page. 79 */ 80 public int displayLength = 0; 81 82 /** 83 * The global configuration information for this run. 84 */ 85 public final ConfigurationImpl configuration; 86 87 /** 88 * To check whether annotation heading is printed or not. 89 */ 90 protected boolean printedAnnotationHeading = false; 91 92 /** 93 * To check whether the repeated annotations is documented or not. 94 */ 95 private boolean isAnnotationDocumented = false; 96 97 /** 98 * To check whether the container annotations is documented or not. 99 */ 100 private boolean isContainerDocumented = false; 101 102 /** 103 * Constructor to construct the HtmlStandardWriter object. 104 * 105 * @param path File to be generated. 106 */ 107 public HtmlDocletWriter(ConfigurationImpl configuration, DocPath path) 108 throws IOException { 109 super(configuration, path); 110 this.configuration = configuration; 111 this.path = path; 112 this.pathToRoot = path.parent().invert(); 113 this.filename = path.basename(); 114 } 115 116 /** 117 * Replace {@docRoot} tag used in options that accept HTML text, such 118 * as -header, -footer, -top and -bottom, and when converting a relative 119 * HREF where commentTagsToString inserts a {@docRoot} where one was 120 * missing. (Also see DocRootTaglet for {@docRoot} tags in doc 121 * comments.) 122 * <p> 123 * Replace {@docRoot} tag in htmlstr with the relative path to the 124 * destination directory from the directory where the file is being 125 * written, looping to handle all such tags in htmlstr. 126 * <p> 127 * For example, for "-d docs" and -header containing {@docRoot}, when 128 * the HTML page for source file p/C1.java is being generated, the 129 * {@docRoot} tag would be inserted into the header as "../", 130 * the relative path from docs/p/ to docs/ (the document root). 131 * <p> 132 * Note: This doc comment was written with '&#064;' representing '@' 133 * to prevent the inline tag from being interpreted. 134 */ 135 public String replaceDocRootDir(String htmlstr) { 136 // Return if no inline tags exist 137 int index = htmlstr.indexOf("{@"); 138 if (index < 0) { 139 return htmlstr; 140 } 141 String lowerHtml = htmlstr.toLowerCase(); 142 // Return index of first occurrence of {@docroot} 143 // Note: {@docRoot} is not case sensitive when passed in w/command line option 144 index = lowerHtml.indexOf("{@docroot}", index); 145 if (index < 0) { 146 return htmlstr; 147 } 148 StringBuilder buf = new StringBuilder(); 149 int previndex = 0; 150 while (true) { 151 if (configuration.docrootparent.length() > 0) { 152 final String docroot_parent = "{@docroot}/.."; 153 // Search for lowercase version of {@docRoot}/.. 154 index = lowerHtml.indexOf(docroot_parent, previndex); 155 // If next {@docRoot}/.. pattern not found, append rest of htmlstr and exit loop 156 if (index < 0) { 157 buf.append(htmlstr.substring(previndex)); 158 break; 159 } 160 // If next {@docroot}/.. pattern found, append htmlstr up to start of tag 161 buf.append(htmlstr.substring(previndex, index)); 162 previndex = index + docroot_parent.length(); 163 // Insert docrootparent absolute path where {@docRoot}/.. was located 164 165 buf.append(configuration.docrootparent); 166 // Append slash if next character is not a slash 167 if (previndex < htmlstr.length() && htmlstr.charAt(previndex) != '/') { 168 buf.append('/'); 169 } 170 } else { 171 final String docroot = "{@docroot}"; 172 // Search for lowercase version of {@docRoot} 173 index = lowerHtml.indexOf(docroot, previndex); 174 // If next {@docRoot} tag not found, append rest of htmlstr and exit loop 175 if (index < 0) { 176 buf.append(htmlstr.substring(previndex)); 177 break; 178 } 179 // If next {@docroot} tag found, append htmlstr up to start of tag 180 buf.append(htmlstr.substring(previndex, index)); 181 previndex = index + docroot.length(); 182 // Insert relative path where {@docRoot} was located 183 buf.append(pathToRoot.isEmpty() ? "." : pathToRoot.getPath()); 184 // Append slash if next character is not a slash 185 if (previndex < htmlstr.length() && htmlstr.charAt(previndex) != '/') { 186 buf.append('/'); 187 } 188 } 189 } 190 return buf.toString(); 191 } 192 193 /** 194 * Get the script to show or hide the All classes link. 195 * 196 * @param id id of the element to show or hide 197 * @return a content tree for the script 198 */ 199 public Content getAllClassesLinkScript(String id) { 200 HtmlTree script = new HtmlTree(HtmlTag.SCRIPT); 201 script.addAttr(HtmlAttr.TYPE, "text/javascript"); 202 String scriptCode = "<!--" + DocletConstants.NL + 203 " allClassesLink = document.getElementById(\"" + id + "\");" + DocletConstants.NL + 204 " if(window==top) {" + DocletConstants.NL + 205 " allClassesLink.style.display = \"block\";" + DocletConstants.NL + 206 " }" + DocletConstants.NL + 207 " else {" + DocletConstants.NL + 208 " allClassesLink.style.display = \"none\";" + DocletConstants.NL + 209 " }" + DocletConstants.NL + 210 " //-->" + DocletConstants.NL; 211 Content scriptContent = new RawHtml(scriptCode); 212 script.addContent(scriptContent); 213 Content div = HtmlTree.DIV(script); 214 return div; 215 } 216 217 /** 218 * Add method information. 219 * 220 * @param method the method to be documented 221 * @param dl the content tree to which the method information will be added 222 */ 223 private void addMethodInfo(MethodDoc method, Content dl) { 224 ClassDoc[] intfacs = method.containingClass().interfaces(); 225 MethodDoc overriddenMethod = method.overriddenMethod(); 226 // Check whether there is any implementation or overridden info to be 227 // printed. If no overridden or implementation info needs to be 228 // printed, do not print this section. 229 if ((intfacs.length > 0 && 230 new ImplementedMethods(method, this.configuration).build().length > 0) || 231 overriddenMethod != null) { 232 MethodWriterImpl.addImplementsInfo(this, method, dl); 233 if (overriddenMethod != null) { 234 MethodWriterImpl.addOverridden(this, 235 method.overriddenType(), overriddenMethod, dl); 236 } 237 } 238 } 239 240 /** 241 * Adds the tags information. 242 * 243 * @param doc the doc for which the tags will be generated 244 * @param htmltree the documentation tree to which the tags will be added 245 */ 246 protected void addTagsInfo(Doc doc, Content htmltree) { 247 if (configuration.nocomment) { 248 return; 249 } 250 Content dl = new HtmlTree(HtmlTag.DL); 251 if (doc instanceof MethodDoc) { 252 addMethodInfo((MethodDoc) doc, dl); 253 } 254 TagletOutputImpl output = new TagletOutputImpl(""); 255 TagletWriter.genTagOuput(configuration.tagletManager, doc, 256 configuration.tagletManager.getCustomTags(doc), 257 getTagletWriterInstance(false), output); 258 String outputString = output.toString().trim(); 259 if (!outputString.isEmpty()) { 260 Content resultString = new RawHtml(outputString); 261 dl.addContent(resultString); 262 } 263 htmltree.addContent(dl); 264 } 265 266 /** 267 * Check whether there are any tags for Serialization Overview 268 * section to be printed. 269 * 270 * @param field the FieldDoc object to check for tags. 271 * @return true if there are tags to be printed else return false. 272 */ 273 protected boolean hasSerializationOverviewTags(FieldDoc field) { 274 TagletOutputImpl output = new TagletOutputImpl(""); 275 TagletWriter.genTagOuput(configuration.tagletManager, field, 276 configuration.tagletManager.getCustomTags(field), 277 getTagletWriterInstance(false), output); 278 return (!output.toString().trim().isEmpty()); 279 } 280 281 /** 282 * Returns a TagletWriter that knows how to write HTML. 283 * 284 * @return a TagletWriter that knows how to write HTML. 285 */ 286 public TagletWriter getTagletWriterInstance(boolean isFirstSentence) { 287 return new TagletWriterImpl(this, isFirstSentence); 288 } 289 290 /** 291 * Get Package link, with target frame. 292 * 293 * @param pd The link will be to the "package-summary.html" page for this package 294 * @param target name of the target frame 295 * @param label tag for the link 296 * @return a content for the target package link 297 */ 298 public Content getTargetPackageLink(PackageDoc pd, String target, 299 Content label) { 300 return getHyperLink(pathString(pd, DocPaths.PACKAGE_SUMMARY), label, "", target); 301 } 302 303 /** 304 * Generates the HTML document tree and prints it out. 305 * 306 * @param metakeywords Array of String keywords for META tag. Each element 307 * of the array is assigned to a separate META tag. 308 * Pass in null for no array 309 * @param includeScript true if printing windowtitle script 310 * false for files that appear in the left-hand frames 311 * @param body the body htmltree to be included in the document 312 */ 313 public void printHtmlDocument(String[] metakeywords, boolean includeScript, 314 Content body) throws IOException { 315 Content htmlDocType = DocType.TRANSITIONAL; 316 Content htmlComment = new Comment(configuration.getText("doclet.New_Page")); 317 Content head = new HtmlTree(HtmlTag.HEAD); 318 if (!configuration.notimestamp) { 319 Content headComment = new Comment(getGeneratedByString()); 320 head.addContent(headComment); 321 } 322 if (configuration.charset.length() > 0) { 323 Content meta = HtmlTree.META("Content-Type", "text/html", 324 configuration.charset); 325 head.addContent(meta); 326 } 327 head.addContent(getTitle()); 328 if (!configuration.notimestamp) { 329 SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd"); 330 Content meta = HtmlTree.META("date", dateFormat.format(new Date())); 331 head.addContent(meta); 332 } 333 if (metakeywords != null) { 334 for (int i=0; i < metakeywords.length; i++) { 335 Content meta = HtmlTree.META("keywords", metakeywords[i]); 336 head.addContent(meta); 337 } 338 } 339 head.addContent(getStyleSheetProperties()); 340 head.addContent(getScriptProperties()); 341 Content htmlTree = HtmlTree.HTML(configuration.getLocale().getLanguage(), 342 head, body); 343 Content htmlDocument = new HtmlDocument(htmlDocType, 344 htmlComment, htmlTree); 345 write(htmlDocument); 346 } 347 348 /** 349 * Get the window title. 350 * 351 * @param title the title string to construct the complete window title 352 * @return the window title string 353 */ 354 public String getWindowTitle(String title) { 355 if (configuration.windowtitle.length() > 0) { 356 title += " (" + configuration.windowtitle + ")"; 357 } 358 return title; 359 } 360 361 /** 362 * Get user specified header and the footer. 363 * 364 * @param header if true print the user provided header else print the 365 * user provided footer. 366 */ 367 public Content getUserHeaderFooter(boolean header) { 368 String content; 369 if (header) { 370 content = replaceDocRootDir(configuration.header); 371 } else { 372 if (configuration.footer.length() != 0) { 373 content = replaceDocRootDir(configuration.footer); 374 } else { 375 content = replaceDocRootDir(configuration.header); 376 } 377 } 378 Content rawContent = new RawHtml(content); 379 Content em = HtmlTree.EM(rawContent); 380 return em; 381 } 382 383 /** 384 * Adds the user specified top. 385 * 386 * @param body the content tree to which user specified top will be added 387 */ 388 public void addTop(Content body) { 389 Content top = new RawHtml(replaceDocRootDir(configuration.top)); 390 body.addContent(top); 391 } 392 393 /** 394 * Adds the user specified bottom. 395 * 396 * @param body the content tree to which user specified bottom will be added 397 */ 398 public void addBottom(Content body) { 399 Content bottom = new RawHtml(replaceDocRootDir(configuration.bottom)); 400 Content small = HtmlTree.SMALL(bottom); 401 Content p = HtmlTree.P(HtmlStyle.legalCopy, small); 402 body.addContent(p); 403 } 404 405 /** 406 * Adds the navigation bar for the Html page at the top and and the bottom. 407 * 408 * @param header If true print navigation bar at the top of the page else 409 * @param body the HtmlTree to which the nav links will be added 410 */ 411 protected void addNavLinks(boolean header, Content body) { 412 if (!configuration.nonavbar) { 413 String allClassesId = "allclasses_"; 414 HtmlTree navDiv = new HtmlTree(HtmlTag.DIV); 415 if (header) { 416 body.addContent(HtmlConstants.START_OF_TOP_NAVBAR); 417 navDiv.addStyle(HtmlStyle.topNav); 418 allClassesId += "navbar_top"; 419 Content a = getMarkerAnchor("navbar_top"); 420 navDiv.addContent(a); 421 Content skipLinkContent = getHyperLink(DocLink.fragment("skip-navbar_top"), 422 HtmlTree.EMPTY, 423 configuration.getText("doclet.Skip_navigation_links"), 424 ""); 425 navDiv.addContent(skipLinkContent); 426 } else { 427 body.addContent(HtmlConstants.START_OF_BOTTOM_NAVBAR); 428 navDiv.addStyle(HtmlStyle.bottomNav); 429 allClassesId += "navbar_bottom"; 430 Content a = getMarkerAnchor("navbar_bottom"); 431 navDiv.addContent(a); 432 Content skipLinkContent = getHyperLink(DocLink.fragment("skip-navbar_bottom"), 433 HtmlTree.EMPTY, 434 configuration.getText("doclet.Skip_navigation_links"), 435 ""); 436 navDiv.addContent(skipLinkContent); 437 } 438 if (header) { 439 navDiv.addContent(getMarkerAnchor("navbar_top_firstrow")); 440 } else { 441 navDiv.addContent(getMarkerAnchor("navbar_bottom_firstrow")); 442 } 443 HtmlTree navList = new HtmlTree(HtmlTag.UL); 444 navList.addStyle(HtmlStyle.navList); 445 navList.addAttr(HtmlAttr.TITLE, "Navigation"); 446 if (configuration.createoverview) { 447 navList.addContent(getNavLinkContents()); 448 } 449 if (configuration.packages.length == 1) { 450 navList.addContent(getNavLinkPackage(configuration.packages[0])); 451 } else if (configuration.packages.length > 1) { 452 navList.addContent(getNavLinkPackage()); 453 } 454 navList.addContent(getNavLinkClass()); 455 if(configuration.classuse) { 456 navList.addContent(getNavLinkClassUse()); 457 } 458 if(configuration.createtree) { 459 navList.addContent(getNavLinkTree()); 460 } 461 if(!(configuration.nodeprecated || 462 configuration.nodeprecatedlist)) { 463 navList.addContent(getNavLinkDeprecated()); 464 } 465 if(configuration.createindex) { 466 navList.addContent(getNavLinkIndex()); 467 } 468 if (!configuration.nohelp) { 469 navList.addContent(getNavLinkHelp()); 470 } 471 navDiv.addContent(navList); 472 Content aboutDiv = HtmlTree.DIV(HtmlStyle.aboutLanguage, getUserHeaderFooter(header)); 473 navDiv.addContent(aboutDiv); 474 body.addContent(navDiv); 475 Content ulNav = HtmlTree.UL(HtmlStyle.navList, getNavLinkPrevious()); 476 ulNav.addContent(getNavLinkNext()); 477 Content subDiv = HtmlTree.DIV(HtmlStyle.subNav, ulNav); 478 Content ulFrames = HtmlTree.UL(HtmlStyle.navList, getNavShowLists()); 479 ulFrames.addContent(getNavHideLists(filename)); 480 subDiv.addContent(ulFrames); 481 HtmlTree ulAllClasses = HtmlTree.UL(HtmlStyle.navList, getNavLinkClassIndex()); 482 ulAllClasses.addAttr(HtmlAttr.ID, allClassesId.toString()); 483 subDiv.addContent(ulAllClasses); 484 subDiv.addContent(getAllClassesLinkScript(allClassesId.toString())); 485 addSummaryDetailLinks(subDiv); 486 if (header) { 487 subDiv.addContent(getMarkerAnchor("skip-navbar_top")); 488 body.addContent(subDiv); 489 body.addContent(HtmlConstants.END_OF_TOP_NAVBAR); 490 } else { 491 subDiv.addContent(getMarkerAnchor("skip-navbar_bottom")); 492 body.addContent(subDiv); 493 body.addContent(HtmlConstants.END_OF_BOTTOM_NAVBAR); 494 } 495 } 496 } 497 498 /** 499 * Get the word "NEXT" to indicate that no link is available. Override 500 * this method to customize next link. 501 * 502 * @return a content tree for the link 503 */ 504 protected Content getNavLinkNext() { 505 return getNavLinkNext(null); 506 } 507 508 /** 509 * Get the word "PREV" to indicate that no link is available. Override 510 * this method to customize prev link. 511 * 512 * @return a content tree for the link 513 */ 514 protected Content getNavLinkPrevious() { 515 return getNavLinkPrevious(null); 516 } 517 518 /** 519 * Do nothing. This is the default method. 520 */ 521 protected void addSummaryDetailLinks(Content navDiv) { 522 } 523 524 /** 525 * Get link to the "overview-summary.html" page. 526 * 527 * @return a content tree for the link 528 */ 529 protected Content getNavLinkContents() { 530 Content linkContent = getHyperLink(pathToRoot.resolve(DocPaths.OVERVIEW_SUMMARY), 531 overviewLabel, "", ""); 532 Content li = HtmlTree.LI(linkContent); 533 return li; 534 } 535 536 /** 537 * Get link to the "package-summary.html" page for the package passed. 538 * 539 * @param pkg Package to which link will be generated 540 * @return a content tree for the link 541 */ 542 protected Content getNavLinkPackage(PackageDoc pkg) { 543 Content linkContent = getPackageLink(pkg, 544 packageLabel); 545 Content li = HtmlTree.LI(linkContent); 546 return li; 547 } 548 549 /** 550 * Get the word "Package" , to indicate that link is not available here. 551 * 552 * @return a content tree for the link 553 */ 554 protected Content getNavLinkPackage() { 555 Content li = HtmlTree.LI(packageLabel); 556 return li; 557 } 558 559 /** 560 * Get the word "Use", to indicate that link is not available. 561 * 562 * @return a content tree for the link 563 */ 564 protected Content getNavLinkClassUse() { 565 Content li = HtmlTree.LI(useLabel); 566 return li; 567 } 568 569 /** 570 * Get link for previous file. 571 * 572 * @param prev File name for the prev link 573 * @return a content tree for the link 574 */ 575 public Content getNavLinkPrevious(DocPath prev) { 576 Content li; 577 if (prev != null) { 578 li = HtmlTree.LI(getHyperLink(prev, prevLabel, "", "")); 579 } 580 else 581 li = HtmlTree.LI(prevLabel); 582 return li; 583 } 584 585 /** 586 * Get link for next file. If next is null, just print the label 587 * without linking it anywhere. 588 * 589 * @param next File name for the next link 590 * @return a content tree for the link 591 */ 592 public Content getNavLinkNext(DocPath next) { 593 Content li; 594 if (next != null) { 595 li = HtmlTree.LI(getHyperLink(next, nextLabel, "", "")); 596 } 597 else 598 li = HtmlTree.LI(nextLabel); 599 return li; 600 } 601 602 /** 603 * Get "FRAMES" link, to switch to the frame version of the output. 604 * 605 * @param link File to be linked, "index.html" 606 * @return a content tree for the link 607 */ 608 protected Content getNavShowLists(DocPath link) { 609 DocLink dl = new DocLink(link, path.getPath(), null); 610 Content framesContent = getHyperLink(dl, framesLabel, "", "_top"); 611 Content li = HtmlTree.LI(framesContent); 612 return li; 613 } 614 615 /** 616 * Get "FRAMES" link, to switch to the frame version of the output. 617 * 618 * @return a content tree for the link 619 */ 620 protected Content getNavShowLists() { 621 return getNavShowLists(pathToRoot.resolve(DocPaths.INDEX)); 622 } 623 624 /** 625 * Get "NO FRAMES" link, to switch to the non-frame version of the output. 626 * 627 * @param link File to be linked 628 * @return a content tree for the link 629 */ 630 protected Content getNavHideLists(DocPath link) { 631 Content noFramesContent = getHyperLink(link, noframesLabel, "", "_top"); 632 Content li = HtmlTree.LI(noFramesContent); 633 return li; 634 } 635 636 /** 637 * Get "Tree" link in the navigation bar. If there is only one package 638 * specified on the command line, then the "Tree" link will be to the 639 * only "package-tree.html" file otherwise it will be to the 640 * "overview-tree.html" file. 641 * 642 * @return a content tree for the link 643 */ 644 protected Content getNavLinkTree() { 645 Content treeLinkContent; 646 PackageDoc[] packages = configuration.root.specifiedPackages(); 647 if (packages.length == 1 && configuration.root.specifiedClasses().length == 0) { 648 treeLinkContent = getHyperLink(pathString(packages[0], 649 DocPaths.PACKAGE_TREE), treeLabel, 650 "", ""); 651 } else { 652 treeLinkContent = getHyperLink(pathToRoot.resolve(DocPaths.OVERVIEW_TREE), 653 treeLabel, "", ""); 654 } 655 Content li = HtmlTree.LI(treeLinkContent); 656 return li; 657 } 658 659 /** 660 * Get the overview tree link for the main tree. 661 * 662 * @param label the label for the link 663 * @return a content tree for the link 664 */ 665 protected Content getNavLinkMainTree(String label) { 666 Content mainTreeContent = getHyperLink(pathToRoot.resolve(DocPaths.OVERVIEW_TREE), 667 new StringContent(label)); 668 Content li = HtmlTree.LI(mainTreeContent); 669 return li; 670 } 671 672 /** 673 * Get the word "Class", to indicate that class link is not available. 674 * 675 * @return a content tree for the link 676 */ 677 protected Content getNavLinkClass() { 678 Content li = HtmlTree.LI(classLabel); 679 return li; 680 } 681 682 /** 683 * Get "Deprecated" API link in the navigation bar. 684 * 685 * @return a content tree for the link 686 */ 687 protected Content getNavLinkDeprecated() { 688 Content linkContent = getHyperLink(pathToRoot.resolve(DocPaths.DEPRECATED_LIST), 689 deprecatedLabel, "", ""); 690 Content li = HtmlTree.LI(linkContent); 691 return li; 692 } 693 694 /** 695 * Get link for generated index. If the user has used "-splitindex" 696 * command line option, then link to file "index-files/index-1.html" is 697 * generated otherwise link to file "index-all.html" is generated. 698 * 699 * @return a content tree for the link 700 */ 701 protected Content getNavLinkClassIndex() { 702 Content allClassesContent = getHyperLink(pathToRoot.resolve( 703 DocPaths.ALLCLASSES_NOFRAME), 704 allclassesLabel, "", ""); 705 Content li = HtmlTree.LI(allClassesContent); 706 return li; 707 } 708 709 /** 710 * Get link for generated class index. 711 * 712 * @return a content tree for the link 713 */ 714 protected Content getNavLinkIndex() { 715 Content linkContent = getHyperLink(pathToRoot.resolve( 716 (configuration.splitindex 717 ? DocPaths.INDEX_FILES.resolve(DocPaths.indexN(1)) 718 : DocPaths.INDEX_ALL)), 719 indexLabel, "", ""); 720 Content li = HtmlTree.LI(linkContent); 721 return li; 722 } 723 724 /** 725 * Get help file link. If user has provided a help file, then generate a 726 * link to the user given file, which is already copied to current or 727 * destination directory. 728 * 729 * @return a content tree for the link 730 */ 731 protected Content getNavLinkHelp() { 732 String helpfile = configuration.helpfile; 733 DocPath helpfilenm; 734 if (helpfile.isEmpty()) { 735 helpfilenm = DocPaths.HELP_DOC; 736 } else { 737 DocFile file = DocFile.createFileForInput(configuration, helpfile); 738 helpfilenm = DocPath.create(file.getName()); 739 } 740 Content linkContent = getHyperLink(pathToRoot.resolve(helpfilenm), 741 helpLabel, "", ""); 742 Content li = HtmlTree.LI(linkContent); 743 return li; 744 } 745 746 /** 747 * Get summary table header. 748 * 749 * @param header the header for the table 750 * @param scope the scope of the headers 751 * @return a content tree for the header 752 */ 753 public Content getSummaryTableHeader(String[] header, String scope) { 754 Content tr = new HtmlTree(HtmlTag.TR); 755 int size = header.length; 756 Content tableHeader; 757 if (size == 1) { 758 tableHeader = new StringContent(header[0]); 759 tr.addContent(HtmlTree.TH(HtmlStyle.colOne, scope, tableHeader)); 760 return tr; 761 } 762 for (int i = 0; i < size; i++) { 763 tableHeader = new StringContent(header[i]); 764 if(i == 0) 765 tr.addContent(HtmlTree.TH(HtmlStyle.colFirst, scope, tableHeader)); 766 else if(i == (size - 1)) 767 tr.addContent(HtmlTree.TH(HtmlStyle.colLast, scope, tableHeader)); 768 else 769 tr.addContent(HtmlTree.TH(scope, tableHeader)); 770 } 771 return tr; 772 } 773 774 /** 775 * Get table caption. 776 * 777 * @param rawText the caption for the table which could be raw Html 778 * @return a content tree for the caption 779 */ 780 public Content getTableCaption(String rawText) { 781 Content title = new RawHtml(rawText); 782 Content captionSpan = HtmlTree.SPAN(title); 783 Content space = getSpace(); 784 Content tabSpan = HtmlTree.SPAN(HtmlStyle.tabEnd, space); 785 Content caption = HtmlTree.CAPTION(captionSpan); 786 caption.addContent(tabSpan); 787 return caption; 788 } 789 790 /** 791 * Get the marker anchor which will be added to the documentation tree. 792 * 793 * @param anchorName the anchor name attribute 794 * @return a content tree for the marker anchor 795 */ 796 public Content getMarkerAnchor(String anchorName) { 797 return getMarkerAnchor(anchorName, null); 798 } 799 800 /** 801 * Get the marker anchor which will be added to the documentation tree. 802 * 803 * @param anchorName the anchor name attribute 804 * @param anchorContent the content that should be added to the anchor 805 * @return a content tree for the marker anchor 806 */ 807 public Content getMarkerAnchor(String anchorName, Content anchorContent) { 808 if (anchorContent == null) 809 anchorContent = new Comment(" "); 810 Content markerAnchor = HtmlTree.A_NAME(anchorName, anchorContent); 811 return markerAnchor; 812 } 813 814 /** 815 * Returns a packagename content. 816 * 817 * @param packageDoc the package to check 818 * @return package name content 819 */ 820 public Content getPackageName(PackageDoc packageDoc) { 821 return packageDoc == null || packageDoc.name().length() == 0 ? 822 defaultPackageLabel : 823 getPackageLabel(packageDoc.name()); 824 } 825 826 /** 827 * Returns a package name label. 828 * 829 * @param packageName the package name 830 * @return the package name content 831 */ 832 public Content getPackageLabel(String packageName) { 833 return new StringContent(packageName); 834 } 835 836 /** 837 * Add package deprecation information to the documentation tree 838 * 839 * @param deprPkgs list of deprecated packages 840 * @param headingKey the caption for the deprecated package table 841 * @param tableSummary the summary for the deprecated package table 842 * @param tableHeader table headers for the deprecated package table 843 * @param contentTree the content tree to which the deprecated package table will be added 844 */ 845 protected void addPackageDeprecatedAPI(List<Doc> deprPkgs, String headingKey, 846 String tableSummary, String[] tableHeader, Content contentTree) { 847 if (deprPkgs.size() > 0) { 848 Content table = HtmlTree.TABLE(0, 3, 0, tableSummary, 849 getTableCaption(configuration.getText(headingKey))); 850 table.addContent(getSummaryTableHeader(tableHeader, "col")); 851 Content tbody = new HtmlTree(HtmlTag.TBODY); 852 for (int i = 0; i < deprPkgs.size(); i++) { 853 PackageDoc pkg = (PackageDoc) deprPkgs.get(i); 854 HtmlTree td = HtmlTree.TD(HtmlStyle.colOne, 855 getPackageLink(pkg, getPackageName(pkg))); 856 if (pkg.tags("deprecated").length > 0) { 857 addInlineDeprecatedComment(pkg, pkg.tags("deprecated")[0], td); 858 } 859 HtmlTree tr = HtmlTree.TR(td); 860 if (i % 2 == 0) { 861 tr.addStyle(HtmlStyle.altColor); 862 } else { 863 tr.addStyle(HtmlStyle.rowColor); 864 } 865 tbody.addContent(tr); 866 } 867 table.addContent(tbody); 868 Content li = HtmlTree.LI(HtmlStyle.blockList, table); 869 Content ul = HtmlTree.UL(HtmlStyle.blockList, li); 870 contentTree.addContent(ul); 871 } 872 } 873 874 /** 875 * Return the path to the class page for a classdoc. 876 * 877 * @param cd Class to which the path is requested. 878 * @param name Name of the file(doesn't include path). 879 */ 880 protected DocPath pathString(ClassDoc cd, DocPath name) { 881 return pathString(cd.containingPackage(), name); 882 } 883 884 /** 885 * Return path to the given file name in the given package. So if the name 886 * passed is "Object.html" and the name of the package is "java.lang", and 887 * if the relative path is "../.." then returned string will be 888 * "../../java/lang/Object.html" 889 * 890 * @param pd Package in which the file name is assumed to be. 891 * @param name File name, to which path string is. 892 */ 893 protected DocPath pathString(PackageDoc pd, DocPath name) { 894 return pathToRoot.resolve(DocPath.forPackage(pd).resolve(name)); 895 } 896 897 /** 898 * Return the link to the given package. 899 * 900 * @param pkg the package to link to. 901 * @param label the label for the link. 902 * @param isStrong true if the label should be strong. 903 * @return the link to the given package. 904 */ 905 public String getPackageLinkString(PackageDoc pkg, String label, 906 boolean isStrong) { 907 return getPackageLinkString(pkg, label, isStrong, ""); 908 } 909 910 /** 911 * Return the link to the given package. 912 * 913 * @param pkg the package to link to. 914 * @param label the label for the link. 915 * @param isStrong true if the label should be strong. 916 * @param style the font of the package link label. 917 * @return the link to the given package. 918 */ 919 public String getPackageLinkString(PackageDoc pkg, String label, boolean isStrong, 920 String style) { 921 boolean included = pkg != null && pkg.isIncluded(); 922 if (! included) { 923 PackageDoc[] packages = configuration.packages; 924 for (int i = 0; i < packages.length; i++) { 925 if (packages[i].equals(pkg)) { 926 included = true; 927 break; 928 } 929 } 930 } 931 if (included || pkg == null) { 932 return getHyperLinkString(pathString(pkg, DocPaths.PACKAGE_SUMMARY), 933 label, isStrong, style); 934 } else { 935 DocLink crossPkgLink = getCrossPackageLink(Util.getPackageName(pkg)); 936 if (crossPkgLink != null) { 937 return getHyperLinkString(crossPkgLink, label, isStrong, style); 938 } else { 939 return label; 940 } 941 } 942 } 943 944 /** 945 * Return the link to the given package. 946 * 947 * @param pkg the package to link to. 948 * @param label the label for the link. 949 * @return a content tree for the package link. 950 */ 951 public Content getPackageLink(PackageDoc pkg, Content label) { 952 boolean included = pkg != null && pkg.isIncluded(); 953 if (! included) { 954 PackageDoc[] packages = configuration.packages; 955 for (int i = 0; i < packages.length; i++) { 956 if (packages[i].equals(pkg)) { 957 included = true; 958 break; 959 } 960 } 961 } 962 if (included || pkg == null) { 963 return getHyperLink(pathString(pkg, DocPaths.PACKAGE_SUMMARY), 964 label); 965 } else { 966 DocLink crossPkgLink = getCrossPackageLink(Util.getPackageName(pkg)); 967 if (crossPkgLink != null) { 968 return getHyperLink(crossPkgLink, label); 969 } else { 970 return label; 971 } 972 } 973 } 974 975 public String italicsClassName(ClassDoc cd, boolean qual) { 976 String name = (qual)? cd.qualifiedName(): cd.name(); 977 return (cd.isInterface())? italicsText(name): name; 978 } 979 980 /** 981 * Add the link to the content tree. 982 * 983 * @param doc program element doc for which the link will be added 984 * @param label label for the link 985 * @param htmltree the content tree to which the link will be added 986 */ 987 public void addSrcLink(ProgramElementDoc doc, Content label, Content htmltree) { 988 if (doc == null) { 989 return; 990 } 991 ClassDoc cd = doc.containingClass(); 992 if (cd == null) { 993 //d must be a class doc since in has no containing class. 994 cd = (ClassDoc) doc; 995 } 996 DocPath href = pathToRoot 997 .resolve(DocPaths.SOURCE_OUTPUT) 998 .resolve(DocPath.forClass(cd)); 999 Content linkContent = getHyperLink(href.fragment(SourceToHTMLConverter.getAnchorName(doc)), label, "", ""); 1000 htmltree.addContent(linkContent); 1001 } 1002 1003 /** 1004 * Return the link to the given class. 1005 * 1006 * @param linkInfo the information about the link. 1007 * 1008 * @return the link for the given class. 1009 */ 1010 public String getLink(LinkInfoImpl linkInfo) { 1011 LinkFactoryImpl factory = new LinkFactoryImpl(this); 1012 String link = factory.getLinkOutput(linkInfo).toString(); 1013 displayLength += linkInfo.displayLength; 1014 return link; 1015 } 1016 1017 /** 1018 * Return the type parameters for the given class. 1019 * 1020 * @param linkInfo the information about the link. 1021 * @return the type for the given class. 1022 */ 1023 public String getTypeParameterLinks(LinkInfoImpl linkInfo) { 1024 LinkFactoryImpl factory = new LinkFactoryImpl(this); 1025 return factory.getTypeParameterLinks(linkInfo, false).toString(); 1026 } 1027 1028 /************************************************************* 1029 * Return a class cross link to external class documentation. 1030 * The name must be fully qualified to determine which package 1031 * the class is in. The -link option does not allow users to 1032 * link to external classes in the "default" package. 1033 * 1034 * @param qualifiedClassName the qualified name of the external class. 1035 * @param refMemName the name of the member being referenced. This should 1036 * be null or empty string if no member is being referenced. 1037 * @param label the label for the external link. 1038 * @param strong true if the link should be strong. 1039 * @param style the style of the link. 1040 * @param code true if the label should be code font. 1041 */ 1042 public String getCrossClassLink(String qualifiedClassName, String refMemName, 1043 String label, boolean strong, String style, 1044 boolean code) { 1045 String className = ""; 1046 String packageName = qualifiedClassName == null ? "" : qualifiedClassName; 1047 int periodIndex; 1048 while ((periodIndex = packageName.lastIndexOf('.')) != -1) { 1049 className = packageName.substring(periodIndex + 1, packageName.length()) + 1050 (className.length() > 0 ? "." + className : ""); 1051 String defaultLabel = code ? codeText(className) : className; 1052 packageName = packageName.substring(0, periodIndex); 1053 if (getCrossPackageLink(packageName) != null) { 1054 //The package exists in external documentation, so link to the external 1055 //class (assuming that it exists). This is definitely a limitation of 1056 //the -link option. There are ways to determine if an external package 1057 //exists, but no way to determine if the external class exists. We just 1058 //have to assume that it does. 1059 DocLink link = configuration.extern.getExternalLink(packageName, pathToRoot, 1060 className + ".html", refMemName); 1061 return getHyperLinkString(link, 1062 (label == null) || label.length() == 0 ? defaultLabel : label, 1063 1064 1065 strong, style, 1066 configuration.getText("doclet.Href_Class_Or_Interface_Title", packageName), 1067 ""); 1068 } 1069 } 1070 return null; 1071 } 1072 1073 public boolean isClassLinkable(ClassDoc cd) { 1074 if (cd.isIncluded()) { 1075 return configuration.isGeneratedDoc(cd); 1076 } 1077 return configuration.extern.isExternal(cd); 1078 } 1079 1080 public DocLink getCrossPackageLink(String pkgName) { 1081 return configuration.extern.getExternalLink(pkgName, pathToRoot, 1082 DocPaths.PACKAGE_SUMMARY.getPath()); 1083 } 1084 1085 /** 1086 * Get the class link. 1087 * 1088 * @param context the id of the context where the link will be added 1089 * @param cd the class doc to link to 1090 * @return a content tree for the link 1091 */ 1092 public Content getQualifiedClassLink(int context, ClassDoc cd) { 1093 return new RawHtml(getLink(new LinkInfoImpl(configuration, context, cd, 1094 configuration.getClassName(cd), ""))); 1095 } 1096 1097 /** 1098 * Add the class link. 1099 * 1100 * @param context the id of the context where the link will be added 1101 * @param cd the class doc to link to 1102 * @param contentTree the content tree to which the link will be added 1103 */ 1104 public void addPreQualifiedClassLink(int context, ClassDoc cd, Content contentTree) { 1105 addPreQualifiedClassLink(context, cd, false, contentTree); 1106 } 1107 1108 /** 1109 * Retrieve the class link with the package portion of the label in 1110 * plain text. If the qualifier is excluded, it will not be included in the 1111 * link label. 1112 * 1113 * @param cd the class to link to. 1114 * @param isStrong true if the link should be strong. 1115 * @return the link with the package portion of the label in plain text. 1116 */ 1117 public String getPreQualifiedClassLink(int context, 1118 ClassDoc cd, boolean isStrong) { 1119 String classlink = ""; 1120 PackageDoc pd = cd.containingPackage(); 1121 if(pd != null && ! configuration.shouldExcludeQualifier(pd.name())) { 1122 classlink = getPkgName(cd); 1123 } 1124 classlink += getLink(new LinkInfoImpl(configuration, 1125 context, cd, cd.name(), isStrong)); 1126 return classlink; 1127 } 1128 1129 /** 1130 * Add the class link with the package portion of the label in 1131 * plain text. If the qualifier is excluded, it will not be included in the 1132 * link label. 1133 * 1134 * @param context the id of the context where the link will be added 1135 * @param cd the class to link to 1136 * @param isStrong true if the link should be strong 1137 * @param contentTree the content tree to which the link with be added 1138 */ 1139 public void addPreQualifiedClassLink(int context, 1140 ClassDoc cd, boolean isStrong, Content contentTree) { 1141 PackageDoc pd = cd.containingPackage(); 1142 if(pd != null && ! configuration.shouldExcludeQualifier(pd.name())) { 1143 contentTree.addContent(getPkgName(cd)); 1144 } 1145 contentTree.addContent(new RawHtml(getLink(new LinkInfoImpl(configuration, 1146 context, cd, cd.name(), isStrong)))); 1147 } 1148 1149 /** 1150 * Add the class link, with only class name as the strong link and prefixing 1151 * plain package name. 1152 * 1153 * @param context the id of the context where the link will be added 1154 * @param cd the class to link to 1155 * @param contentTree the content tree to which the link with be added 1156 */ 1157 public void addPreQualifiedStrongClassLink(int context, ClassDoc cd, Content contentTree) { 1158 addPreQualifiedClassLink(context, cd, true, contentTree); 1159 } 1160 1161 /** 1162 * Get the link for the given member. 1163 * 1164 * @param context the id of the context where the link will be added 1165 * @param doc the member being linked to 1166 * @param label the label for the link 1167 * @return a content tree for the doc link 1168 */ 1169 public Content getDocLink(int context, MemberDoc doc, String label) { 1170 return getDocLink(context, doc.containingClass(), doc, label); 1171 } 1172 1173 /** 1174 * Return the link for the given member. 1175 * 1176 * @param context the id of the context where the link will be printed. 1177 * @param doc the member being linked to. 1178 * @param label the label for the link. 1179 * @param strong true if the link should be strong. 1180 * @return the link for the given member. 1181 */ 1182 public String getDocLink(int context, MemberDoc doc, String label, 1183 boolean strong) { 1184 return getDocLink(context, doc.containingClass(), doc, label, strong); 1185 } 1186 1187 /** 1188 * Return the link for the given member. 1189 * 1190 * @param context the id of the context where the link will be printed. 1191 * @param classDoc the classDoc that we should link to. This is not 1192 * necessarily equal to doc.containingClass(). We may be 1193 * inheriting comments. 1194 * @param doc the member being linked to. 1195 * @param label the label for the link. 1196 * @param strong true if the link should be strong. 1197 * @return the link for the given member. 1198 */ 1199 public String getDocLink(int context, ClassDoc classDoc, MemberDoc doc, 1200 String label, boolean strong) { 1201 if (! (doc.isIncluded() || 1202 Util.isLinkable(classDoc, configuration))) { 1203 return label; 1204 } else if (doc instanceof ExecutableMemberDoc) { 1205 ExecutableMemberDoc emd = (ExecutableMemberDoc)doc; 1206 return getLink(new LinkInfoImpl(configuration, context, classDoc, 1207 getAnchor(emd), label, strong)); 1208 } else if (doc instanceof MemberDoc) { 1209 return getLink(new LinkInfoImpl(configuration, context, classDoc, 1210 doc.name(), label, strong)); 1211 } else { 1212 return label; 1213 } 1214 } 1215 1216 /** 1217 * Return the link for the given member. 1218 * 1219 * @param context the id of the context where the link will be added 1220 * @param classDoc the classDoc that we should link to. This is not 1221 * necessarily equal to doc.containingClass(). We may be 1222 * inheriting comments 1223 * @param doc the member being linked to 1224 * @param label the label for the link 1225 * @return the link for the given member 1226 */ 1227 public Content getDocLink(int context, ClassDoc classDoc, MemberDoc doc, 1228 String label) { 1229 if (! (doc.isIncluded() || 1230 Util.isLinkable(classDoc, configuration))) { 1231 return new StringContent(label); 1232 } else if (doc instanceof ExecutableMemberDoc) { 1233 ExecutableMemberDoc emd = (ExecutableMemberDoc)doc; 1234 return new RawHtml(getLink(new LinkInfoImpl(configuration, context, classDoc, 1235 getAnchor(emd), label, false))); 1236 } else if (doc instanceof MemberDoc) { 1237 return new RawHtml(getLink(new LinkInfoImpl(configuration, context, classDoc, 1238 doc.name(), label, false))); 1239 } else { 1240 return new StringContent(label); 1241 } 1242 } 1243 1244 public String getAnchor(ExecutableMemberDoc emd) { 1245 StringBuilder signature = new StringBuilder(emd.signature()); 1246 StringBuilder signatureParsed = new StringBuilder(); 1247 int counter = 0; 1248 for (int i = 0; i < signature.length(); i++) { 1249 char c = signature.charAt(i); 1250 if (c == '<') { 1251 counter++; 1252 } else if (c == '>') { 1253 counter--; 1254 } else if (counter == 0) { 1255 signatureParsed.append(c); 1256 } 1257 } 1258 return emd.name() + signatureParsed.toString(); 1259 } 1260 1261 public String seeTagToString(SeeTag see) { 1262 String tagName = see.name(); 1263 if (! (tagName.startsWith("@link") || tagName.equals("@see"))) { 1264 return ""; 1265 } 1266 1267 String seetext = replaceDocRootDir(see.text()); 1268 1269 //Check if @see is an href or "string" 1270 if (seetext.startsWith("<") || seetext.startsWith("\"")) { 1271 return seetext; 1272 } 1273 1274 boolean plain = tagName.equalsIgnoreCase("@linkplain"); 1275 String label = plainOrCodeText(plain, see.label()); 1276 1277 //The text from the @see tag. We will output this text when a label is not specified. 1278 String text = plainOrCodeText(plain, seetext); 1279 1280 ClassDoc refClass = see.referencedClass(); 1281 String refClassName = see.referencedClassName(); 1282 MemberDoc refMem = see.referencedMember(); 1283 String refMemName = see.referencedMemberName(); 1284 1285 if (refClass == null) { 1286 //@see is not referencing an included class 1287 PackageDoc refPackage = see.referencedPackage(); 1288 if (refPackage != null && refPackage.isIncluded()) { 1289 //@see is referencing an included package 1290 if (label.isEmpty()) 1291 label = plainOrCodeText(plain, refPackage.name()); 1292 return getPackageLinkString(refPackage, label, false); 1293 } else { 1294 //@see is not referencing an included class or package. Check for cross links. 1295 String classCrossLink; 1296 DocLink packageCrossLink = getCrossPackageLink(refClassName); 1297 if (packageCrossLink != null) { 1298 //Package cross link found 1299 return getHyperLinkString(packageCrossLink, 1300 (label.isEmpty() ? text : label), false); 1301 } else if ((classCrossLink = getCrossClassLink(refClassName, 1302 refMemName, label, false, "", !plain)) != null) { 1303 //Class cross link found (possibly to a member in the class) 1304 return classCrossLink; 1305 } else { 1306 //No cross link found so print warning 1307 configuration.getDocletSpecificMsg().warning(see.position(), "doclet.see.class_or_package_not_found", 1308 tagName, seetext); 1309 return (label.isEmpty() ? text: label); 1310 } 1311 } 1312 } else if (refMemName == null) { 1313 // Must be a class reference since refClass is not null and refMemName is null. 1314 if (label.isEmpty()) { 1315 label = plainOrCodeText(plain, refClass.name()); 1316 } 1317 return getLink(new LinkInfoImpl(configuration, refClass, label)); 1318 } else if (refMem == null) { 1319 // Must be a member reference since refClass is not null and refMemName is not null. 1320 // However, refMem is null, so this referenced member does not exist. 1321 return (label.isEmpty() ? text: label); 1322 } else { 1323 // Must be a member reference since refClass is not null and refMemName is not null. 1324 // refMem is not null, so this @see tag must be referencing a valid member. 1325 ClassDoc containing = refMem.containingClass(); 1326 if (see.text().trim().startsWith("#") && 1327 ! (containing.isPublic() || 1328 Util.isLinkable(containing, configuration))) { 1329 // Since the link is relative and the holder is not even being 1330 // documented, this must be an inherited link. Redirect it. 1331 // The current class either overrides the referenced member or 1332 // inherits it automatically. 1333 if (this instanceof ClassWriterImpl) { 1334 containing = ((ClassWriterImpl) this).getClassDoc(); 1335 } else if (!containing.isPublic()){ 1336 configuration.getDocletSpecificMsg().warning( 1337 see.position(), "doclet.see.class_or_package_not_accessible", 1338 tagName, containing.qualifiedName()); 1339 } else { 1340 configuration.getDocletSpecificMsg().warning( 1341 see.position(), "doclet.see.class_or_package_not_found", 1342 tagName, seetext); 1343 } 1344 } 1345 if (configuration.currentcd != containing) { 1346 refMemName = containing.name() + "." + refMemName; 1347 } 1348 if (refMem instanceof ExecutableMemberDoc) { 1349 if (refMemName.indexOf('(') < 0) { 1350 refMemName += ((ExecutableMemberDoc)refMem).signature(); 1351 } 1352 } 1353 1354 text = plainOrCodeText(plain, Util.escapeHtmlChars(refMemName)); 1355 1356 return getDocLink(LinkInfoImpl.CONTEXT_SEE_TAG, containing, 1357 refMem, (label.isEmpty() ? text: label), false); 1358 } 1359 } 1360 1361 private String plainOrCodeText(boolean plain, String text) { 1362 return (plain || text.isEmpty()) ? text : codeText(text); 1363 } 1364 1365 /** 1366 * Add the inline comment. 1367 * 1368 * @param doc the doc for which the inline comment will be added 1369 * @param tag the inline tag to be added 1370 * @param htmltree the content tree to which the comment will be added 1371 */ 1372 public void addInlineComment(Doc doc, Tag tag, Content htmltree) { 1373 addCommentTags(doc, tag.inlineTags(), false, false, htmltree); 1374 } 1375 1376 /** 1377 * Add the inline deprecated comment. 1378 * 1379 * @param doc the doc for which the inline deprecated comment will be added 1380 * @param tag the inline tag to be added 1381 * @param htmltree the content tree to which the comment will be added 1382 */ 1383 public void addInlineDeprecatedComment(Doc doc, Tag tag, Content htmltree) { 1384 addCommentTags(doc, tag.inlineTags(), true, false, htmltree); 1385 } 1386 1387 /** 1388 * Adds the summary content. 1389 * 1390 * @param doc the doc for which the summary will be generated 1391 * @param htmltree the documentation tree to which the summary will be added 1392 */ 1393 public void addSummaryComment(Doc doc, Content htmltree) { 1394 addSummaryComment(doc, doc.firstSentenceTags(), htmltree); 1395 } 1396 1397 /** 1398 * Adds the summary content. 1399 * 1400 * @param doc the doc for which the summary will be generated 1401 * @param firstSentenceTags the first sentence tags for the doc 1402 * @param htmltree the documentation tree to which the summary will be added 1403 */ 1404 public void addSummaryComment(Doc doc, Tag[] firstSentenceTags, Content htmltree) { 1405 addCommentTags(doc, firstSentenceTags, false, true, htmltree); 1406 } 1407 1408 public void addSummaryDeprecatedComment(Doc doc, Tag tag, Content htmltree) { 1409 addCommentTags(doc, tag.firstSentenceTags(), true, true, htmltree); 1410 } 1411 1412 /** 1413 * Adds the inline comment. 1414 * 1415 * @param doc the doc for which the inline comments will be generated 1416 * @param htmltree the documentation tree to which the inline comments will be added 1417 */ 1418 public void addInlineComment(Doc doc, Content htmltree) { 1419 addCommentTags(doc, doc.inlineTags(), false, false, htmltree); 1420 } 1421 1422 /** 1423 * Adds the comment tags. 1424 * 1425 * @param doc the doc for which the comment tags will be generated 1426 * @param tags the first sentence tags for the doc 1427 * @param depr true if it is deprecated 1428 * @param first true if the first sentence tags should be added 1429 * @param htmltree the documentation tree to which the comment tags will be added 1430 */ 1431 private void addCommentTags(Doc doc, Tag[] tags, boolean depr, 1432 boolean first, Content htmltree) { 1433 if(configuration.nocomment){ 1434 return; 1435 } 1436 Content div; 1437 Content result = new RawHtml(commentTagsToString(null, doc, tags, first)); 1438 if (depr) { 1439 Content italic = HtmlTree.I(result); 1440 div = HtmlTree.DIV(HtmlStyle.block, italic); 1441 htmltree.addContent(div); 1442 } 1443 else { 1444 div = HtmlTree.DIV(HtmlStyle.block, result); 1445 htmltree.addContent(div); 1446 } 1447 if (tags.length == 0) { 1448 htmltree.addContent(getSpace()); 1449 } 1450 } 1451 1452 /** 1453 * Converts inline tags and text to text strings, expanding the 1454 * inline tags along the way. Called wherever text can contain 1455 * an inline tag, such as in comments or in free-form text arguments 1456 * to non-inline tags. 1457 * 1458 * @param holderTag specific tag where comment resides 1459 * @param doc specific doc where comment resides 1460 * @param tags array of text tags and inline tags (often alternating) 1461 * present in the text of interest for this doc 1462 * @param isFirstSentence true if text is first sentence 1463 */ 1464 public String commentTagsToString(Tag holderTag, Doc doc, Tag[] tags, 1465 boolean isFirstSentence) { 1466 StringBuilder result = new StringBuilder(); 1467 boolean textTagChange = false; 1468 // Array of all possible inline tags for this javadoc run 1469 configuration.tagletManager.checkTags(doc, tags, true); 1470 for (int i = 0; i < tags.length; i++) { 1471 Tag tagelem = tags[i]; 1472 String tagName = tagelem.name(); 1473 if (tagelem instanceof SeeTag) { 1474 result.append(seeTagToString((SeeTag)tagelem)); 1475 } else if (! tagName.equals("Text")) { 1476 int originalLength = result.length(); 1477 TagletOutput output = TagletWriter.getInlineTagOuput( 1478 configuration.tagletManager, holderTag, 1479 tagelem, getTagletWriterInstance(isFirstSentence)); 1480 result.append(output == null ? "" : output.toString()); 1481 if (originalLength == 0 && isFirstSentence && tagelem.name().equals("@inheritDoc") && result.length() > 0) { 1482 break; 1483 } else if (configuration.docrootparent.length() > 0 && 1484 tagelem.name().equals("@docRoot") && 1485 ((tags[i + 1]).text()).startsWith("/..")) { 1486 //If Xdocrootparent switch ON, set the flag to remove the /.. occurance after 1487 //{@docRoot} tag in the very next Text tag. 1488 textTagChange = true; 1489 continue; 1490 } else { 1491 continue; 1492 } 1493 } else { 1494 String text = tagelem.text(); 1495 //If Xdocrootparent switch ON, remove the /.. occurance after {@docRoot} tag. 1496 if (textTagChange) { 1497 text = text.replaceFirst("/..", ""); 1498 textTagChange = false; 1499 } 1500 //This is just a regular text tag. The text may contain html links (<a>) 1501 //or inline tag {@docRoot}, which will be handled as special cases. 1502 text = redirectRelativeLinks(tagelem.holder(), text); 1503 1504 // Replace @docRoot only if not represented by an instance of DocRootTaglet, 1505 // that is, only if it was not present in a source file doc comment. 1506 // This happens when inserted by the doclet (a few lines 1507 // above in this method). [It might also happen when passed in on the command 1508 // line as a text argument to an option (like -header).] 1509 text = replaceDocRootDir(text); 1510 if (isFirstSentence) { 1511 text = removeNonInlineHtmlTags(text); 1512 } 1513 StringTokenizer lines = new StringTokenizer(text, "\r\n", true); 1514 StringBuilder textBuff = new StringBuilder(); 1515 while (lines.hasMoreTokens()) { 1516 StringBuilder line = new StringBuilder(lines.nextToken()); 1517 Util.replaceTabs(configuration, line); 1518 textBuff.append(line.toString()); 1519 } 1520 result.append(textBuff); 1521 } 1522 } 1523 return result.toString(); 1524 } 1525 1526 /** 1527 * Return true if relative links should not be redirected. 1528 * 1529 * @return Return true if a relative link should not be redirected. 1530 */ 1531 private boolean shouldNotRedirectRelativeLinks() { 1532 return this instanceof AnnotationTypeWriter || 1533 this instanceof ClassWriter || 1534 this instanceof PackageSummaryWriter; 1535 } 1536 1537 /** 1538 * Suppose a piece of documentation has a relative link. When you copy 1539 * that documentation to another place such as the index or class-use page, 1540 * that relative link will no longer work. We should redirect those links 1541 * so that they will work again. 1542 * <p> 1543 * Here is the algorithm used to fix the link: 1544 * <p> 1545 * {@literal <relative link> => docRoot + <relative path to file> + <relative link> } 1546 * <p> 1547 * For example, suppose com.sun.javadoc.RootDoc has this link: 1548 * {@literal <a href="package-summary.html">The package Page</a> } 1549 * <p> 1550 * If this link appeared in the index, we would redirect 1551 * the link like this: 1552 * 1553 * {@literal <a href="./com/sun/javadoc/package-summary.html">The package Page</a>} 1554 * 1555 * @param doc the Doc object whose documentation is being written. 1556 * @param text the text being written. 1557 * 1558 * @return the text, with all the relative links redirected to work. 1559 */ 1560 private String redirectRelativeLinks(Doc doc, String text) { 1561 if (doc == null || shouldNotRedirectRelativeLinks()) { 1562 return text; 1563 } 1564 1565 DocPath redirectPathFromRoot; 1566 if (doc instanceof ClassDoc) { 1567 redirectPathFromRoot = DocPath.forPackage(((ClassDoc) doc).containingPackage()); 1568 } else if (doc instanceof MemberDoc) { 1569 redirectPathFromRoot = DocPath.forPackage(((MemberDoc) doc).containingPackage()); 1570 } else if (doc instanceof PackageDoc) { 1571 redirectPathFromRoot = DocPath.forPackage((PackageDoc) doc); 1572 } else { 1573 return text; 1574 } 1575 1576 //Redirect all relative links. 1577 int end, begin = text.toLowerCase().indexOf("<a"); 1578 if(begin >= 0){ 1579 StringBuilder textBuff = new StringBuilder(text); 1580 1581 while(begin >=0){ 1582 if (textBuff.length() > begin + 2 && ! Character.isWhitespace(textBuff.charAt(begin+2))) { 1583 begin = textBuff.toString().toLowerCase().indexOf("<a", begin + 1); 1584 continue; 1585 } 1586 1587 begin = textBuff.indexOf("=", begin) + 1; 1588 end = textBuff.indexOf(">", begin +1); 1589 if(begin == 0){ 1590 //Link has no equal symbol. 1591 configuration.root.printWarning( 1592 doc.position(), 1593 configuration.getText("doclet.malformed_html_link_tag", text)); 1594 break; 1595 } 1596 if (end == -1) { 1597 //Break without warning. This <a> tag is not necessarily malformed. The text 1598 //might be missing '>' character because the href has an inline tag. 1599 break; 1600 } 1601 if (textBuff.substring(begin, end).indexOf("\"") != -1){ 1602 begin = textBuff.indexOf("\"", begin) + 1; 1603 end = textBuff.indexOf("\"", begin +1); 1604 if (begin == 0 || end == -1){ 1605 //Link is missing a quote. 1606 break; 1607 } 1608 } 1609 String relativeLink = textBuff.substring(begin, end); 1610 if (!(relativeLink.toLowerCase().startsWith("mailto:") || 1611 relativeLink.toLowerCase().startsWith("http:") || 1612 relativeLink.toLowerCase().startsWith("https:") || 1613 relativeLink.toLowerCase().startsWith("file:"))) { 1614 relativeLink = "{@"+(new DocRootTaglet()).getName() + "}/" 1615 + redirectPathFromRoot.resolve(relativeLink).getPath(); 1616 textBuff.replace(begin, end, relativeLink); 1617 } 1618 begin = textBuff.toString().toLowerCase().indexOf("<a", begin + 1); 1619 } 1620 return textBuff.toString(); 1621 } 1622 return text; 1623 } 1624 1625 public String removeNonInlineHtmlTags(String text) { 1626 if (text.indexOf('<') < 0) { 1627 return text; 1628 } 1629 String noninlinetags[] = { "<ul>", "</ul>", "<ol>", "</ol>", 1630 "<dl>", "</dl>", "<table>", "</table>", 1631 "<tr>", "</tr>", "<td>", "</td>", 1632 "<th>", "</th>", "<p>", "</p>", 1633 "<li>", "</li>", "<dd>", "</dd>", 1634 "<dir>", "</dir>", "<dt>", "</dt>", 1635 "<h1>", "</h1>", "<h2>", "</h2>", 1636 "<h3>", "</h3>", "<h4>", "</h4>", 1637 "<h5>", "</h5>", "<h6>", "</h6>", 1638 "<pre>", "</pre>", "<menu>", "</menu>", 1639 "<listing>", "</listing>", "<hr>", 1640 "<blockquote>", "</blockquote>", 1641 "<center>", "</center>", 1642 "<UL>", "</UL>", "<OL>", "</OL>", 1643 "<DL>", "</DL>", "<TABLE>", "</TABLE>", 1644 "<TR>", "</TR>", "<TD>", "</TD>", 1645 "<TH>", "</TH>", "<P>", "</P>", 1646 "<LI>", "</LI>", "<DD>", "</DD>", 1647 "<DIR>", "</DIR>", "<DT>", "</DT>", 1648 "<H1>", "</H1>", "<H2>", "</H2>", 1649 "<H3>", "</H3>", "<H4>", "</H4>", 1650 "<H5>", "</H5>", "<H6>", "</H6>", 1651 "<PRE>", "</PRE>", "<MENU>", "</MENU>", 1652 "<LISTING>", "</LISTING>", "<HR>", 1653 "<BLOCKQUOTE>", "</BLOCKQUOTE>", 1654 "<CENTER>", "</CENTER>" 1655 }; 1656 for (int i = 0; i < noninlinetags.length; i++) { 1657 text = replace(text, noninlinetags[i], ""); 1658 } 1659 return text; 1660 } 1661 1662 public String replace(String text, String tobe, String by) { 1663 while (true) { 1664 int startindex = text.indexOf(tobe); 1665 if (startindex < 0) { 1666 return text; 1667 } 1668 int endindex = startindex + tobe.length(); 1669 StringBuilder replaced = new StringBuilder(); 1670 if (startindex > 0) { 1671 replaced.append(text.substring(0, startindex)); 1672 } 1673 replaced.append(by); 1674 if (text.length() > endindex) { 1675 replaced.append(text.substring(endindex)); 1676 } 1677 text = replaced.toString(); 1678 } 1679 } 1680 1681 /** 1682 * Returns a link to the stylesheet file. 1683 * 1684 * @return an HtmlTree for the lINK tag which provides the stylesheet location 1685 */ 1686 public HtmlTree getStyleSheetProperties() { 1687 String stylesheetfile = configuration.stylesheetfile; 1688 DocPath stylesheet; 1689 if (stylesheetfile.isEmpty()) { 1690 stylesheet = DocPaths.STYLESHEET; 1691 } else { 1692 DocFile file = DocFile.createFileForInput(configuration, stylesheetfile); 1693 stylesheet = DocPath.create(file.getName()); 1694 } 1695 HtmlTree link = HtmlTree.LINK("stylesheet", "text/css", 1696 pathToRoot.resolve(stylesheet).getPath(), 1697 "Style"); 1698 return link; 1699 } 1700 1701 /** 1702 * Returns a link to the JavaScript file. 1703 * 1704 * @return an HtmlTree for the Script tag which provides the JavaScript location 1705 */ 1706 public HtmlTree getScriptProperties() { 1707 HtmlTree script = HtmlTree.SCRIPT("text/javascript", 1708 pathToRoot.resolve(DocPaths.JAVASCRIPT).getPath()); 1709 return script; 1710 } 1711 1712 /** 1713 * According to 1714 * <cite>The Java™ Language Specification</cite>, 1715 * all the outer classes and static nested classes are core classes. 1716 */ 1717 public boolean isCoreClass(ClassDoc cd) { 1718 return cd.containingClass() == null || cd.isStatic(); 1719 } 1720 1721 /** 1722 * Adds the annotatation types for the given packageDoc. 1723 * 1724 * @param packageDoc the package to write annotations for. 1725 * @param htmltree the documentation tree to which the annotation info will be 1726 * added 1727 */ 1728 public void addAnnotationInfo(PackageDoc packageDoc, Content htmltree) { 1729 addAnnotationInfo(packageDoc, packageDoc.annotations(), htmltree); 1730 } 1731 1732 /** 1733 * Adds the annotatation types for the given doc. 1734 * 1735 * @param doc the package to write annotations for 1736 * @param htmltree the content tree to which the annotation types will be added 1737 */ 1738 public void addAnnotationInfo(ProgramElementDoc doc, Content htmltree) { 1739 addAnnotationInfo(doc, doc.annotations(), htmltree); 1740 } 1741 1742 /** 1743 * Add the annotatation types for the given doc and parameter. 1744 * 1745 * @param indent the number of spaces to indent the parameters. 1746 * @param doc the doc to write annotations for. 1747 * @param param the parameter to write annotations for. 1748 * @param tree the content tree to which the annotation types will be added 1749 */ 1750 public boolean addAnnotationInfo(int indent, Doc doc, Parameter param, 1751 Content tree) { 1752 return addAnnotationInfo(indent, doc, param.annotations(), false, tree); 1753 } 1754 1755 /** 1756 * Adds the annotatation types for the given doc. 1757 * 1758 * @param doc the doc to write annotations for. 1759 * @param descList the array of {@link AnnotationDesc}. 1760 * @param htmltree the documentation tree to which the annotation info will be 1761 * added 1762 */ 1763 private void addAnnotationInfo(Doc doc, AnnotationDesc[] descList, 1764 Content htmltree) { 1765 addAnnotationInfo(0, doc, descList, true, htmltree); 1766 } 1767 1768 /** 1769 * Adds the annotatation types for the given doc. 1770 * 1771 * @param indent the number of extra spaces to indent the annotations. 1772 * @param doc the doc to write annotations for. 1773 * @param descList the array of {@link AnnotationDesc}. 1774 * @param htmltree the documentation tree to which the annotation info will be 1775 * added 1776 */ 1777 private boolean addAnnotationInfo(int indent, Doc doc, 1778 AnnotationDesc[] descList, boolean lineBreak, Content htmltree) { 1779 List<String> annotations = getAnnotations(indent, descList, lineBreak); 1780 if (annotations.size() == 0) { 1781 return false; 1782 } 1783 Content annotationContent; 1784 for (Iterator<String> iter = annotations.iterator(); iter.hasNext();) { 1785 annotationContent = new RawHtml(iter.next()); 1786 htmltree.addContent(annotationContent); 1787 } 1788 return true; 1789 } 1790 1791 /** 1792 * Return the string representations of the annotation types for 1793 * the given doc. 1794 * 1795 * @param indent the number of extra spaces to indent the annotations. 1796 * @param descList the array of {@link AnnotationDesc}. 1797 * @param linkBreak if true, add new line between each member value. 1798 * @return an array of strings representing the annotations being 1799 * documented. 1800 */ 1801 private List<String> getAnnotations(int indent, AnnotationDesc[] descList, boolean linkBreak) { 1802 List<String> results = new ArrayList<String>(); 1803 StringBuilder annotation; 1804 for (int i = 0; i < descList.length; i++) { 1805 AnnotationTypeDoc annotationDoc = descList[i].annotationType(); 1806 // If an annotation is not documented, do not add it to the list. If 1807 // the annotation is of a repeatable type, and if it is not documented 1808 // and also if its container annotation is not documented, do not add it 1809 // to the list. If an annotation of a repeatable type is not documented 1810 // but its container is documented, it will be added to the list. 1811 if (! Util.isDocumentedAnnotation(annotationDoc) && 1812 (!isAnnotationDocumented && !isContainerDocumented)) { 1813 continue; 1814 } 1815 annotation = new StringBuilder(); 1816 isAnnotationDocumented = false; 1817 LinkInfoImpl linkInfo = new LinkInfoImpl(configuration, 1818 LinkInfoImpl.CONTEXT_ANNOTATION, annotationDoc); 1819 AnnotationDesc.ElementValuePair[] pairs = descList[i].elementValues(); 1820 // If the annotation is synthesized, do not print the container. 1821 if (descList[i].isSynthesized()) { 1822 for (int j = 0; j < pairs.length; j++) { 1823 AnnotationValue annotationValue = pairs[j].value(); 1824 List<AnnotationValue> annotationTypeValues = new ArrayList<AnnotationValue>(); 1825 if (annotationValue.value() instanceof AnnotationValue[]) { 1826 AnnotationValue[] annotationArray = 1827 (AnnotationValue[]) annotationValue.value(); 1828 annotationTypeValues.addAll(Arrays.asList(annotationArray)); 1829 } else { 1830 annotationTypeValues.add(annotationValue); 1831 } 1832 String sep = ""; 1833 for (AnnotationValue av : annotationTypeValues) { 1834 annotation.append(sep); 1835 annotation.append(annotationValueToString(av)); 1836 sep = " "; 1837 } 1838 } 1839 } 1840 else if (isAnnotationArray(pairs)) { 1841 // If the container has 1 or more value defined and if the 1842 // repeatable type annotation is not documented, do not print 1843 // the container. 1844 if (pairs.length == 1 && isAnnotationDocumented) { 1845 AnnotationValue[] annotationArray = 1846 (AnnotationValue[]) (pairs[0].value()).value(); 1847 List<AnnotationValue> annotationTypeValues = new ArrayList<AnnotationValue>(); 1848 annotationTypeValues.addAll(Arrays.asList(annotationArray)); 1849 String sep = ""; 1850 for (AnnotationValue av : annotationTypeValues) { 1851 annotation.append(sep); 1852 annotation.append(annotationValueToString(av)); 1853 sep = " "; 1854 } 1855 } 1856 // If the container has 1 or more value defined and if the 1857 // repeatable type annotation is not documented, print the container. 1858 else { 1859 addAnnotations(annotationDoc, linkInfo, annotation, pairs, 1860 indent, false); 1861 } 1862 } 1863 else { 1864 addAnnotations(annotationDoc, linkInfo, annotation, pairs, 1865 indent, linkBreak); 1866 } 1867 annotation.append(linkBreak ? DocletConstants.NL : ""); 1868 results.add(annotation.toString()); 1869 } 1870 return results; 1871 } 1872 1873 /** 1874 * Add annotation to the annotation string. 1875 * 1876 * @param annotationDoc the annotation being documented 1877 * @param linkInfo the information about the link 1878 * @param annotation the annotation string to which the annotation will be added 1879 * @param pairs annotation type element and value pairs 1880 * @param indent the number of extra spaces to indent the annotations. 1881 * @param linkBreak if true, add new line between each member value 1882 */ 1883 private void addAnnotations(AnnotationTypeDoc annotationDoc, LinkInfoImpl linkInfo, 1884 StringBuilder annotation, AnnotationDesc.ElementValuePair[] pairs, 1885 int indent, boolean linkBreak) { 1886 linkInfo.label = "@" + annotationDoc.name(); 1887 annotation.append(getLink(linkInfo)); 1888 if (pairs.length > 0) { 1889 annotation.append('('); 1890 for (int j = 0; j < pairs.length; j++) { 1891 if (j > 0) { 1892 annotation.append(","); 1893 if (linkBreak) { 1894 annotation.append(DocletConstants.NL); 1895 int spaces = annotationDoc.name().length() + 2; 1896 for (int k = 0; k < (spaces + indent); k++) { 1897 annotation.append(' '); 1898 } 1899 } 1900 } 1901 annotation.append(getDocLink(LinkInfoImpl.CONTEXT_ANNOTATION, 1902 pairs[j].element(), pairs[j].element().name(), false)); 1903 annotation.append('='); 1904 AnnotationValue annotationValue = pairs[j].value(); 1905 List<AnnotationValue> annotationTypeValues = new ArrayList<AnnotationValue>(); 1906 if (annotationValue.value() instanceof AnnotationValue[]) { 1907 AnnotationValue[] annotationArray = 1908 (AnnotationValue[]) annotationValue.value(); 1909 annotationTypeValues.addAll(Arrays.asList(annotationArray)); 1910 } else { 1911 annotationTypeValues.add(annotationValue); 1912 } 1913 annotation.append(annotationTypeValues.size() == 1 ? "" : "{"); 1914 String sep = ""; 1915 for (AnnotationValue av : annotationTypeValues) { 1916 annotation.append(sep); 1917 annotation.append(annotationValueToString(av)); 1918 sep = ","; 1919 } 1920 annotation.append(annotationTypeValues.size() == 1 ? "" : "}"); 1921 isContainerDocumented = false; 1922 } 1923 annotation.append(")"); 1924 } 1925 } 1926 1927 /** 1928 * Check if the annotation contains an array of annotation as a value. This 1929 * check is to verify if a repeatable type annotation is present or not. 1930 * 1931 * @param pairs annotation type element and value pairs 1932 * 1933 * @return true if the annotation contains an array of annotation as a value. 1934 */ 1935 private boolean isAnnotationArray(AnnotationDesc.ElementValuePair[] pairs) { 1936 AnnotationValue annotationValue; 1937 for (int j = 0; j < pairs.length; j++) { 1938 annotationValue = pairs[j].value(); 1939 if (annotationValue.value() instanceof AnnotationValue[]) { 1940 AnnotationValue[] annotationArray = 1941 (AnnotationValue[]) annotationValue.value(); 1942 if (annotationArray.length > 1) { 1943 if (annotationArray[0].value() instanceof AnnotationDesc) { 1944 AnnotationTypeDoc annotationDoc = 1945 ((AnnotationDesc) annotationArray[0].value()).annotationType(); 1946 isContainerDocumented = true; 1947 if (Util.isDocumentedAnnotation(annotationDoc)) { 1948 isAnnotationDocumented = true; 1949 } 1950 return true; 1951 } 1952 } 1953 } 1954 } 1955 return false; 1956 } 1957 1958 private String annotationValueToString(AnnotationValue annotationValue) { 1959 if (annotationValue.value() instanceof Type) { 1960 Type type = (Type) annotationValue.value(); 1961 if (type.asClassDoc() != null) { 1962 LinkInfoImpl linkInfo = new LinkInfoImpl(configuration, 1963 LinkInfoImpl.CONTEXT_ANNOTATION, type); 1964 linkInfo.label = (type.asClassDoc().isIncluded() ? 1965 type.typeName() : 1966 type.qualifiedTypeName()) + type.dimension() + ".class"; 1967 return getLink(linkInfo); 1968 } else { 1969 return type.typeName() + type.dimension() + ".class"; 1970 } 1971 } else if (annotationValue.value() instanceof AnnotationDesc) { 1972 List<String> list = getAnnotations(0, 1973 new AnnotationDesc[]{(AnnotationDesc) annotationValue.value()}, 1974 false); 1975 StringBuilder buf = new StringBuilder(); 1976 for (String s: list) { 1977 buf.append(s); 1978 } 1979 return buf.toString(); 1980 } else if (annotationValue.value() instanceof MemberDoc) { 1981 return getDocLink(LinkInfoImpl.CONTEXT_ANNOTATION, 1982 (MemberDoc) annotationValue.value(), 1983 ((MemberDoc) annotationValue.value()).name(), false); 1984 } else { 1985 return annotationValue.toString(); 1986 } 1987 } 1988 1989 /** 1990 * Return the configuation for this doclet. 1991 * 1992 * @return the configuration for this doclet. 1993 */ 1994 public Configuration configuration() { 1995 return configuration; 1996 } 1997 }