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, Content htmltree) { 461 htmltree.addContent(startMarker); 462 htmltree.addContent(getMarkerAnchor(markerAnchor)); 463 htmltree.addContent(HtmlTree.HEADING(HtmlTag.H3, heading)); 464 } 465 466 /** 467 * Get table header. 468 * 469 * @param text the table caption 470 * @param tableSummary the summary for the table 471 * @param tableStyle the table style 472 * @param tableHeader the table header 473 * @return a content object 474 */ 475 public Content getTableHeader(String text, String tableSummary, HtmlStyle tableStyle, 476 List<String> tableHeader) { 477 return getTableHeader(getTableCaption(new RawHtml(text)), tableSummary, tableStyle, tableHeader); 478 } 479 480 /** 481 * Get table header. 482 * 483 * @param caption the table caption 484 * @param tableSummary the summary for the table 485 * @param tableStyle the table style 486 * @param tableHeader the table header 487 * @return a content object 488 */ 489 public Content getTableHeader(Content caption, String tableSummary, HtmlStyle tableStyle, 490 List<String> tableHeader) { 491 Content table = (configuration.isOutputHtml5()) 492 ? HtmlTree.TABLE(tableStyle, caption) 493 : HtmlTree.TABLE(tableStyle, tableSummary, caption); 494 table.addContent(getSummaryTableHeader(tableHeader, "col")); 495 return table; 496 } 497 498 /** 499 * {@inheritDoc} 500 */ 501 public void addModulesSummary(Content summaryContentTree) { 502 if (display(requires) || display(indirectModules)) { 503 HtmlTree li = new HtmlTree(HtmlTag.LI); 504 li.addStyle(HtmlStyle.blockList); 505 addSummaryHeader(HtmlConstants.START_OF_MODULES_SUMMARY, SectionName.MODULES, 506 contents.navModules, li); 507 if (display(requires)) { 508 String text = configuration.getText("doclet.Requires_Summary"); 509 String tableSummary = configuration.getText("doclet.Member_Table_Summary", 510 configuration.getText("doclet.Requires_Summary"), 511 configuration.getText("doclet.modules")); 512 Content table = getTableHeader(text, tableSummary, HtmlStyle.requiresSummary, requiresTableHeader); 513 Content tbody = new HtmlTree(HtmlTag.TBODY); 514 addModulesList(requires, tbody); 515 table.addContent(tbody); 516 li.addContent(table); 517 } 518 // Display indirect modules table in both "api" and "all" mode. 519 if (display(indirectModules)) { 520 String amrText = configuration.getText("doclet.Indirect_Requires_Summary"); 521 String amrTableSummary = configuration.getText("doclet.Member_Table_Summary", 522 configuration.getText("doclet.Indirect_Requires_Summary"), 523 configuration.getText("doclet.modules")); 524 Content amrTable = getTableHeader(amrText, amrTableSummary, HtmlStyle.requiresSummary, requiresTableHeader); 525 Content amrTbody = new HtmlTree(HtmlTag.TBODY); 526 addModulesList(indirectModules, amrTbody); 527 amrTable.addContent(amrTbody); 528 li.addContent(amrTable); 529 } 530 HtmlTree ul = HtmlTree.UL(HtmlStyle.blockList, li); 531 summaryContentTree.addContent(ul); 532 } 533 } 534 535 /** 536 * Add the list of modules. 537 * 538 * @param mdleMap map of modules and modifiers 539 * @param tbody the content tree to which the list will be added 540 */ 541 public void addModulesList(Map<ModuleElement, Content> mdleMap, Content tbody) { 542 boolean altColor = true; 543 for (ModuleElement m : mdleMap.keySet()) { 544 Content tdModifiers = HtmlTree.TD(HtmlStyle.colFirst, mdleMap.get(m)); 545 Content moduleLinkContent = getModuleLink(m, new StringContent(m.getQualifiedName())); 546 Content thModule = HtmlTree.TH_ROW_SCOPE(HtmlStyle.colSecond, moduleLinkContent); 547 HtmlTree tdSummary = new HtmlTree(HtmlTag.TD); 548 tdSummary.addStyle(HtmlStyle.colLast); 549 addSummaryComment(m, tdSummary); 550 HtmlTree tr = HtmlTree.TR(tdModifiers); 551 tr.addContent(thModule); 552 tr.addContent(tdSummary); 553 tr.addStyle(altColor ? HtmlStyle.altColor : HtmlStyle.rowColor); 554 tbody.addContent(tr); 555 altColor = !altColor; 556 } 557 } 558 559 public void addPackagesSummary(Content summaryContentTree) { 560 if (display(exportedPackages) || display(openedPackages) || display(concealedPackages) 561 || display(indirectPackages) || display(indirectOpenPackages)) { 562 HtmlTree li = new HtmlTree(HtmlTag.LI); 563 li.addStyle(HtmlStyle.blockList); 564 addSummaryHeader(HtmlConstants.START_OF_PACKAGES_SUMMARY, SectionName.PACKAGES, 565 contents.navPackages, li); 566 String tableSummary = configuration.getText("doclet.Member_Table_Summary", 567 configuration.getText("doclet.Packages_Summary"), 568 configuration.getText("doclet.packages")); 569 if (display(exportedPackages) || display(openedPackages) || display(concealedPackages)) { 570 addPackageSummary(tableSummary, li); 571 } 572 if (display(indirectPackages)) { 573 String aepText = configuration.getText("doclet.Indirect_Exports_Summary"); 574 String aepTableSummary = configuration.getText("doclet.Indirect_Packages_Table_Summary", 575 configuration.getText("doclet.Indirect_Exports_Summary"), 576 configuration.getText("doclet.modules"), 577 configuration.getText("doclet.packages")); 578 Content aepTable = getTableHeader(aepText, aepTableSummary, HtmlStyle.packagesSummary, 579 indirectPackagesTableHeader); 580 Content aepTbody = new HtmlTree(HtmlTag.TBODY); 581 addIndirectPackages(aepTbody, indirectPackages); 582 aepTable.addContent(aepTbody); 583 li.addContent(aepTable); 584 } 585 if (display(indirectOpenPackages)) { 586 String aopText = configuration.getText("doclet.Indirect_Opens_Summary"); 587 String aopTableSummary = configuration.getText("doclet.Indirect_Packages_Table_Summary", 588 configuration.getText("doclet.Indirect_Opens_Summary"), 589 configuration.getText("doclet.modules"), 590 configuration.getText("doclet.packages")); 591 Content aopTable = getTableHeader(aopText, aopTableSummary, HtmlStyle.packagesSummary, 592 indirectPackagesTableHeader); 593 Content aopTbody = new HtmlTree(HtmlTag.TBODY); 594 addIndirectPackages(aopTbody, indirectOpenPackages); 595 aopTable.addContent(aopTbody); 596 li.addContent(aopTable); 597 } 598 HtmlTree ul = HtmlTree.UL(HtmlStyle.blockList, li); 599 summaryContentTree.addContent(ul); 600 } 601 } 602 603 /** 604 * Add the package summary for the module. 605 * 606 * @param tableSummary 607 * @param li 608 */ 609 public void addPackageSummary(String tableSummary, HtmlTree li) { 610 Content caption; 611 Content tbody = getPackageTableRows(); 612 if (showTabs()) { 613 caption = getTableCaption(); 614 generateTableTabTypesScript(typeMap, modulePackageTypes, "packages"); 615 } else { 616 ModulePackageTypes type = modulePackageTypes.iterator().next(); 617 caption = getTableCaption(configuration.getContent(type.tableTabs().resourceKey())); 618 } 619 Content table = getTableHeader(caption, tableSummary, HtmlStyle.packagesSummary, exportedPackagesTableHeader); 620 table.addContent(tbody); 621 li.addContent(table); 622 } 623 624 /** 625 * Returns true if the table tabs needs to be displayed. 626 * 627 * @return true if the tabs should be displayed 628 */ 629 public boolean showTabs() { 630 int value; 631 for (ModulePackageTypes type : EnumSet.allOf(ModulePackageTypes.class)) { 632 value = type.tableTabs().value(); 633 if ((value & packageTypesOr) == value) { 634 modulePackageTypes.add(type); 635 } 636 } 637 boolean showTabs = modulePackageTypes.size() > 1; 638 if (showTabs) { 639 modulePackageTypes.add(ModulePackageTypes.ALL); 640 } 641 return showTabs; 642 } 643 644 /** 645 * Get the summary table caption. 646 * 647 * @return the caption for the summary table 648 */ 649 public Content getTableCaption() { 650 Content tabbedCaption = new HtmlTree(HtmlTag.CAPTION); 651 for (ModulePackageTypes type : modulePackageTypes) { 652 Content captionSpan; 653 Content span; 654 if (type.tableTabs().isDefaultTab()) { 655 captionSpan = HtmlTree.SPAN(configuration.getContent(type.tableTabs().resourceKey())); 656 span = HtmlTree.SPAN(type.tableTabs().tabId(), 657 HtmlStyle.activeTableTab, captionSpan); 658 } else { 659 captionSpan = HtmlTree.SPAN(getPackageTypeLinks(type)); 660 span = HtmlTree.SPAN(type.tableTabs().tabId(), 661 HtmlStyle.tableTab, captionSpan); 662 } 663 Content tabSpan = HtmlTree.SPAN(HtmlStyle.tabEnd, Contents.SPACE); 664 span.addContent(tabSpan); 665 tabbedCaption.addContent(span); 666 } 667 return tabbedCaption; 668 } 669 670 /** 671 * Get the package type links for the table caption. 672 * 673 * @param packageType the package type to be displayed as link 674 * @return the content tree for the package type link 675 */ 676 public Content getPackageTypeLinks(ModulePackageTypes packageType) { 677 String jsShow = "javascript:showPkgs(" + packageType.tableTabs().value() + ");"; 678 HtmlTree link = HtmlTree.A(jsShow, configuration.getContent(packageType.tableTabs().resourceKey())); 679 return link; 680 } 681 682 /** 683 * Get the package table rows. 684 * 685 * @return a content object 686 */ 687 public Content getPackageTableRows() { 688 Content tbody = new HtmlTree(HtmlTag.TBODY); 689 boolean altColor = true; 690 int counter = 0; 691 counter = addPackageTableRows(tbody, counter, ModulePackageTypes.EXPORTED, exportedPackages); 692 counter = addPackageTableRows(tbody, counter, ModulePackageTypes.OPENED, openedPackages); 693 // Show concealed packages only in "all" mode. 694 if (moduleMode == ModuleMode.ALL) { 695 for (PackageElement pkg : concealedPackages) { 696 Content pkgLinkContent = getPackageLink(pkg, new StringContent(utils.getPackageName(pkg))); 697 Content thPackage = HtmlTree.TH_ROW_SCOPE(HtmlStyle.colFirst, pkgLinkContent); 698 HtmlTree tdModules = new HtmlTree(HtmlTag.TD); 699 tdModules.addStyle(HtmlStyle.colSecond); 700 tdModules.addContent(configuration.getText("doclet.None")); 701 HtmlTree tdSummary = new HtmlTree(HtmlTag.TD); 702 tdSummary.addStyle(HtmlStyle.colLast); 703 addSummaryComment(pkg, tdSummary); 704 HtmlTree tr = HtmlTree.TR(thPackage); 705 tr.addContent(tdModules); 706 tr.addContent(tdSummary); 707 tr.addStyle(altColor ? HtmlStyle.altColor : HtmlStyle.rowColor); 708 int pkgType = ModulePackageTypes.CONCEALED.tableTabs().value(); 709 packageTypesOr = packageTypesOr | pkgType; 710 String tableId = "i" + counter; 711 counter++; 712 typeMap.put(tableId, pkgType); 713 tr.addAttr(HtmlAttr.ID, tableId); 714 tbody.addContent(tr); 715 altColor = !altColor; 716 } 717 } 718 return tbody; 719 } 720 721 public int addPackageTableRows(Content tbody, int counter, ModulePackageTypes pType, 722 Map<PackageElement,SortedSet<ModuleElement>> ap) { 723 boolean altColor = true; 724 for (Map.Entry<PackageElement, SortedSet<ModuleElement>> entry : ap.entrySet()) { 725 PackageElement pkg = entry.getKey(); 726 SortedSet<ModuleElement> mdleList = entry.getValue(); 727 Content pkgLinkContent = getPackageLink(pkg, new StringContent(utils.getPackageName(pkg))); 728 Content thPackage = HtmlTree.TH_ROW_SCOPE(HtmlStyle.colFirst, pkgLinkContent); 729 HtmlTree tr = HtmlTree.TR(thPackage); 730 if (moduleMode == ModuleMode.ALL) { 731 HtmlTree tdModules = new HtmlTree(HtmlTag.TD); 732 tdModules.addStyle(HtmlStyle.colSecond); 733 if (!mdleList.isEmpty()) { 734 int sep = 0; 735 for (ModuleElement m : mdleList) { 736 if (sep > 0) { 737 tdModules.addContent(new HtmlTree(HtmlTag.BR)); 738 } 739 tdModules.addContent(getModuleLink(m, new StringContent(m.getQualifiedName()))); 740 sep++; 741 } 742 } else { 743 tdModules.addContent(configuration.getText("doclet.All_Modules")); 744 } 745 tr.addContent(tdModules); 746 } 747 HtmlTree tdSummary = new HtmlTree(HtmlTag.TD); 748 tdSummary.addStyle(HtmlStyle.colLast); 749 addSummaryComment(pkg, tdSummary); 750 tr.addContent(tdSummary); 751 tr.addStyle(altColor ? HtmlStyle.altColor : HtmlStyle.rowColor); 752 int pkgType = pType.tableTabs().value(); 753 packageTypesOr = packageTypesOr | pkgType; 754 String tableId = "i" + counter; 755 counter++; 756 typeMap.put(tableId, pkgType); 757 tr.addAttr(HtmlAttr.ID, tableId); 758 tbody.addContent(tr); 759 altColor = !altColor; 760 } 761 return counter; 762 } 763 764 /** 765 * Add the indirect packages for the module being documented. 766 * 767 * @param tbody the content tree to which the table will be added 768 * @param ip indirect packages to be added 769 */ 770 public void addIndirectPackages(Content tbody, Map<ModuleElement, SortedSet<PackageElement>> ip) { 771 boolean altColor = true; 772 for (Map.Entry<ModuleElement, SortedSet<PackageElement>> entry : ip.entrySet()) { 773 ModuleElement m = entry.getKey(); 774 SortedSet<PackageElement> pkgList = entry.getValue(); 775 Content moduleLinkContent = getModuleLink(m, new StringContent(m.getQualifiedName())); 776 Content thModule = HtmlTree.TH_ROW_SCOPE(HtmlStyle.colFirst, moduleLinkContent); 777 HtmlTree tdPackages = new HtmlTree(HtmlTag.TD); 778 tdPackages.addStyle(HtmlStyle.colLast); 779 String sep = ""; 780 for (PackageElement pkg : pkgList) { 781 tdPackages.addContent(sep); 782 tdPackages.addContent(getPackageLink(pkg, new StringContent(utils.getPackageName(pkg)))); 783 sep = " "; 784 } 785 HtmlTree tr = HtmlTree.TR(thModule); 786 tr.addContent(tdPackages); 787 tr.addStyle(altColor ? HtmlStyle.altColor : HtmlStyle.rowColor); 788 tbody.addContent(tr); 789 altColor = !altColor; 790 } 791 } 792 793 /** 794 * {@inheritDoc} 795 */ 796 public void addServicesSummary(Content summaryContentTree) { 797 798 boolean haveUses = displayServices(uses, usesTrees); 799 boolean haveProvides = displayServices(provides.keySet(), providesTrees); 800 801 if (haveProvides || haveUses) { 802 HtmlTree li = new HtmlTree(HtmlTag.LI); 803 li.addStyle(HtmlStyle.blockList); 804 addSummaryHeader(HtmlConstants.START_OF_SERVICES_SUMMARY, SectionName.SERVICES, 805 contents.navServices, li); 806 String text; 807 String tableSummary; 808 if (haveProvides) { 809 text = configuration.getText("doclet.Provides_Summary"); 810 tableSummary = configuration.getText("doclet.Member_Table_Summary", 811 configuration.getText("doclet.Provides_Summary"), 812 configuration.getText("doclet.types")); 813 Content table = getTableHeader(text, tableSummary, HtmlStyle.providesSummary, providesTableHeader); 814 Content tbody = new HtmlTree(HtmlTag.TBODY); 815 addProvidesList(tbody); 816 if (!tbody.isEmpty()) { 817 table.addContent(tbody); 818 li.addContent(table); 819 } 820 } 821 if (haveUses){ 822 text = configuration.getText("doclet.Uses_Summary"); 823 tableSummary = configuration.getText("doclet.Member_Table_Summary", 824 configuration.getText("doclet.Uses_Summary"), 825 configuration.getText("doclet.types")); 826 Content table = getTableHeader(text, tableSummary, HtmlStyle.usesSummary, usesTableHeader); 827 Content tbody = new HtmlTree(HtmlTag.TBODY); 828 addUsesList(tbody); 829 if (!tbody.isEmpty()) { 830 table.addContent(tbody); 831 li.addContent(table); 832 } 833 } 834 HtmlTree ul = HtmlTree.UL(HtmlStyle.blockList, li); 835 summaryContentTree.addContent(ul); 836 } 837 } 838 839 /** 840 * Add the uses list for the module. 841 * 842 * @param tbody the content tree to which the directive will be added 843 */ 844 public void addUsesList(Content tbody) { 845 boolean altColor = true; 846 Content typeLinkContent; 847 Content thType; 848 HtmlTree tdSummary; 849 Content description; 850 for (TypeElement t : uses) { 851 if (!displayServiceDirective(t, usesTrees)) { 852 continue; 853 } 854 typeLinkContent = getLink(new LinkInfoImpl(configuration, LinkInfoImpl.Kind.PACKAGE, t)); 855 thType = HtmlTree.TH_ROW_SCOPE(HtmlStyle.colFirst, typeLinkContent); 856 tdSummary = new HtmlTree(HtmlTag.TD); 857 tdSummary.addStyle(HtmlStyle.colLast); 858 if (display(usesTrees)) { 859 description = usesTrees.get(t); 860 if (description != null) { 861 tdSummary.addContent(description); 862 } 863 } 864 addSummaryComment(t, tdSummary); 865 HtmlTree tr = HtmlTree.TR(thType); 866 tr.addContent(tdSummary); 867 tr.addStyle(altColor ? HtmlStyle.altColor : HtmlStyle.rowColor); 868 tbody.addContent(tr); 869 altColor = !altColor; 870 } 871 } 872 873 /** 874 * Add the provides list for the module. 875 * 876 * @param tbody the content tree to which the directive will be added 877 */ 878 public void addProvidesList(Content tbody) { 879 boolean altColor = true; 880 SortedSet<TypeElement> implSet; 881 Content description; 882 for (Map.Entry<TypeElement, SortedSet<TypeElement>> entry : provides.entrySet()) { 883 TypeElement srv = entry.getKey(); 884 if (!displayServiceDirective(srv, providesTrees)) { 885 continue; 886 } 887 implSet = entry.getValue(); 888 Content srvLinkContent = getLink(new LinkInfoImpl(configuration, LinkInfoImpl.Kind.PACKAGE, srv)); 889 HtmlTree thType = HtmlTree.TH_ROW_SCOPE(HtmlStyle.colFirst, srvLinkContent); 890 HtmlTree tdDesc = new HtmlTree(HtmlTag.TD); 891 tdDesc.addStyle(HtmlStyle.colLast); 892 if (display(providesTrees)) { 893 description = providesTrees.get(srv); 894 if (description != null) { 895 tdDesc.addContent(description); 896 } 897 } 898 addSummaryComment(srv, tdDesc); 899 // Only display the implementation details in the "all" mode. 900 if (moduleMode == ModuleMode.ALL && !implSet.isEmpty()) { 901 tdDesc.addContent(new HtmlTree(HtmlTag.BR)); 902 tdDesc.addContent("("); 903 HtmlTree implSpan = HtmlTree.SPAN(HtmlStyle.implementationLabel, contents.implementation); 904 tdDesc.addContent(implSpan); 905 tdDesc.addContent(Contents.SPACE); 906 String sep = ""; 907 for (TypeElement impl : implSet) { 908 tdDesc.addContent(sep); 909 tdDesc.addContent(getLink(new LinkInfoImpl(configuration, LinkInfoImpl.Kind.PACKAGE, impl))); 910 sep = ", "; 911 } 912 tdDesc.addContent(")"); 913 } 914 HtmlTree tr = HtmlTree.TR(thType); 915 tr.addContent(tdDesc); 916 tr.addStyle(altColor ? HtmlStyle.altColor : HtmlStyle.rowColor); 917 tbody.addContent(tr); 918 altColor = !altColor; 919 } 920 } 921 922 /** 923 * Add the module deprecation information to the documentation tree. 924 * 925 * @param div the content tree to which the deprecation information will be added 926 */ 927 public void addDeprecationInfo(Content div) { 928 List<? extends DocTree> deprs = utils.getBlockTags(mdle, DocTree.Kind.DEPRECATED); 929 if (utils.isDeprecated(mdle)) { 930 CommentHelper ch = utils.getCommentHelper(mdle); 931 HtmlTree deprDiv = new HtmlTree(HtmlTag.DIV); 932 deprDiv.addStyle(HtmlStyle.deprecationBlock); 933 Content deprPhrase = HtmlTree.SPAN(HtmlStyle.deprecatedLabel, getDeprecatedPhrase(mdle)); 934 deprDiv.addContent(deprPhrase); 935 if (!deprs.isEmpty()) { 936 List<? extends DocTree> commentTags = ch.getDescription(configuration, deprs.get(0)); 937 if (!commentTags.isEmpty()) { 938 addInlineDeprecatedComment(mdle, deprs.get(0), deprDiv); 939 } 940 } 941 div.addContent(deprDiv); 942 } 943 } 944 945 /** 946 * {@inheritDoc} 947 */ 948 @Override 949 public void addModuleDescription(Content moduleContentTree) { 950 if (!utils.getFullBody(mdle).isEmpty()) { 951 Content tree = configuration.allowTag(HtmlTag.SECTION) ? HtmlTree.SECTION() : moduleContentTree; 952 addDeprecationInfo(tree); 953 tree.addContent(HtmlConstants.START_OF_MODULE_DESCRIPTION); 954 tree.addContent(getMarkerAnchor(SectionName.MODULE_DESCRIPTION)); 955 addInlineComment(mdle, tree); 956 if (configuration.allowTag(HtmlTag.SECTION)) { 957 moduleContentTree.addContent(tree); 958 } 959 } 960 } 961 962 /** 963 * {@inheritDoc} 964 */ 965 @Override 966 public void addModuleTags(Content moduleContentTree) { 967 Content tree = (configuration.allowTag(HtmlTag.SECTION)) 968 ? HtmlTree.SECTION() 969 : moduleContentTree; 970 addTagsInfo(mdle, tree); 971 if (configuration.allowTag(HtmlTag.SECTION)) { 972 moduleContentTree.addContent(tree); 973 } 974 } 975 976 /** 977 * Add summary details to the navigation bar. 978 * 979 * @param subDiv the content tree to which the summary detail links will be added 980 */ 981 @Override 982 protected void addSummaryDetailLinks(Content subDiv) { 983 Content div = HtmlTree.DIV(getNavSummaryLinks()); 984 subDiv.addContent(div); 985 } 986 987 /** 988 * Get summary links for navigation bar. 989 * 990 * @return the content tree for the navigation summary links 991 */ 992 protected Content getNavSummaryLinks() { 993 Content li = HtmlTree.LI(contents.moduleSubNavLabel); 994 li.addContent(Contents.SPACE); 995 Content ulNav = HtmlTree.UL(HtmlStyle.subNavList, li); 996 Content liNav = new HtmlTree(HtmlTag.LI); 997 liNav.addContent(!utils.getFullBody(mdle).isEmpty() && !configuration.nocomment 998 ? getHyperLink(SectionName.MODULE_DESCRIPTION, contents.navModuleDescription) 999 : contents.navModuleDescription); 1000 addNavGap(liNav); 1001 liNav.addContent((display(requires) || display(indirectModules)) 1002 ? getHyperLink(SectionName.MODULES, contents.navModules) 1003 : contents.navModules); 1004 addNavGap(liNav); 1005 liNav.addContent((display(exportedPackages) || display(openedPackages) || display(concealedPackages) 1006 || display(indirectPackages) || display(indirectOpenPackages)) 1007 ? getHyperLink(SectionName.PACKAGES, contents.navPackages) 1008 : contents.navPackages); 1009 addNavGap(liNav); 1010 liNav.addContent((displayServices(uses, usesTrees) || displayServices(provides.keySet(), providesTrees)) 1011 ? getHyperLink(SectionName.SERVICES, contents.navServices) 1012 : contents.navServices); 1013 ulNav.addContent(liNav); 1014 return ulNav; 1015 } 1016 1017 /** 1018 * {@inheritDoc} 1019 */ 1020 @Override 1021 public void addModuleContent(Content contentTree, Content moduleContentTree) { 1022 if (configuration.allowTag(HtmlTag.MAIN)) { 1023 mainTree.addContent(moduleContentTree); 1024 contentTree.addContent(mainTree); 1025 } else { 1026 contentTree.addContent(moduleContentTree); 1027 } 1028 } 1029 1030 /** 1031 * {@inheritDoc} 1032 */ 1033 @Override 1034 public void addModuleFooter(Content contentTree) { 1035 Content htmlTree = (configuration.allowTag(HtmlTag.FOOTER)) 1036 ? HtmlTree.FOOTER() 1037 : contentTree; 1038 addNavLinks(false, htmlTree); 1039 addBottom(htmlTree); 1040 if (configuration.allowTag(HtmlTag.FOOTER)) { 1041 contentTree.addContent(htmlTree); 1042 } 1043 } 1044 1045 /** 1046 * {@inheritDoc} 1047 * 1048 * @throws jdk.javadoc.internal.doclets.toolkit.util.DocFileIOException 1049 */ 1050 @Override 1051 public void printDocument(Content contentTree) throws DocFileIOException { 1052 printHtmlDocument(configuration.metakeywords.getMetaKeywordsForModule(mdle), 1053 true, contentTree); 1054 } 1055 1056 /** 1057 * Add the module package deprecation information to the documentation tree. 1058 * 1059 * @param li the content tree to which the deprecation information will be added 1060 * @param pkg the PackageDoc that is added 1061 */ 1062 public void addPackageDeprecationInfo(Content li, PackageElement pkg) { 1063 List<? extends DocTree> deprs; 1064 if (utils.isDeprecated(pkg)) { 1065 deprs = utils.getDeprecatedTrees(pkg); 1066 HtmlTree deprDiv = new HtmlTree(HtmlTag.DIV); 1067 deprDiv.addStyle(HtmlStyle.deprecationBlock); 1068 Content deprPhrase = HtmlTree.SPAN(HtmlStyle.deprecatedLabel, getDeprecatedPhrase(pkg)); 1069 deprDiv.addContent(deprPhrase); 1070 if (!deprs.isEmpty()) { 1071 CommentHelper ch = utils.getCommentHelper(pkg); 1072 List<? extends DocTree> commentTags = ch.getDescription(configuration, deprs.get(0)); 1073 if (!commentTags.isEmpty()) { 1074 addInlineDeprecatedComment(pkg, deprs.get(0), deprDiv); 1075 } 1076 } 1077 li.addContent(deprDiv); 1078 } 1079 } 1080 1081 /** 1082 * Get this module link. 1083 * 1084 * @return a content tree for the module link 1085 */ 1086 @Override 1087 protected Content getNavLinkModule() { 1088 Content li = HtmlTree.LI(HtmlStyle.navBarCell1Rev, contents.moduleLabel); 1089 return li; 1090 } 1091 1092 /** 1093 * Get "PREV MODULE" link in the navigation bar. 1094 * 1095 * @return a content tree for the previous link 1096 */ 1097 @Override 1098 public Content getNavLinkPrevious() { 1099 Content li; 1100 if (prevModule == null) { 1101 li = HtmlTree.LI(contents.prevModuleLabel); 1102 } else { 1103 li = HtmlTree.LI(getHyperLink(pathToRoot.resolve(DocPaths.moduleSummary( 1104 prevModule)), contents.prevModuleLabel, "", "")); 1105 } 1106 return li; 1107 } 1108 1109 /** 1110 * Get "NEXT MODULE" link in the navigation bar. 1111 * 1112 * @return a content tree for the next link 1113 */ 1114 @Override 1115 public Content getNavLinkNext() { 1116 Content li; 1117 if (nextModule == null) { 1118 li = HtmlTree.LI(contents.nextModuleLabel); 1119 } else { 1120 li = HtmlTree.LI(getHyperLink(pathToRoot.resolve(DocPaths.moduleSummary( 1121 nextModule)), contents.nextModuleLabel, "", "")); 1122 } 1123 return li; 1124 } 1125 }