1 /* 2 * Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package jdk.javadoc.internal.doclets.formats.html; 27 28 import java.util.Collections; 29 import java.util.EnumSet; 30 import java.util.LinkedHashMap; 31 import java.util.List; 32 import java.util.Map; 33 import java.util.Set; 34 import java.util.SortedSet; 35 import java.util.TreeMap; 36 import java.util.TreeSet; 37 38 import javax.lang.model.element.Element; 39 import javax.lang.model.element.ModuleElement; 40 import javax.lang.model.element.PackageElement; 41 import javax.lang.model.element.TypeElement; 42 import javax.lang.model.util.ElementFilter; 43 44 import com.sun.source.doctree.DocTree; 45 import jdk.javadoc.doclet.DocletEnvironment.ModuleMode; 46 import jdk.javadoc.internal.doclets.formats.html.markup.HtmlAttr; 47 import jdk.javadoc.internal.doclets.formats.html.markup.HtmlConstants; 48 import jdk.javadoc.internal.doclets.formats.html.markup.HtmlStyle; 49 import jdk.javadoc.internal.doclets.formats.html.markup.HtmlTag; 50 import jdk.javadoc.internal.doclets.formats.html.markup.HtmlTree; 51 import jdk.javadoc.internal.doclets.formats.html.markup.RawHtml; 52 import jdk.javadoc.internal.doclets.formats.html.markup.StringContent; 53 import jdk.javadoc.internal.doclets.toolkit.Content; 54 import jdk.javadoc.internal.doclets.toolkit.ModuleSummaryWriter; 55 import jdk.javadoc.internal.doclets.toolkit.util.CommentHelper; 56 import jdk.javadoc.internal.doclets.toolkit.util.DocFileIOException; 57 import jdk.javadoc.internal.doclets.toolkit.util.DocPaths; 58 import jdk.javadoc.internal.doclets.toolkit.util.ModulePackageTypes; 59 60 /** 61 * Class to generate file for each module contents in the right-hand frame. This will list all the 62 * required modules, packages and service types for the module. A click on any of the links will update 63 * the frame with the clicked element page. 64 * 65 * <p><b>This is NOT part of any supported API. 66 * If you write code that depends on this, you do so at your own risk. 67 * This code and its internal interfaces are subject to change or 68 * deletion without notice.</b> 69 * 70 * @author Bhavesh Patel 71 */ 72 public class ModuleWriterImpl extends HtmlDocletWriter implements ModuleSummaryWriter { 73 74 /** 75 * The prev module name in the alpha-order list. 76 */ 77 protected ModuleElement prevModule; 78 79 /** 80 * The next module name in the alpha-order list. 81 */ 82 protected ModuleElement nextModule; 83 84 /** 85 * The module being documented. 86 */ 87 protected ModuleElement mdle; 88 89 /** 90 * The module mode for this javadoc run. It can be set to "api" or "all". 91 */ 92 private final ModuleMode moduleMode; 93 94 /** 95 * Map of module elements and modifiers required by this module. 96 */ 97 private final Map<ModuleElement, Content> requires 98 = new TreeMap<>(utils.makeModuleComparator()); 99 100 /** 101 * Map of indirect modules and modifiers, transitive closure, required by this module. 102 */ 103 private final Map<ModuleElement, Content> indirectModules 104 = new TreeMap<>(utils.makeModuleComparator()); 105 106 /** 107 * Map of packages exported by this module and the modules it has been exported to. 108 */ 109 private final Map<PackageElement, SortedSet<ModuleElement>> exportedPackages 110 = new TreeMap<>(utils.makePackageComparator()); 111 112 /** 113 * Map of opened packages by this module and the modules it has been opened to. 114 */ 115 private final Map<PackageElement, SortedSet<ModuleElement>> openedPackages 116 = new TreeMap<>(utils.makePackageComparator()); 117 118 /** 119 * Set of concealed packages of this module. 120 */ 121 private final SortedSet<PackageElement> concealedPackages = new TreeSet<>(utils.makePackageComparator()); 122 123 /** 124 * Map of indirect modules (transitive closure) and their exported packages. 125 */ 126 private final Map<ModuleElement, SortedSet<PackageElement>> indirectPackages 127 = new TreeMap<>(utils.makeModuleComparator()); 128 129 /** 130 * Map of indirect modules (transitive closure) and their open packages. 131 */ 132 private final Map<ModuleElement, SortedSet<PackageElement>> indirectOpenPackages 133 = new TreeMap<>(utils.makeModuleComparator()); 134 135 /** 136 * Set of services used by the module. 137 */ 138 private final SortedSet<TypeElement> uses 139 = new TreeSet<>(utils.makeAllClassesComparator()); 140 141 /** 142 * Map of services used by the module and specified using @uses javadoc tag, and description. 143 */ 144 private final Map<TypeElement, Content> usesTrees 145 = new TreeMap<>(utils.makeAllClassesComparator()); 146 147 /** 148 * Map of services provided by this module, and set of its implementations. 149 */ 150 private final Map<TypeElement, SortedSet<TypeElement>> provides 151 = new TreeMap<>(utils.makeAllClassesComparator()); 152 153 /** 154 * Map of services provided by the module and specified using @provides javadoc tag, and 155 * description. 156 */ 157 private final Map<TypeElement, Content> providesTrees 158 = new TreeMap<>(utils.makeAllClassesComparator()); 159 160 private int packageTypesOr = 0; 161 162 protected Set<ModulePackageTypes> modulePackageTypes = EnumSet.noneOf(ModulePackageTypes.class); 163 164 protected Map<String, Integer> typeMap = new LinkedHashMap<>(); 165 166 /** 167 * The HTML tree for main tag. 168 */ 169 protected HtmlTree mainTree = HtmlTree.MAIN(); 170 171 /** 172 * The HTML tree for section tag. 173 */ 174 protected HtmlTree sectionTree = HtmlTree.SECTION(); 175 176 /** 177 * Constructor to construct ModuleWriter object and to generate "moduleName-summary.html" file. 178 * 179 * @param configuration the configuration of the doclet. 180 * @param mdle Module under consideration. 181 * @param prevModule Previous module in the sorted array. 182 * @param nextModule Next module in the sorted array. 183 */ 184 public ModuleWriterImpl(HtmlConfiguration configuration, 185 ModuleElement mdle, ModuleElement prevModule, ModuleElement nextModule) { 186 super(configuration, DocPaths.moduleSummary(mdle)); 187 this.prevModule = prevModule; 188 this.nextModule = nextModule; 189 this.mdle = mdle; 190 this.moduleMode = configuration.docEnv.getModuleMode(); 191 computeModulesData(); 192 } 193 194 /** 195 * Get the module header. 196 * 197 * @param heading the heading for the section 198 */ 199 @Override 200 public Content getModuleHeader(String heading) { 201 HtmlTree bodyTree = getBody(true, getWindowTitle(mdle.getQualifiedName().toString())); 202 HtmlTree htmlTree = (configuration.allowTag(HtmlTag.HEADER)) 203 ? HtmlTree.HEADER() 204 : bodyTree; 205 addTop(htmlTree); 206 addNavLinks(true, htmlTree); 207 if (configuration.allowTag(HtmlTag.HEADER)) { 208 bodyTree.addContent(htmlTree); 209 } 210 HtmlTree div = new HtmlTree(HtmlTag.DIV); 211 div.addStyle(HtmlStyle.header); 212 Content annotationContent = new HtmlTree(HtmlTag.P); 213 addAnnotationInfo(mdle, annotationContent); 214 div.addContent(annotationContent); 215 Content label = mdle.isOpen() && (configuration.docEnv.getModuleMode() == ModuleMode.ALL) 216 ? contents.openModuleLabel : contents.moduleLabel; 217 Content tHeading = HtmlTree.HEADING(HtmlConstants.TITLE_HEADING, true, 218 HtmlStyle.title, label); 219 tHeading.addContent(Contents.SPACE); 220 Content moduleHead = new RawHtml(heading); 221 tHeading.addContent(moduleHead); 222 div.addContent(tHeading); 223 if (configuration.allowTag(HtmlTag.MAIN)) { 224 mainTree.addContent(div); 225 } else { 226 bodyTree.addContent(div); 227 } 228 return bodyTree; 229 } 230 231 /** 232 * Get the content header. 233 */ 234 @Override 235 public Content getContentHeader() { 236 HtmlTree div = new HtmlTree(HtmlTag.DIV); 237 div.addStyle(HtmlStyle.contentContainer); 238 return div; 239 } 240 241 /** 242 * Get the summary section header. 243 */ 244 @Override 245 public Content getSummaryHeader() { 246 HtmlTree li = new HtmlTree(HtmlTag.LI); 247 li.addStyle(HtmlStyle.blockList); 248 return li; 249 } 250 251 /** 252 * Get the summary tree. 253 * 254 * @param summaryContentTree the content tree to be added to the summary tree. 255 */ 256 @Override 257 public Content getSummaryTree(Content summaryContentTree) { 258 HtmlTree ul = HtmlTree.UL(HtmlStyle.blockList, summaryContentTree); 259 return ul; 260 } 261 262 /** 263 * Compute the modules data that will be displayed in various tables on the module summary page. 264 */ 265 public void computeModulesData() { 266 CommentHelper ch = utils.getCommentHelper(mdle); 267 // Get module dependencies using the module's transitive closure. 268 Map<ModuleElement, String> dependentModules = utils.getDependentModules(mdle); 269 // Add all dependent modules to indirect modules set. We will remove the modules, 270 // listed using the requires directive, from this set to come up with the table of indirect 271 // required modules. 272 dependentModules.forEach((module, mod) -> { 273 if (shouldDocument(module)) { 274 indirectModules.put(module, new StringContent(mod)); 275 } 276 }); 277 (ElementFilter.requiresIn(mdle.getDirectives())).forEach((directive) -> { 278 ModuleElement m = directive.getDependency(); 279 if (shouldDocument(m)) { 280 if (moduleMode == ModuleMode.ALL || directive.isTransitive()) { 281 requires.put(m, new StringContent(utils.getModifiers(directive))); 282 } else { 283 // For api mode, just keep the public requires in dependentModules for display of 284 // indirect packages in the "Packages" section. 285 dependentModules.remove(m); 286 } 287 indirectModules.remove(m); 288 } 289 }); 290 291 // Get all packages for the module and put it in the concealed packages set. 292 utils.getModulePackageMap().getOrDefault(mdle, Collections.emptySet()).forEach((pkg) -> { 293 if (shouldDocument(pkg) && moduleMode == ModuleMode.ALL) { 294 concealedPackages.add(pkg); 295 } 296 }); 297 298 // Get all exported packages for the module using the exports directive for the module. 299 (ElementFilter.exportsIn(mdle.getDirectives())).forEach((directive) -> { 300 PackageElement p = directive.getPackage(); 301 if (shouldDocument(p)) { 302 SortedSet<ModuleElement> mdleList = new TreeSet<>(utils.makeModuleComparator()); 303 List<? extends ModuleElement> targetMdles = directive.getTargetModules(); 304 if (targetMdles != null) { 305 mdleList.addAll(targetMdles); 306 } 307 // Qualified exports should not be displayed in the api mode. So if mdleList is empty, 308 // its exported to all modules and hence can be added. 309 if (moduleMode == ModuleMode.ALL || mdleList.isEmpty()) { 310 exportedPackages.put(p, mdleList); 311 } 312 if (moduleMode == ModuleMode.ALL) { 313 concealedPackages.remove(p); 314 } 315 } 316 }); 317 // Get all opened packages for the module using the opens directive for the module. 318 (ElementFilter.opensIn(mdle.getDirectives())).forEach((directive) -> { 319 PackageElement p = directive.getPackage(); 320 if (shouldDocument(p)) { 321 SortedSet<ModuleElement> mdleList = new TreeSet<>(utils.makeModuleComparator()); 322 List<? extends ModuleElement> targetMdles = directive.getTargetModules(); 323 if (targetMdles != null) { 324 mdleList.addAll(targetMdles); 325 } 326 // Qualified opens should not be displayed in the api mode. So if mdleList is empty, 327 // it is opened to all modules and hence can be added. 328 if (moduleMode == ModuleMode.ALL || mdleList.isEmpty()) { 329 openedPackages.put(p, mdleList); 330 } 331 if (moduleMode == ModuleMode.ALL) { 332 concealedPackages.remove(p); 333 } 334 } 335 }); 336 // Get all the exported and opened packages, for the transitive closure of the module, to be displayed in 337 // the indirect packages tables. 338 dependentModules.forEach((module, mod) -> { 339 SortedSet<PackageElement> exportPkgList = new TreeSet<>(utils.makePackageComparator()); 340 (ElementFilter.exportsIn(module.getDirectives())).forEach((directive) -> { 341 PackageElement pkg = directive.getPackage(); 342 if (shouldDocument(pkg)) { 343 // Qualified exports are not displayed in API mode 344 if (moduleMode == ModuleMode.ALL || directive.getTargetModules() == null) { 345 exportPkgList.add(pkg); 346 } 347 } 348 }); 349 // If none of the indirect modules have exported packages to be displayed, we should not be 350 // displaying the table and so it should not be added to the map. 351 if (!exportPkgList.isEmpty()) { 352 indirectPackages.put(module, exportPkgList); 353 } 354 SortedSet<PackageElement> openPkgList = new TreeSet<>(utils.makePackageComparator()); 355 (ElementFilter.opensIn(module.getDirectives())).forEach((directive) -> { 356 PackageElement pkg = directive.getPackage(); 357 if (shouldDocument(pkg)) { 358 // Qualified opens are not displayed in API mode 359 if (moduleMode == ModuleMode.ALL || directive.getTargetModules() == null) { 360 openPkgList.add(pkg); 361 } 362 } 363 }); 364 // If none of the indirect modules have opened packages to be displayed, we should not be 365 // displaying the table and so it should not be added to the map. 366 if (!openPkgList.isEmpty()) { 367 indirectOpenPackages.put(module, openPkgList); 368 } 369 }); 370 // Get all the services listed as uses directive. 371 (ElementFilter.usesIn(mdle.getDirectives())).forEach((directive) -> { 372 TypeElement u = directive.getService(); 373 if (shouldDocument(u)) { 374 uses.add(u); 375 } 376 }); 377 // Get all the services and implementations listed as provides directive. 378 (ElementFilter.providesIn(mdle.getDirectives())).forEach((directive) -> { 379 TypeElement u = directive.getService(); 380 if (shouldDocument(u)) { 381 List<? extends TypeElement> implList = directive.getImplementations(); 382 SortedSet<TypeElement> implSet = new TreeSet<>(utils.makeAllClassesComparator()); 383 implSet.addAll(implList); 384 provides.put(u, implSet); 385 } 386 }); 387 // Generate the map of all services listed using @provides, and the description. 388 (utils.getBlockTags(mdle, DocTree.Kind.PROVIDES)).forEach((tree) -> { 389 TypeElement t = ch.getServiceType(configuration, tree); 390 if (t != null) { 391 providesTrees.put(t, commentTagsToContent(tree, mdle, ch.getDescription(configuration, tree), false)); 392 } 393 }); 394 // Generate the map of all services listed using @uses, and the description. 395 (utils.getBlockTags(mdle, DocTree.Kind.USES)).forEach((tree) -> { 396 TypeElement t = ch.getServiceType(configuration, tree); 397 if (t != null) { 398 usesTrees.put(t, commentTagsToContent(tree, mdle, ch.getDescription(configuration, tree), false)); 399 } 400 }); 401 } 402 403 /** 404 * Returns true if the element should be documented on the module summary page. 405 * 406 * @param element the element to be checked 407 * @return true if the element should be documented 408 */ 409 public boolean shouldDocument(Element element) { 410 return (moduleMode == ModuleMode.ALL || utils.isIncluded(element)); 411 } 412 413 /** 414 * Returns true if there are elements to be displayed. 415 * 416 * @param section set of elements 417 * @return true if there are elements to be displayed 418 */ 419 public boolean display(Set<? extends Element> section) { 420 return section != null && !section.isEmpty(); 421 } 422 423 /** 424 * Returns true if there are elements to be displayed. 425 * 426 * @param section map of elements. 427 * @return true if there are elements to be displayed 428 */ 429 public boolean display(Map<? extends Element, ?> section) { 430 return section != null && !section.isEmpty(); 431 } 432 433 /* 434 * Returns true, in API mode, if at least one type element in 435 * the typeElements set is referenced by a javadoc tag in tagsMap. 436 */ 437 private boolean displayServices(Set<TypeElement> typeElements, 438 Map<TypeElement, Content> tagsMap) { 439 return typeElements != null && 440 typeElements.stream().anyMatch((v) -> displayServiceDirective(v, tagsMap)); 441 } 442 443 /* 444 * Returns true, in API mode, if the type element is referenced 445 * from a javadoc tag in tagsMap. 446 */ 447 private boolean displayServiceDirective(TypeElement typeElement, 448 Map<TypeElement, Content> tagsMap) { 449 return moduleMode == ModuleMode.ALL || tagsMap.containsKey(typeElement); 450 } 451 452 /** 453 * Add the summary header. 454 * 455 * @param startMarker the marker comment 456 * @param markerAnchor the marker anchor for the section 457 * @param heading the heading for the section 458 * @param htmltree the content tree to which the information is added 459 */ 460 public void addSummaryHeader(Content startMarker, SectionName markerAnchor, Content heading, 461 Content htmltree) { 462 htmltree.addContent(startMarker); 463 htmltree.addContent(getMarkerAnchor(markerAnchor)); 464 htmltree.addContent(HtmlTree.HEADING(HtmlTag.H3, heading)); 465 } 466 467 /** 468 * Get a table. 469 * 470 * @param text the table caption 471 * @param tableSummary the summary for the table 472 * @param tableStyle the table style 473 * @param tableHeader the table header 474 * @return a content object 475 */ 476 Content getTable(String text, String tableSummary, HtmlStyle tableStyle, 477 TableHeader tableHeader) { 478 return getTable(getTableCaption(new RawHtml(text)), tableSummary, tableStyle, tableHeader); 479 } 480 481 /** 482 * Get a table. 483 * 484 * @param caption the table caption 485 * @param tableSummary the summary for the table 486 * @param tableStyle the table style 487 * @param tableHeader the table header 488 * @return a content object 489 */ 490 Content getTable(Content caption, String tableSummary, HtmlStyle tableStyle, 491 TableHeader tableHeader) { 492 Content table = (configuration.isOutputHtml5()) 493 ? HtmlTree.TABLE(tableStyle, caption) 494 : HtmlTree.TABLE(tableStyle, tableSummary, caption); 495 table.addContent(tableHeader.toContent()); 496 return table; 497 } 498 499 /** 500 * {@inheritDoc} 501 */ 502 @Override 503 public void addModulesSummary(Content summaryContentTree) { 504 if (display(requires) || display(indirectModules)) { 505 TableHeader requiresTableHeader = 506 new TableHeader(contents.modifierLabel, contents.moduleLabel, 507 contents.descriptionLabel); 508 HtmlTree li = new HtmlTree(HtmlTag.LI); 509 li.addStyle(HtmlStyle.blockList); 510 addSummaryHeader(HtmlConstants.START_OF_MODULES_SUMMARY, SectionName.MODULES, 511 contents.navModules, li); 512 if (display(requires)) { 513 String text = configuration.getText("doclet.Requires_Summary"); 514 String tableSummary = configuration.getText("doclet.Member_Table_Summary", 515 text, 516 configuration.getText("doclet.modules")); 517 Content table = getTable(text, tableSummary, HtmlStyle.requiresSummary, 518 requiresTableHeader); 519 Content tbody = new HtmlTree(HtmlTag.TBODY); 520 addModulesList(requires, tbody); 521 table.addContent(tbody); 522 li.addContent(table); 523 } 524 // Display indirect modules table in both "api" and "all" mode. 525 if (display(indirectModules)) { 526 String amrText = configuration.getText("doclet.Indirect_Requires_Summary"); 527 String amrTableSummary = configuration.getText("doclet.Member_Table_Summary", 528 amrText, 529 configuration.getText("doclet.modules")); 530 Content amrTable = getTable(amrText, amrTableSummary, HtmlStyle.requiresSummary, 531 requiresTableHeader); 532 Content amrTbody = new HtmlTree(HtmlTag.TBODY); 533 addModulesList(indirectModules, amrTbody); 534 amrTable.addContent(amrTbody); 535 li.addContent(amrTable); 536 } 537 HtmlTree ul = HtmlTree.UL(HtmlStyle.blockList, li); 538 summaryContentTree.addContent(ul); 539 } 540 } 541 542 /** 543 * Add the list of modules. 544 * 545 * @param mdleMap map of modules and modifiers 546 * @param tbody the content tree to which the list will be added 547 */ 548 public void addModulesList(Map<ModuleElement, Content> mdleMap, Content tbody) { 549 boolean altColor = true; 550 for (ModuleElement m : mdleMap.keySet()) { 551 Content tdModifiers = HtmlTree.TD(HtmlStyle.colFirst, mdleMap.get(m)); 552 Content moduleLinkContent = getModuleLink(m, new StringContent(m.getQualifiedName())); 553 Content thModule = HtmlTree.TH_ROW_SCOPE(HtmlStyle.colSecond, moduleLinkContent); 554 HtmlTree tdSummary = new HtmlTree(HtmlTag.TD); 555 tdSummary.addStyle(HtmlStyle.colLast); 556 addSummaryComment(m, tdSummary); 557 HtmlTree tr = HtmlTree.TR(tdModifiers); 558 tr.addContent(thModule); 559 tr.addContent(tdSummary); 560 tr.addStyle(altColor ? HtmlStyle.altColor : HtmlStyle.rowColor); 561 tbody.addContent(tr); 562 altColor = !altColor; 563 } 564 } 565 566 @Override 567 public void addPackagesSummary(Content summaryContentTree) { 568 if (display(exportedPackages) || display(openedPackages) || display(concealedPackages) 569 || display(indirectPackages) || display(indirectOpenPackages)) { 570 HtmlTree li = new HtmlTree(HtmlTag.LI); 571 li.addStyle(HtmlStyle.blockList); 572 addSummaryHeader(HtmlConstants.START_OF_PACKAGES_SUMMARY, SectionName.PACKAGES, 573 contents.navPackages, li); 574 String tableSummary = configuration.getText("doclet.Member_Table_Summary", 575 configuration.getText("doclet.Packages_Summary"), 576 configuration.getText("doclet.packages")); 577 if (display(exportedPackages) || display(openedPackages) || display(concealedPackages)) { 578 addPackageSummary(tableSummary, li); 579 } 580 TableHeader indirectPackagesHeader = 581 new TableHeader(contents.fromLabel, contents.packagesLabel); 582 if (display(indirectPackages)) { 583 String aepText = configuration.getText("doclet.Indirect_Exports_Summary"); 584 String aepTableSummary = configuration.getText("doclet.Indirect_Packages_Table_Summary", 585 aepText, 586 configuration.getText("doclet.modules"), 587 configuration.getText("doclet.packages")); 588 Content aepTable = getTable(aepText, aepTableSummary, HtmlStyle.packagesSummary, 589 indirectPackagesHeader); 590 Content aepTbody = new HtmlTree(HtmlTag.TBODY); 591 addIndirectPackages(aepTbody, indirectPackages); 592 aepTable.addContent(aepTbody); 593 li.addContent(aepTable); 594 } 595 if (display(indirectOpenPackages)) { 596 String aopText = configuration.getText("doclet.Indirect_Opens_Summary"); 597 String aopTableSummary = configuration.getText("doclet.Indirect_Packages_Table_Summary", 598 aopText, 599 configuration.getText("doclet.modules"), 600 configuration.getText("doclet.packages")); 601 Content aopTable = getTable(aopText, aopTableSummary, HtmlStyle.packagesSummary, 602 indirectPackagesHeader); 603 Content aopTbody = new HtmlTree(HtmlTag.TBODY); 604 addIndirectPackages(aopTbody, indirectOpenPackages); 605 aopTable.addContent(aopTbody); 606 li.addContent(aopTable); 607 } 608 HtmlTree ul = HtmlTree.UL(HtmlStyle.blockList, li); 609 summaryContentTree.addContent(ul); 610 } 611 } 612 613 /** 614 * Add the package summary for the module. 615 * 616 * @param tableSummary 617 * @param li 618 */ 619 public void addPackageSummary(String tableSummary, HtmlTree li) { 620 Content caption; 621 Content tbody = getPackageTableRows(); 622 if (showTabs()) { 623 caption = getTableCaption(); 624 generateTableTabTypesScript(typeMap, modulePackageTypes, "packages"); 625 } else { 626 ModulePackageTypes type = modulePackageTypes.iterator().next(); 627 caption = getTableCaption(configuration.getContent(type.tableTabs().resourceKey())); 628 } 629 TableHeader header = (configuration.docEnv.getModuleMode() == ModuleMode.ALL) 630 ? new TableHeader(contents.packageLabel, contents.moduleLabel, contents.descriptionLabel) 631 : new TableHeader(contents.packageLabel, contents.descriptionLabel); 632 Content table = getTable(caption, tableSummary, HtmlStyle.packagesSummary, header); 633 table.addContent(tbody); 634 li.addContent(table); 635 } 636 637 /** 638 * Returns true if the table tabs needs to be displayed. 639 * 640 * @return true if the tabs should be displayed 641 */ 642 public boolean showTabs() { 643 int value; 644 for (ModulePackageTypes type : EnumSet.allOf(ModulePackageTypes.class)) { 645 value = type.tableTabs().value(); 646 if ((value & packageTypesOr) == value) { 647 modulePackageTypes.add(type); 648 } 649 } 650 boolean showTabs = modulePackageTypes.size() > 1; 651 if (showTabs) { 652 modulePackageTypes.add(ModulePackageTypes.ALL); 653 } 654 return showTabs; 655 } 656 657 /** 658 * Get the summary table caption. 659 * 660 * @return the caption for the summary table 661 */ 662 public Content getTableCaption() { 663 Content tabbedCaption = new HtmlTree(HtmlTag.CAPTION); 664 for (ModulePackageTypes type : modulePackageTypes) { 665 Content captionSpan; 666 Content span; 667 if (type.tableTabs().isDefaultTab()) { 668 captionSpan = HtmlTree.SPAN(configuration.getContent(type.tableTabs().resourceKey())); 669 span = HtmlTree.SPAN(type.tableTabs().tabId(), 670 HtmlStyle.activeTableTab, captionSpan); 671 } else { 672 captionSpan = HtmlTree.SPAN(getPackageTypeLinks(type)); 673 span = HtmlTree.SPAN(type.tableTabs().tabId(), 674 HtmlStyle.tableTab, captionSpan); 675 } 676 Content tabSpan = HtmlTree.SPAN(HtmlStyle.tabEnd, Contents.SPACE); 677 span.addContent(tabSpan); 678 tabbedCaption.addContent(span); 679 } 680 return tabbedCaption; 681 } 682 683 /** 684 * Get the package type links for the table caption. 685 * 686 * @param packageType the package type to be displayed as link 687 * @return the content tree for the package type link 688 */ 689 public Content getPackageTypeLinks(ModulePackageTypes packageType) { 690 String jsShow = "javascript:showPkgs(" + packageType.tableTabs().value() + ");"; 691 HtmlTree link = HtmlTree.A(jsShow, configuration.getContent(packageType.tableTabs().resourceKey())); 692 return link; 693 } 694 695 /** 696 * Get the package table rows. 697 * 698 * @return a content object 699 */ 700 public Content getPackageTableRows() { 701 Content tbody = new HtmlTree(HtmlTag.TBODY); 702 boolean altColor = true; 703 int counter = 0; 704 counter = addPackageTableRows(tbody, counter, ModulePackageTypes.EXPORTED, exportedPackages); 705 counter = addPackageTableRows(tbody, counter, ModulePackageTypes.OPENED, openedPackages); 706 // Show concealed packages only in "all" mode. 707 if (moduleMode == ModuleMode.ALL) { 708 for (PackageElement pkg : concealedPackages) { 709 Content pkgLinkContent = getPackageLink(pkg, new StringContent(utils.getPackageName(pkg))); 710 Content thPackage = HtmlTree.TH_ROW_SCOPE(HtmlStyle.colFirst, pkgLinkContent); 711 HtmlTree tdModules = new HtmlTree(HtmlTag.TD); 712 tdModules.addStyle(HtmlStyle.colSecond); 713 tdModules.addContent(configuration.getText("doclet.None")); 714 HtmlTree tdSummary = new HtmlTree(HtmlTag.TD); 715 tdSummary.addStyle(HtmlStyle.colLast); 716 addSummaryComment(pkg, tdSummary); 717 HtmlTree tr = HtmlTree.TR(thPackage); 718 tr.addContent(tdModules); 719 tr.addContent(tdSummary); 720 tr.addStyle(altColor ? HtmlStyle.altColor : HtmlStyle.rowColor); 721 int pkgType = ModulePackageTypes.CONCEALED.tableTabs().value(); 722 packageTypesOr = packageTypesOr | pkgType; 723 String tableId = "i" + counter; 724 counter++; 725 typeMap.put(tableId, pkgType); 726 tr.addAttr(HtmlAttr.ID, tableId); 727 tbody.addContent(tr); 728 altColor = !altColor; 729 } 730 } 731 return tbody; 732 } 733 734 public int addPackageTableRows(Content tbody, int counter, ModulePackageTypes pType, 735 Map<PackageElement,SortedSet<ModuleElement>> ap) { 736 boolean altColor = true; 737 for (Map.Entry<PackageElement, SortedSet<ModuleElement>> entry : ap.entrySet()) { 738 PackageElement pkg = entry.getKey(); 739 SortedSet<ModuleElement> mdleList = entry.getValue(); 740 Content pkgLinkContent = getPackageLink(pkg, new StringContent(utils.getPackageName(pkg))); 741 Content thPackage = HtmlTree.TH_ROW_SCOPE(HtmlStyle.colFirst, pkgLinkContent); 742 HtmlTree tr = HtmlTree.TR(thPackage); 743 if (moduleMode == ModuleMode.ALL) { 744 HtmlTree tdModules = new HtmlTree(HtmlTag.TD); 745 tdModules.addStyle(HtmlStyle.colSecond); 746 if (!mdleList.isEmpty()) { 747 int sep = 0; 748 for (ModuleElement m : mdleList) { 749 if (sep > 0) { 750 tdModules.addContent(new HtmlTree(HtmlTag.BR)); 751 } 752 tdModules.addContent(getModuleLink(m, new StringContent(m.getQualifiedName()))); 753 sep++; 754 } 755 } else { 756 tdModules.addContent(configuration.getText("doclet.All_Modules")); 757 } 758 tr.addContent(tdModules); 759 } 760 HtmlTree tdSummary = new HtmlTree(HtmlTag.TD); 761 tdSummary.addStyle(HtmlStyle.colLast); 762 addSummaryComment(pkg, tdSummary); 763 tr.addContent(tdSummary); 764 tr.addStyle(altColor ? HtmlStyle.altColor : HtmlStyle.rowColor); 765 int pkgType = pType.tableTabs().value(); 766 packageTypesOr = packageTypesOr | pkgType; 767 String tableId = "i" + counter; 768 counter++; 769 typeMap.put(tableId, pkgType); 770 tr.addAttr(HtmlAttr.ID, tableId); 771 tbody.addContent(tr); 772 altColor = !altColor; 773 } 774 return counter; 775 } 776 777 /** 778 * Add the indirect packages for the module being documented. 779 * 780 * @param tbody the content tree to which the table will be added 781 * @param ip indirect packages to be added 782 */ 783 public void addIndirectPackages(Content tbody, Map<ModuleElement, SortedSet<PackageElement>> ip) { 784 boolean altColor = true; 785 for (Map.Entry<ModuleElement, SortedSet<PackageElement>> entry : ip.entrySet()) { 786 ModuleElement m = entry.getKey(); 787 SortedSet<PackageElement> pkgList = entry.getValue(); 788 Content moduleLinkContent = getModuleLink(m, new StringContent(m.getQualifiedName())); 789 Content thModule = HtmlTree.TH_ROW_SCOPE(HtmlStyle.colFirst, moduleLinkContent); 790 HtmlTree tdPackages = new HtmlTree(HtmlTag.TD); 791 tdPackages.addStyle(HtmlStyle.colLast); 792 String sep = ""; 793 for (PackageElement pkg : pkgList) { 794 tdPackages.addContent(sep); 795 tdPackages.addContent(getPackageLink(pkg, new StringContent(utils.getPackageName(pkg)))); 796 sep = " "; 797 } 798 HtmlTree tr = HtmlTree.TR(thModule); 799 tr.addContent(tdPackages); 800 tr.addStyle(altColor ? HtmlStyle.altColor : HtmlStyle.rowColor); 801 tbody.addContent(tr); 802 altColor = !altColor; 803 } 804 } 805 806 /** 807 * {@inheritDoc} 808 */ 809 @Override 810 public void addServicesSummary(Content summaryContentTree) { 811 812 boolean haveUses = displayServices(uses, usesTrees); 813 boolean haveProvides = displayServices(provides.keySet(), providesTrees); 814 815 if (haveProvides || haveUses) { 816 HtmlTree li = new HtmlTree(HtmlTag.LI); 817 li.addStyle(HtmlStyle.blockList); 818 addSummaryHeader(HtmlConstants.START_OF_SERVICES_SUMMARY, SectionName.SERVICES, 819 contents.navServices, li); 820 TableHeader usesProvidesTableHeader = 821 new TableHeader(contents.typeLabel, contents.descriptionLabel); 822 if (haveProvides) { 823 String label = configuration.getText("doclet.Provides_Summary"); 824 String tableSummary = configuration.getText("doclet.Member_Table_Summary", 825 label, 826 configuration.getText("doclet.types")); 827 Content table = getTable(label, tableSummary, HtmlStyle.providesSummary, 828 usesProvidesTableHeader); 829 Content tbody = new HtmlTree(HtmlTag.TBODY); 830 addProvidesList(tbody); 831 if (!tbody.isEmpty()) { 832 table.addContent(tbody); 833 li.addContent(table); 834 } 835 } 836 if (haveUses){ 837 String label = configuration.getText("doclet.Uses_Summary"); 838 String tableSummary = configuration.getText("doclet.Member_Table_Summary", 839 label, 840 configuration.getText("doclet.types")); 841 Content table = getTable(label, tableSummary, HtmlStyle.usesSummary, 842 usesProvidesTableHeader); 843 Content tbody = new HtmlTree(HtmlTag.TBODY); 844 addUsesList(tbody); 845 if (!tbody.isEmpty()) { 846 table.addContent(tbody); 847 li.addContent(table); 848 } 849 } 850 HtmlTree ul = HtmlTree.UL(HtmlStyle.blockList, li); 851 summaryContentTree.addContent(ul); 852 } 853 } 854 855 /** 856 * Add the uses list for the module. 857 * 858 * @param tbody the content tree to which the directive will be added 859 */ 860 public void addUsesList(Content tbody) { 861 boolean altColor = true; 862 Content typeLinkContent; 863 Content thType; 864 HtmlTree tdSummary; 865 Content description; 866 for (TypeElement t : uses) { 867 if (!displayServiceDirective(t, usesTrees)) { 868 continue; 869 } 870 typeLinkContent = getLink(new LinkInfoImpl(configuration, LinkInfoImpl.Kind.PACKAGE, t)); 871 thType = HtmlTree.TH_ROW_SCOPE(HtmlStyle.colFirst, typeLinkContent); 872 tdSummary = new HtmlTree(HtmlTag.TD); 873 tdSummary.addStyle(HtmlStyle.colLast); 874 if (display(usesTrees)) { 875 description = usesTrees.get(t); 876 if (description != null) { 877 tdSummary.addContent(description); 878 } 879 } 880 addSummaryComment(t, tdSummary); 881 HtmlTree tr = HtmlTree.TR(thType); 882 tr.addContent(tdSummary); 883 tr.addStyle(altColor ? HtmlStyle.altColor : HtmlStyle.rowColor); 884 tbody.addContent(tr); 885 altColor = !altColor; 886 } 887 } 888 889 /** 890 * Add the provides list for the module. 891 * 892 * @param tbody the content tree to which the directive will be added 893 */ 894 public void addProvidesList(Content tbody) { 895 boolean altColor = true; 896 SortedSet<TypeElement> implSet; 897 Content description; 898 for (Map.Entry<TypeElement, SortedSet<TypeElement>> entry : provides.entrySet()) { 899 TypeElement srv = entry.getKey(); 900 if (!displayServiceDirective(srv, providesTrees)) { 901 continue; 902 } 903 implSet = entry.getValue(); 904 Content srvLinkContent = getLink(new LinkInfoImpl(configuration, LinkInfoImpl.Kind.PACKAGE, srv)); 905 HtmlTree thType = HtmlTree.TH_ROW_SCOPE(HtmlStyle.colFirst, srvLinkContent); 906 HtmlTree tdDesc = new HtmlTree(HtmlTag.TD); 907 tdDesc.addStyle(HtmlStyle.colLast); 908 if (display(providesTrees)) { 909 description = providesTrees.get(srv); 910 if (description != null) { 911 tdDesc.addContent(description); 912 } 913 } 914 addSummaryComment(srv, tdDesc); 915 // Only display the implementation details in the "all" mode. 916 if (moduleMode == ModuleMode.ALL && !implSet.isEmpty()) { 917 tdDesc.addContent(new HtmlTree(HtmlTag.BR)); 918 tdDesc.addContent("("); 919 HtmlTree implSpan = HtmlTree.SPAN(HtmlStyle.implementationLabel, contents.implementation); 920 tdDesc.addContent(implSpan); 921 tdDesc.addContent(Contents.SPACE); 922 String sep = ""; 923 for (TypeElement impl : implSet) { 924 tdDesc.addContent(sep); 925 tdDesc.addContent(getLink(new LinkInfoImpl(configuration, LinkInfoImpl.Kind.PACKAGE, impl))); 926 sep = ", "; 927 } 928 tdDesc.addContent(")"); 929 } 930 HtmlTree tr = HtmlTree.TR(thType); 931 tr.addContent(tdDesc); 932 tr.addStyle(altColor ? HtmlStyle.altColor : HtmlStyle.rowColor); 933 tbody.addContent(tr); 934 altColor = !altColor; 935 } 936 } 937 938 /** 939 * Add the module deprecation information to the documentation tree. 940 * 941 * @param div the content tree to which the deprecation information will be added 942 */ 943 public void addDeprecationInfo(Content div) { 944 List<? extends DocTree> deprs = utils.getBlockTags(mdle, DocTree.Kind.DEPRECATED); 945 if (utils.isDeprecated(mdle)) { 946 CommentHelper ch = utils.getCommentHelper(mdle); 947 HtmlTree deprDiv = new HtmlTree(HtmlTag.DIV); 948 deprDiv.addStyle(HtmlStyle.deprecationBlock); 949 Content deprPhrase = HtmlTree.SPAN(HtmlStyle.deprecatedLabel, getDeprecatedPhrase(mdle)); 950 deprDiv.addContent(deprPhrase); 951 if (!deprs.isEmpty()) { 952 List<? extends DocTree> commentTags = ch.getDescription(configuration, deprs.get(0)); 953 if (!commentTags.isEmpty()) { 954 addInlineDeprecatedComment(mdle, deprs.get(0), deprDiv); 955 } 956 } 957 div.addContent(deprDiv); 958 } 959 } 960 961 /** 962 * {@inheritDoc} 963 */ 964 @Override 965 public void addModuleDescription(Content moduleContentTree) { 966 if (!utils.getFullBody(mdle).isEmpty()) { 967 Content tree = configuration.allowTag(HtmlTag.SECTION) ? HtmlTree.SECTION() : moduleContentTree; 968 addDeprecationInfo(tree); 969 tree.addContent(HtmlConstants.START_OF_MODULE_DESCRIPTION); 970 tree.addContent(getMarkerAnchor(SectionName.MODULE_DESCRIPTION)); 971 addInlineComment(mdle, tree); 972 if (configuration.allowTag(HtmlTag.SECTION)) { 973 moduleContentTree.addContent(tree); 974 } 975 } 976 } 977 978 /** 979 * {@inheritDoc} 980 */ 981 @Override 982 public void addModuleTags(Content moduleContentTree) { 983 Content tree = (configuration.allowTag(HtmlTag.SECTION)) 984 ? HtmlTree.SECTION() 985 : moduleContentTree; 986 addTagsInfo(mdle, tree); 987 if (configuration.allowTag(HtmlTag.SECTION)) { 988 moduleContentTree.addContent(tree); 989 } 990 } 991 992 /** 993 * Add summary details to the navigation bar. 994 * 995 * @param subDiv the content tree to which the summary detail links will be added 996 */ 997 @Override 998 protected void addSummaryDetailLinks(Content subDiv) { 999 Content div = HtmlTree.DIV(getNavSummaryLinks()); 1000 subDiv.addContent(div); 1001 } 1002 1003 /** 1004 * Get summary links for navigation bar. 1005 * 1006 * @return the content tree for the navigation summary links 1007 */ 1008 protected Content getNavSummaryLinks() { 1009 Content li = HtmlTree.LI(contents.moduleSubNavLabel); 1010 li.addContent(Contents.SPACE); 1011 Content ulNav = HtmlTree.UL(HtmlStyle.subNavList, li); 1012 Content liNav = new HtmlTree(HtmlTag.LI); 1013 liNav.addContent(!utils.getFullBody(mdle).isEmpty() && !configuration.nocomment 1014 ? getHyperLink(SectionName.MODULE_DESCRIPTION, contents.navModuleDescription) 1015 : contents.navModuleDescription); 1016 addNavGap(liNav); 1017 liNav.addContent((display(requires) || display(indirectModules)) 1018 ? getHyperLink(SectionName.MODULES, contents.navModules) 1019 : contents.navModules); 1020 addNavGap(liNav); 1021 liNav.addContent((display(exportedPackages) || display(openedPackages) || display(concealedPackages) 1022 || display(indirectPackages) || display(indirectOpenPackages)) 1023 ? getHyperLink(SectionName.PACKAGES, contents.navPackages) 1024 : contents.navPackages); 1025 addNavGap(liNav); 1026 liNav.addContent((displayServices(uses, usesTrees) || displayServices(provides.keySet(), providesTrees)) 1027 ? getHyperLink(SectionName.SERVICES, contents.navServices) 1028 : contents.navServices); 1029 ulNav.addContent(liNav); 1030 return ulNav; 1031 } 1032 1033 /** 1034 * {@inheritDoc} 1035 */ 1036 @Override 1037 public void addModuleContent(Content contentTree, Content moduleContentTree) { 1038 if (configuration.allowTag(HtmlTag.MAIN)) { 1039 mainTree.addContent(moduleContentTree); 1040 contentTree.addContent(mainTree); 1041 } else { 1042 contentTree.addContent(moduleContentTree); 1043 } 1044 } 1045 1046 /** 1047 * {@inheritDoc} 1048 */ 1049 @Override 1050 public void addModuleFooter(Content contentTree) { 1051 Content htmlTree = (configuration.allowTag(HtmlTag.FOOTER)) 1052 ? HtmlTree.FOOTER() 1053 : contentTree; 1054 addNavLinks(false, htmlTree); 1055 addBottom(htmlTree); 1056 if (configuration.allowTag(HtmlTag.FOOTER)) { 1057 contentTree.addContent(htmlTree); 1058 } 1059 } 1060 1061 /** 1062 * {@inheritDoc} 1063 * 1064 * @throws jdk.javadoc.internal.doclets.toolkit.util.DocFileIOException 1065 */ 1066 @Override 1067 public void printDocument(Content contentTree) throws DocFileIOException { 1068 printHtmlDocument(configuration.metakeywords.getMetaKeywordsForModule(mdle), 1069 true, contentTree); 1070 } 1071 1072 /** 1073 * Add the module package deprecation information to the documentation tree. 1074 * 1075 * @param li the content tree to which the deprecation information will be added 1076 * @param pkg the PackageDoc that is added 1077 */ 1078 public void addPackageDeprecationInfo(Content li, PackageElement pkg) { 1079 List<? extends DocTree> deprs; 1080 if (utils.isDeprecated(pkg)) { 1081 deprs = utils.getDeprecatedTrees(pkg); 1082 HtmlTree deprDiv = new HtmlTree(HtmlTag.DIV); 1083 deprDiv.addStyle(HtmlStyle.deprecationBlock); 1084 Content deprPhrase = HtmlTree.SPAN(HtmlStyle.deprecatedLabel, getDeprecatedPhrase(pkg)); 1085 deprDiv.addContent(deprPhrase); 1086 if (!deprs.isEmpty()) { 1087 CommentHelper ch = utils.getCommentHelper(pkg); 1088 List<? extends DocTree> commentTags = ch.getDescription(configuration, deprs.get(0)); 1089 if (!commentTags.isEmpty()) { 1090 addInlineDeprecatedComment(pkg, deprs.get(0), deprDiv); 1091 } 1092 } 1093 li.addContent(deprDiv); 1094 } 1095 } 1096 1097 /** 1098 * Get this module link. 1099 * 1100 * @return a content tree for the module link 1101 */ 1102 @Override 1103 protected Content getNavLinkModule() { 1104 Content li = HtmlTree.LI(HtmlStyle.navBarCell1Rev, contents.moduleLabel); 1105 return li; 1106 } 1107 1108 /** 1109 * Get "PREV MODULE" link in the navigation bar. 1110 * 1111 * @return a content tree for the previous link 1112 */ 1113 @Override 1114 public Content getNavLinkPrevious() { 1115 Content li; 1116 if (prevModule == null) { 1117 li = HtmlTree.LI(contents.prevModuleLabel); 1118 } else { 1119 li = HtmlTree.LI(getHyperLink(pathToRoot.resolve(DocPaths.moduleSummary( 1120 prevModule)), contents.prevModuleLabel, "", "")); 1121 } 1122 return li; 1123 } 1124 1125 /** 1126 * Get "NEXT MODULE" link in the navigation bar. 1127 * 1128 * @return a content tree for the next link 1129 */ 1130 @Override 1131 public Content getNavLinkNext() { 1132 Content li; 1133 if (nextModule == null) { 1134 li = HtmlTree.LI(contents.nextModuleLabel); 1135 } else { 1136 li = HtmlTree.LI(getHyperLink(pathToRoot.resolve(DocPaths.moduleSummary( 1137 nextModule)), contents.nextModuleLabel, "", "")); 1138 } 1139 return li; 1140 } 1141 }