ModuleWriterImpl.java revision 3831:209b0eab0e1f
194742Sobrien/*
294742Sobrien * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
394742Sobrien * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
495253Sru *
594742Sobrien * This code is free software; you can redistribute it and/or modify it
696991Srwatson * under the terms of the GNU General Public License version 2 only, as
796991Srwatson * published by the Free Software Foundation.  Oracle designates this
896991Srwatson * particular file as subject to the "Classpath" exception as provided
9102773Srwatson * by Oracle in the LICENSE file that accompanied this code.
10102773Srwatson *
1194854Ssos * This code is distributed in the hope that it will be useful, but WITHOUT
1294917Simp * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13126445Sobrien * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
1494917Simp * version 2 for more details (a copy is included in the LICENSE file that
1594917Simp * accompanied this code).
1694917Simp *
17117751Smarkm * You should have received a copy of the GNU General Public License version
18117751Smarkm * 2 along with this work; if not, write to the Free Software Foundation,
19116149Smarkm * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20116149Smarkm *
21125244Snectar * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22125244Snectar * or visit www.oracle.com if you need additional information or have any
2394847Sjhb * questions.
2494847Sjhb */
2594847Sjhb
26126337Svkashyappackage jdk.javadoc.internal.doclets.formats.html;
27128023Svkashyap
2894855Sscottlimport java.util.EnumSet;
29126054Sscottlimport java.util.LinkedHashMap;
30126054Sscottlimport java.util.List;
31126054Sscottlimport java.util.Map;
32126054Sscottlimport java.util.Set;
33126054Sscottlimport java.util.SortedSet;
34126054Sscottlimport java.util.TreeMap;
3594915Skenimport java.util.TreeSet;
3699607Smjacob
3794915Skenimport javax.lang.model.element.Element;
3894915Skenimport javax.lang.model.element.ModuleElement;
3994915Skenimport javax.lang.model.element.PackageElement;
4094915Skenimport javax.lang.model.element.TypeElement;
4194915Skenimport javax.lang.model.util.ElementFilter;
4294915Sken
4394915Skenimport com.sun.source.doctree.DocTree;
4494915Skenimport jdk.javadoc.doclet.DocletEnvironment.ModuleMode;
4599607Smjacobimport jdk.javadoc.internal.doclets.formats.html.markup.HtmlAttr;
46106734Smjacobimport jdk.javadoc.internal.doclets.formats.html.markup.HtmlConstants;
47128435Stackermanimport jdk.javadoc.internal.doclets.formats.html.markup.HtmlStyle;
4897611Sbillfimport jdk.javadoc.internal.doclets.formats.html.markup.HtmlTag;
4994918Sgshapiroimport jdk.javadoc.internal.doclets.formats.html.markup.HtmlTree;
5094918Sgshapiroimport jdk.javadoc.internal.doclets.formats.html.markup.RawHtml;
5194918Sgshapiroimport jdk.javadoc.internal.doclets.formats.html.markup.StringContent;
5294918Sgshapiroimport jdk.javadoc.internal.doclets.toolkit.Content;
5394918Sgshapiroimport jdk.javadoc.internal.doclets.toolkit.ModuleSummaryWriter;
54118316Smbrimport jdk.javadoc.internal.doclets.toolkit.util.CommentHelper;
5594955Smurrayimport jdk.javadoc.internal.doclets.toolkit.util.DocFileIOException;
5695054Snectarimport jdk.javadoc.internal.doclets.toolkit.util.DocPaths;
57125080Scpercivaimport jdk.javadoc.internal.doclets.toolkit.util.ModulePackageTypes;
58106187Sdes
59106187Sdes/**
6095455Sdes * Class to generate file for each module contents in the right-hand frame. This will list all the
6198750Sdes * required modules, packages and service types for the module. A click on any of the links will update
6299606Sdes * the frame with the clicked element page.
6399606Sdes *
6499606Sdes *  <p><b>This is NOT part of any supported API.
6596268Sgad *  If you write code that depends on this, you do so at your own risk.
6696268Sgad *  This code and its internal interfaces are subject to change or
67116233Sgad *  deletion without notice.</b>
68139390Sgad *
69139390Sgad * @author Bhavesh Patel
70139390Sgad */
7196332Speterpublic class ModuleWriterImpl extends HtmlDocletWriter implements ModuleSummaryWriter {
7296332Speter
7396332Speter    /**
7496332Speter     * The prev module name in the alpha-order list.
7596332Speter     */
76100314Sru    protected ModuleElement prevModule;
7796451Sru
7897611Sbillf    /**
7998333Sanholt     * The next module name in the alpha-order list.
8098986Sjmallett     */
81111061Sjmallett    protected ModuleElement nextModule;
8299732Sjoerg
8399732Sjoerg    /**
84113692Snectar     * The module being documented.
85113692Snectar     */
86115825Sfanf    protected ModuleElement mdle;
87126445Sobrien
88117645Sdwmalone    /**
89118204Sbp     * The module mode for this javadoc run. It can be set to "api" or "all".
90118204Sbp     */
91118204Sbp    private final ModuleMode moduleMode;
92118204Sbp
93127337Smlaier    /**
94126445Sobrien     * Map of module elements and modifiers required by this module.
95133182Spjd     */
96133182Spjd    private final Map<ModuleElement, Content> requires
97133182Spjd            = new TreeMap<>(utils.makeModuleComparator());
98133182Spjd
99133182Spjd    /**
100133841Spjd     * Map of additional modules and modifiers, transitive closure, required by this module.
101133182Spjd     */
102133182Spjd    private final Map<ModuleElement, Content> additionalModules
103132311Salfred            = new TreeMap<>(utils.makeModuleComparator());
104132311Salfred
105132311Salfred    /**
106132268Salfred     * Map of packages exported by this module and the modules it's been exported to.
107138235Seik     */
108115822Sdougb    private final Map<PackageElement, SortedSet<ModuleElement>> exportedPackages
109115822Sdougb            = new TreeMap<>(utils.makePackageComparator());
110115822Sdougb
111115822Sdougb    /**
112115822Sdougb     * Map of opened packages by this module and the modules it's been opened to.
113115822Sdougb     */
114115822Sdougb    private final Map<PackageElement, SortedSet<ModuleElement>> openedPackages
115115822Sdougb            = new TreeMap<>(utils.makePackageComparator());
116115822Sdougb
117115822Sdougb    /**
118115822Sdougb     * Set of concealed packages of this module.
119115822Sdougb     */
120115822Sdougb    private final SortedSet<PackageElement> concealedPackages = new TreeSet<>(utils.makePackageComparator());
121115822Sdougb
122115822Sdougb    /**
123115822Sdougb     * Map of additional modules (transitive closure) and its exported packages.
124115822Sdougb     */
125115822Sdougb    private final Map<ModuleElement, SortedSet<PackageElement>> additionalPackages
126115822Sdougb            = new TreeMap<>(utils.makeModuleComparator());
127115822Sdougb
128115822Sdougb    /**
129115822Sdougb     * Map of additional modules (transitive closure) and its open packages.
130115895Sguido     */
131115822Sdougb    private final Map<ModuleElement, SortedSet<PackageElement>> additionalOpenPackages
132115895Sguido            = new TreeMap<>(utils.makeModuleComparator());
133115895Sguido
134115895Sguido    /**
135115822Sdougb     * Set of services used by the module.
136115822Sdougb     */
137115822Sdougb    private final SortedSet<TypeElement> uses
138115822Sdougb            = new TreeSet<>(utils.makeAllClassesComparator());
139115822Sdougb
140115822Sdougb    /**
141115822Sdougb     * Map of services used by the module and specified using @uses javadoc tag, and description.
142115822Sdougb     */
143115822Sdougb    private final Map<TypeElement, Content> usesTrees
144115822Sdougb            = new TreeMap<>(utils.makeAllClassesComparator());
145115822Sdougb
146115822Sdougb    /**
147115822Sdougb     * Map of services provided by this module, and set of its implementations.
148115822Sdougb     */
149115822Sdougb    private final Map<TypeElement, SortedSet<TypeElement>> provides
150115822Sdougb            = new TreeMap<>(utils.makeAllClassesComparator());
151115822Sdougb
152115822Sdougb    /**
153115822Sdougb     * Map of services provided by the module and specified using @provides javadoc tag, and
154115822Sdougb     * description.
155115822Sdougb     */
156115822Sdougb    private final Map<TypeElement, Content> providesTrees
157115822Sdougb            = new TreeMap<>(utils.makeAllClassesComparator());
158115822Sdougb
159115822Sdougb    private int packageTypesOr = 0;
160115822Sdougb
161115822Sdougb    protected Set<ModulePackageTypes> modulePackageTypes = EnumSet.noneOf(ModulePackageTypes.class);
162115822Sdougb
163115822Sdougb    protected Map<String, Integer> typeMap = new LinkedHashMap<>();
164115822Sdougb
165115895Sguido    /**
166115895Sguido     * The HTML tree for main tag.
167115895Sguido     */
168115895Sguido    protected HtmlTree mainTree = HtmlTree.MAIN();
169115822Sdougb
170115822Sdougb    /**
171115822Sdougb     * The HTML tree for section tag.
172115822Sdougb     */
173    protected HtmlTree sectionTree = HtmlTree.SECTION();
174
175    /**
176     * Constructor to construct ModuleWriter object and to generate "moduleName-summary.html" file.
177     *
178     * @param configuration the configuration of the doclet.
179     * @param mdle        Module under consideration.
180     * @param prevModule   Previous module in the sorted array.
181     * @param nextModule   Next module in the sorted array.
182     */
183    public ModuleWriterImpl(ConfigurationImpl configuration,
184            ModuleElement mdle, ModuleElement prevModule, ModuleElement nextModule) {
185        super(configuration, DocPaths.moduleSummary(mdle));
186        this.prevModule = prevModule;
187        this.nextModule = nextModule;
188        this.mdle = mdle;
189        this.moduleMode = configuration.docEnv.getModuleMode();
190        computeModulesData();
191    }
192
193    /**
194     * Get the module header.
195     *
196     * @param heading the heading for the section
197     */
198    @Override
199    public Content getModuleHeader(String heading) {
200        HtmlTree bodyTree = getBody(true, getWindowTitle(mdle.getQualifiedName().toString()));
201        HtmlTree htmlTree = (configuration.allowTag(HtmlTag.HEADER))
202                ? HtmlTree.HEADER()
203                : bodyTree;
204        addTop(htmlTree);
205        addNavLinks(true, htmlTree);
206        if (configuration.allowTag(HtmlTag.HEADER)) {
207            bodyTree.addContent(htmlTree);
208        }
209        HtmlTree div = new HtmlTree(HtmlTag.DIV);
210        div.addStyle(HtmlStyle.header);
211        Content annotationContent = new HtmlTree(HtmlTag.P);
212        addAnnotationInfo(mdle, annotationContent);
213        div.addContent(annotationContent);
214        Content tHeading = HtmlTree.HEADING(HtmlConstants.TITLE_HEADING, true,
215                HtmlStyle.title, contents.moduleLabel);
216        tHeading.addContent(Contents.SPACE);
217        Content moduleHead = new RawHtml(heading);
218        tHeading.addContent(moduleHead);
219        div.addContent(tHeading);
220        if (configuration.allowTag(HtmlTag.MAIN)) {
221            mainTree.addContent(div);
222        } else {
223            bodyTree.addContent(div);
224        }
225        return bodyTree;
226    }
227
228    /**
229     * Get the content header.
230     */
231    @Override
232    public Content getContentHeader() {
233        HtmlTree div = new HtmlTree(HtmlTag.DIV);
234        div.addStyle(HtmlStyle.contentContainer);
235        return div;
236    }
237
238    /**
239     * Get the summary section header.
240     */
241    @Override
242    public Content getSummaryHeader() {
243        HtmlTree li = new HtmlTree(HtmlTag.LI);
244        li.addStyle(HtmlStyle.blockList);
245        return li;
246    }
247
248    /**
249     * Get the summary tree.
250     *
251     * @param summaryContentTree the content tree to be added to the summary tree.
252     */
253    @Override
254    public Content getSummaryTree(Content summaryContentTree) {
255        HtmlTree ul = HtmlTree.UL(HtmlStyle.blockList, summaryContentTree);
256        return ul;
257    }
258
259    /**
260     * Compute the modules data that will be displayed in various tables on the module summary page.
261     */
262    public void computeModulesData() {
263        CommentHelper ch = utils.getCommentHelper(mdle);
264        // Get module dependencies using the module's transitive closure.
265        Map<ModuleElement, String> dependentModules = utils.getDependentModules(mdle);
266        // Add all dependent modules to additional modules set. We will remove the modules,
267        // listed using the requires directive, from this set to come up with the table of additional
268        // required modules.
269        dependentModules.forEach((module, mod) -> {
270            if (shouldDocument(module)) {
271                additionalModules.put(module, new StringContent(mod));
272            }
273        });
274        (ElementFilter.requiresIn(mdle.getDirectives())).forEach((directive) -> {
275            ModuleElement m = directive.getDependency();
276            if (shouldDocument(m)) {
277                if (moduleMode == ModuleMode.ALL || directive.isTransitive()) {
278                    requires.put(m, new StringContent(utils.getModifiers(directive)));
279            } else {
280                // For api mode, just keep the public requires in dependentModules for display of
281                    // additional packages in the "Packages" section.
282                    dependentModules.remove(m);
283            }
284                additionalModules.remove(m);
285        }
286        });
287        // Get all packages for the module and put it in the concealed packages set.
288        (utils.getModulePackageMap().get(mdle)).forEach((pkg) -> {
289            if (shouldDocument(pkg)) {
290                concealedPackages.add(pkg);
291            }
292        });
293        // Get all exported packages for the module using the exports directive for the module.
294        (ElementFilter.exportsIn(mdle.getDirectives())).forEach((directive) -> {
295            PackageElement p = directive.getPackage();
296            if (shouldDocument(p)) {
297                SortedSet<ModuleElement> mdleList = new TreeSet<>(utils.makeModuleComparator());
298                List<? extends ModuleElement> targetMdles = directive.getTargetModules();
299                if (targetMdles != null) {
300                    mdleList.addAll(targetMdles);
301                }
302                // Qualified exports should not be displayed in the api mode. So if mdleList is empty,
303                // its exported to all modules and hence can be added.
304                if (moduleMode == ModuleMode.ALL || mdleList.isEmpty()) {
305                    exportedPackages.put(p, mdleList);
306                }
307                concealedPackages.remove(p);
308            }
309        });
310        // Get all opened packages for the module using the opens directive for the module.
311        (ElementFilter.opensIn(mdle.getDirectives())).forEach((directive) -> {
312            PackageElement p = directive.getPackage();
313            if (shouldDocument(p)) {
314                SortedSet<ModuleElement> mdleList = new TreeSet<>(utils.makeModuleComparator());
315                List<? extends ModuleElement> targetMdles = directive.getTargetModules();
316                if (targetMdles != null) {
317                    mdleList.addAll(targetMdles);
318                }
319                // Qualified opens should not be displayed in the api mode. So if mdleList is empty,
320                // it's opened to all modules and hence can be added.
321                if (moduleMode == ModuleMode.ALL || mdleList.isEmpty()) {
322                    openedPackages.put(p, mdleList);
323                }
324                concealedPackages.remove(p);
325            }
326        });
327        // Remove all the exported and opened packages so we have just the concealed packages now.
328        concealedPackages.removeAll(exportedPackages.keySet());
329        concealedPackages.removeAll(openedPackages.keySet());
330        // Get all the exported and opened packages, for the transitive closure of the module, to be displayed in
331        // the additional packages tables.
332        dependentModules.forEach((module, mod) -> {
333            SortedSet<PackageElement> pkgList = new TreeSet<>(utils.makePackageComparator());
334            (ElementFilter.exportsIn(module.getDirectives())).forEach((directive) -> {
335                PackageElement pkg = directive.getPackage();
336                if (shouldDocument(pkg)) {
337                    pkgList.add(pkg);
338                }
339            });
340            // If none of the transitive modules have exported packages to be displayed, we should not be
341            // displaying the table and so it should not be added to the map.
342            if (!pkgList.isEmpty()) {
343                additionalPackages.put(module, pkgList);
344            }
345            SortedSet<PackageElement> openPkgList = new TreeSet<>(utils.makePackageComparator());
346            (ElementFilter.opensIn(module.getDirectives())).forEach((directive) -> {
347                PackageElement pkg = directive.getPackage();
348                if (shouldDocument(pkg)) {
349                    openPkgList.add(pkg);
350                }
351            });
352            // If none of the transitive modules have opened packages to be displayed, we should not be
353            // displaying the table and so it should not be added to the map.
354            if (!openPkgList.isEmpty()) {
355                additionalOpenPackages.put(module, openPkgList);
356            }
357        });
358        // Get all the services listed as uses directive.
359        (ElementFilter.usesIn(mdle.getDirectives())).forEach((directive) -> {
360            TypeElement u = directive.getService();
361            if (shouldDocument(u)) {
362                uses.add(u);
363            }
364        });
365        // Get all the services and implementations listed as provides directive.
366        (ElementFilter.providesIn(mdle.getDirectives())).forEach((directive) -> {
367            TypeElement u = directive.getService();
368            if (shouldDocument(u)) {
369                List<? extends TypeElement> implList = directive.getImplementations();
370                SortedSet<TypeElement> implSet = new TreeSet<>(utils.makeAllClassesComparator());
371                implSet.addAll(implList);
372                provides.put(u, implSet);
373            }
374        });
375        // Generate the map of all services listed using @provides, and the description.
376        (utils.getBlockTags(mdle, DocTree.Kind.PROVIDES)).forEach((tree) -> {
377            TypeElement t = ch.getServiceType(configuration, tree);
378            if (t != null) {
379                providesTrees.put(t, commentTagsToContent(tree, mdle, ch.getDescription(configuration, tree), false));
380            }
381        });
382        // Generate the map of all services listed using @uses, and the description.
383        (utils.getBlockTags(mdle, DocTree.Kind.USES)).forEach((tree) -> {
384            TypeElement t = ch.getServiceType(configuration, tree);
385            if (t != null) {
386                usesTrees.put(t, commentTagsToContent(tree, mdle, ch.getDescription(configuration, tree), false));
387            }
388        });
389    }
390
391    /**
392     * Returns true if the element should be documented on the module summary page.
393     *
394     * @param element the element to be checked
395     * @return true if the element should be documented
396     */
397    public boolean shouldDocument(Element element) {
398        return (moduleMode == ModuleMode.ALL || utils.isIncluded(element));
399    }
400
401    /**
402     * Returns true if there are elements to be displayed.
403     *
404     * @param section set of elements
405     * @return true if there are elements to be displayed
406     */
407    public boolean display(SortedSet<? extends Element> section) {
408        return section != null && !section.isEmpty();
409    }
410
411    /**
412     * Returns true if there are elements to be displayed.
413     *
414     * @param section map of elements.
415     * @return true if there are elements to be displayed
416     */
417    public boolean display(Map<? extends Element, ?> section) {
418        return section != null && !section.isEmpty();
419    }
420
421    /**
422     * Add the summary header.
423     *
424     * @param startMarker the marker comment
425     * @param markerAnchor the marker anchor for the section
426     * @param heading the heading for the section
427     * @param htmltree the content tree to which the information is added
428     */
429    public void addSummaryHeader(Content startMarker, SectionName markerAnchor, Content heading, Content htmltree) {
430        htmltree.addContent(startMarker);
431        htmltree.addContent(getMarkerAnchor(markerAnchor));
432        htmltree.addContent(HtmlTree.HEADING(HtmlTag.H3, heading));
433    }
434
435    /**
436     * Get table header.
437     *
438     * @param text the table caption
439     * @param tableSummary the summary for the table
440     * @param tableStyle the table style
441     * @param tableHeader the table header
442     * @return a content object
443     */
444    public Content getTableHeader(String text, String tableSummary, HtmlStyle tableStyle,
445            List<String> tableHeader) {
446        return getTableHeader(getTableCaption(new RawHtml(text)), tableSummary, tableStyle, tableHeader);
447    }
448
449    /**
450     * Get table header.
451     *
452     * @param caption the table caption
453     * @param tableSummary the summary for the table
454     * @param tableStyle the table style
455     * @param tableHeader the table header
456     * @return a content object
457     */
458    public Content getTableHeader(Content caption, String tableSummary, HtmlStyle tableStyle,
459            List<String> tableHeader) {
460        Content table = (configuration.isOutputHtml5())
461                ? HtmlTree.TABLE(tableStyle, caption)
462                : HtmlTree.TABLE(tableStyle, tableSummary, caption);
463        table.addContent(getSummaryTableHeader(tableHeader, "col"));
464        return table;
465    }
466
467    /**
468     * {@inheritDoc}
469     */
470    public void addModulesSummary(Content summaryContentTree) {
471        if (display(requires) || display(additionalModules)) {
472            HtmlTree li = new HtmlTree(HtmlTag.LI);
473            li.addStyle(HtmlStyle.blockList);
474            addSummaryHeader(HtmlConstants.START_OF_MODULES_SUMMARY, SectionName.MODULES,
475                    contents.navModules, li);
476            if (display(requires)) {
477            String text = configuration.getText("doclet.Requires_Summary");
478            String tableSummary = configuration.getText("doclet.Member_Table_Summary",
479                    configuration.getText("doclet.Requires_Summary"),
480                    configuration.getText("doclet.modules"));
481                Content table = getTableHeader(text, tableSummary, HtmlStyle.requiresSummary, requiresTableHeader);
482                Content tbody = new HtmlTree(HtmlTag.TBODY);
483                addModulesList(requires, tbody);
484                table.addContent(tbody);
485                li.addContent(table);
486            }
487            // Display additional modules table in both "api" and "all" mode.
488            if (display(additionalModules)) {
489                String amrText = configuration.getText("doclet.Additional_Modules_Required_Summary");
490                String amrTableSummary = configuration.getText("doclet.Member_Table_Summary",
491                        configuration.getText("doclet.Additional_Modules_Required_Summary"),
492                        configuration.getText("doclet.modules"));
493                Content amrTable = getTableHeader(amrText, amrTableSummary, HtmlStyle.requiresSummary, requiresTableHeader);
494                Content amrTbody = new HtmlTree(HtmlTag.TBODY);
495                addModulesList(additionalModules, amrTbody);
496                amrTable.addContent(amrTbody);
497                li.addContent(amrTable);
498            }
499            HtmlTree ul = HtmlTree.UL(HtmlStyle.blockList, li);
500            summaryContentTree.addContent(ul);
501        }
502    }
503
504    /**
505     * Add the list of modules.
506     *
507     * @param mdleMap map of modules and modifiers
508     * @param tbody the content tree to which the list will be added
509     */
510    public void addModulesList(Map<ModuleElement, Content> mdleMap, Content tbody) {
511        boolean altColor = true;
512        for (ModuleElement m : mdleMap.keySet()) {
513            Content tdModifiers = HtmlTree.TD(HtmlStyle.colFirst, mdleMap.get(m));
514            Content moduleLinkContent = getModuleLink(m, new StringContent(m.getQualifiedName()));
515            Content thModule = HtmlTree.TH_ROW_SCOPE(HtmlStyle.colSecond, moduleLinkContent);
516            HtmlTree tdSummary = new HtmlTree(HtmlTag.TD);
517            tdSummary.addStyle(HtmlStyle.colLast);
518            addSummaryComment(m, tdSummary);
519            HtmlTree tr = HtmlTree.TR(tdModifiers);
520            tr.addContent(thModule);
521            tr.addContent(tdSummary);
522            tr.addStyle(altColor ? HtmlStyle.altColor : HtmlStyle.rowColor);
523            tbody.addContent(tr);
524            altColor = !altColor;
525        }
526    }
527
528    public void addPackagesSummary(Content summaryContentTree) {
529        if (display(exportedPackages) || display(openedPackages) || display(concealedPackages)
530                || display(additionalPackages) || display(additionalOpenPackages)) {
531            HtmlTree li = new HtmlTree(HtmlTag.LI);
532            li.addStyle(HtmlStyle.blockList);
533            addSummaryHeader(HtmlConstants.START_OF_PACKAGES_SUMMARY, SectionName.PACKAGES,
534                    contents.navPackages, li);
535            String tableSummary = configuration.getText("doclet.Member_Table_Summary",
536                    configuration.getText("doclet.Packages_Summary"),
537                    configuration.getText("doclet.packages"));
538            if (display(exportedPackages) || display(openedPackages) || display(concealedPackages)) {
539                addPackageSummary(tableSummary, li);
540            }
541            if (display(additionalPackages)) {
542                String aepText = configuration.getText("doclet.Additional_Exported_Packages_Summary");
543                String aepTableSummary = configuration.getText("doclet.Additional_Packages_Table_Summary",
544                        configuration.getText("doclet.Additional_Exported_Packages_Summary"),
545                        configuration.getText("doclet.modules"),
546                        configuration.getText("doclet.packages"));
547                Content aepTable = getTableHeader(aepText, aepTableSummary, HtmlStyle.packagesSummary,
548                        additionalPackagesTableHeader);
549                Content aepTbody = new HtmlTree(HtmlTag.TBODY);
550                addAdditionalPackages(aepTbody, additionalPackages);
551                aepTable.addContent(aepTbody);
552                li.addContent(aepTable);
553            }
554            if (display(additionalOpenPackages)) {
555                String aopText = configuration.getText("doclet.Additional_Opened_Packages_Summary");
556                String aopTableSummary = configuration.getText("doclet.Additional_Packages_Table_Summary",
557                        configuration.getText("doclet.Additional_Opened_Packages_Summary"),
558                        configuration.getText("doclet.modules"),
559                        configuration.getText("doclet.packages"));
560                Content aopTable = getTableHeader(aopText, aopTableSummary, HtmlStyle.packagesSummary,
561                        additionalPackagesTableHeader);
562                Content aopTbody = new HtmlTree(HtmlTag.TBODY);
563                addAdditionalPackages(aopTbody, additionalOpenPackages);
564                aopTable.addContent(aopTbody);
565                li.addContent(aopTable);
566            }
567            HtmlTree ul = HtmlTree.UL(HtmlStyle.blockList, li);
568            summaryContentTree.addContent(ul);
569        }
570    }
571
572    /**
573     * Add the package summary for the module.
574     *
575     * @param tableSummary
576     * @param li
577     */
578    public void addPackageSummary(String tableSummary, HtmlTree li) {
579        Content caption;
580        Content tbody = getPackageTableRows();
581        if (showTabs()) {
582            caption = getTableCaption();
583            generateTableTabTypesScript(typeMap, modulePackageTypes, "packages");
584        } else {
585            ModulePackageTypes type = modulePackageTypes.iterator().next();
586            caption = getTableCaption(configuration.getContent(type.tableTabs().resourceKey()));
587        }
588        Content table = getTableHeader(caption, tableSummary, HtmlStyle.packagesSummary, exportedPackagesTableHeader);
589        table.addContent(tbody);
590        li.addContent(table);
591    }
592
593    /**
594     * Returns true if the table tabs needs to be displayed.
595     *
596     * @return true if the tabs should be displayed
597     */
598    public boolean showTabs() {
599        int value;
600        for (ModulePackageTypes type : EnumSet.allOf(ModulePackageTypes.class)) {
601            value = type.tableTabs().value();
602            if ((value & packageTypesOr) == value) {
603                modulePackageTypes.add(type);
604            }
605        }
606        boolean showTabs = modulePackageTypes.size() > 1;
607        if (showTabs) {
608            modulePackageTypes.add(ModulePackageTypes.ALL);
609        }
610        return showTabs;
611    }
612
613    /**
614     * Get the summary table caption.
615     *
616     * @return the caption for the summary table
617     */
618    public Content getTableCaption() {
619        Content tabbedCaption = new HtmlTree(HtmlTag.CAPTION);
620        for (ModulePackageTypes type : modulePackageTypes) {
621            Content captionSpan;
622            Content span;
623            if (type.tableTabs().isDefaultTab()) {
624                captionSpan = HtmlTree.SPAN(configuration.getContent(type.tableTabs().resourceKey()));
625                span = HtmlTree.SPAN(type.tableTabs().tabId(),
626                        HtmlStyle.activeTableTab, captionSpan);
627            } else {
628                captionSpan = HtmlTree.SPAN(getPackageTypeLinks(type));
629                span = HtmlTree.SPAN(type.tableTabs().tabId(),
630                        HtmlStyle.tableTab, captionSpan);
631            }
632            Content tabSpan = HtmlTree.SPAN(HtmlStyle.tabEnd, Contents.SPACE);
633            span.addContent(tabSpan);
634            tabbedCaption.addContent(span);
635        }
636        return tabbedCaption;
637    }
638
639    /**
640     * Get the package type links for the table caption.
641     *
642     * @param packageType the package type to be displayed as link
643     * @return the content tree for the package type link
644     */
645    public Content getPackageTypeLinks(ModulePackageTypes packageType) {
646        String jsShow = "javascript:showPkgs(" + packageType.tableTabs().value() + ");";
647        HtmlTree link = HtmlTree.A(jsShow, configuration.getContent(packageType.tableTabs().resourceKey()));
648        return link;
649    }
650
651    /**
652     * Get the package table rows.
653     *
654     * @return a content object
655     */
656    public Content getPackageTableRows() {
657        Content tbody = new HtmlTree(HtmlTag.TBODY);
658        boolean altColor = true;
659        int counter = 0;
660        counter = addPackageTableRows(tbody, counter, ModulePackageTypes.EXPORTED, exportedPackages);
661        counter = addPackageTableRows(tbody, counter, ModulePackageTypes.OPENED, openedPackages);
662        // Show concealed packages only in "all" mode.
663        if (moduleMode == ModuleMode.ALL) {
664            for (PackageElement pkg : concealedPackages) {
665                Content pkgLinkContent = getPackageLink(pkg, new StringContent(utils.getPackageName(pkg)));
666                Content thPackage = HtmlTree.TH_ROW_SCOPE(HtmlStyle.colFirst, pkgLinkContent);
667                HtmlTree tdModules = new HtmlTree(HtmlTag.TD);
668                tdModules.addStyle(HtmlStyle.colSecond);
669                tdModules.addContent(configuration.getText("doclet.None"));
670        HtmlTree tdSummary = new HtmlTree(HtmlTag.TD);
671        tdSummary.addStyle(HtmlStyle.colLast);
672                addSummaryComment(pkg, tdSummary);
673        HtmlTree tr = HtmlTree.TR(thPackage);
674                tr.addContent(tdModules);
675        tr.addContent(tdSummary);
676        tr.addStyle(altColor ? HtmlStyle.altColor : HtmlStyle.rowColor);
677                int pkgType = ModulePackageTypes.CONCEALED.tableTabs().value();
678                packageTypesOr = packageTypesOr | pkgType;
679                String tableId = "i" + counter;
680                counter++;
681                typeMap.put(tableId, pkgType);
682                tr.addAttr(HtmlAttr.ID, tableId);
683        tbody.addContent(tr);
684                altColor = !altColor;
685            }
686        }
687        return tbody;
688    }
689
690    public int addPackageTableRows(Content tbody, int counter, ModulePackageTypes pType,
691            Map<PackageElement,SortedSet<ModuleElement>> ap) {
692        boolean altColor = true;
693        for (Map.Entry<PackageElement, SortedSet<ModuleElement>> entry : ap.entrySet()) {
694            PackageElement pkg = entry.getKey();
695            SortedSet<ModuleElement> mdleList = entry.getValue();
696            Content pkgLinkContent = getPackageLink(pkg, new StringContent(utils.getPackageName(pkg)));
697            Content thPackage = HtmlTree.TH_ROW_SCOPE(HtmlStyle.colFirst, pkgLinkContent);
698            HtmlTree tr = HtmlTree.TR(thPackage);
699            if (moduleMode == ModuleMode.ALL) {
700                HtmlTree tdModules = new HtmlTree(HtmlTag.TD);
701                tdModules.addStyle(HtmlStyle.colSecond);
702                if (!mdleList.isEmpty()) {
703                    int sep = 0;
704                    for (ModuleElement m : mdleList) {
705                        if (sep > 0) {
706                            tdModules.addContent(new HtmlTree(HtmlTag.BR));
707                        }
708                        tdModules.addContent(getModuleLink(m, new StringContent(m.getQualifiedName())));
709                        sep++;
710                    }
711                } else {
712                    tdModules.addContent(configuration.getText("doclet.All_Modules"));
713                }
714                tr.addContent(tdModules);
715            }
716            HtmlTree tdSummary = new HtmlTree(HtmlTag.TD);
717            tdSummary.addStyle(HtmlStyle.colLast);
718            addSummaryComment(pkg, tdSummary);
719            tr.addContent(tdSummary);
720            tr.addStyle(altColor ? HtmlStyle.altColor : HtmlStyle.rowColor);
721            int pkgType = pType.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        return counter;
731    }
732
733    /**
734     * Add the additional packages for the module being documented.
735     *
736     * @param tbody the content tree to which the table will be added
737     * @param ap additional packages to be added
738     */
739    public void addAdditionalPackages(Content tbody, Map<ModuleElement, SortedSet<PackageElement>> ap) {
740        boolean altColor = true;
741        for (Map.Entry<ModuleElement, SortedSet<PackageElement>> entry : ap.entrySet()) {
742            ModuleElement m = entry.getKey();
743            SortedSet<PackageElement> pkgList = entry.getValue();
744            Content moduleLinkContent = getModuleLink(m, new StringContent(m.getQualifiedName()));
745            Content thModule = HtmlTree.TH_ROW_SCOPE(HtmlStyle.colFirst, moduleLinkContent);
746            HtmlTree tdPackages = new HtmlTree(HtmlTag.TD);
747            tdPackages.addStyle(HtmlStyle.colLast);
748            String sep = "";
749            for (PackageElement pkg : pkgList) {
750                tdPackages.addContent(sep);
751                tdPackages.addContent(getPackageLink(pkg, new StringContent(utils.getPackageName(pkg))));
752                sep = " ";
753            }
754            HtmlTree tr = HtmlTree.TR(thModule);
755            tr.addContent(tdPackages);
756            tr.addStyle(altColor ? HtmlStyle.altColor : HtmlStyle.rowColor);
757            tbody.addContent(tr);
758            altColor = !altColor;
759        }
760    }
761
762    /**
763     * {@inheritDoc}
764     */
765    public void addServicesSummary(Content summaryContentTree) {
766        if (display(uses) || display(provides)) {
767            HtmlTree li = new HtmlTree(HtmlTag.LI);
768            li.addStyle(HtmlStyle.blockList);
769            addSummaryHeader(HtmlConstants.START_OF_SERVICES_SUMMARY, SectionName.SERVICES,
770                    contents.navServices, li);
771            String text;
772            String tableSummary;
773            if (display(uses)) {
774                text = configuration.getText("doclet.Uses_Summary");
775                tableSummary = configuration.getText("doclet.Member_Table_Summary",
776                        configuration.getText("doclet.Uses_Summary"),
777                        configuration.getText("doclet.types"));
778                Content table = getTableHeader(text, tableSummary, HtmlStyle.usesSummary, usesTableHeader);
779                Content tbody = new HtmlTree(HtmlTag.TBODY);
780                addUsesList(tbody);
781                if (!tbody.isEmpty()) {
782                    table.addContent(tbody);
783                    li.addContent(table);
784            }
785            }
786            if (display(provides)) {
787                text = configuration.getText("doclet.Provides_Summary");
788                tableSummary = configuration.getText("doclet.Member_Table_Summary",
789                        configuration.getText("doclet.Provides_Summary"),
790                        configuration.getText("doclet.types"));
791                Content table = getTableHeader(text, tableSummary, HtmlStyle.providesSummary, providesTableHeader);
792                Content tbody = new HtmlTree(HtmlTag.TBODY);
793                addProvidesList(tbody);
794                if (!tbody.isEmpty()) {
795                    table.addContent(tbody);
796                    li.addContent(table);
797                }
798            }
799            HtmlTree ul = HtmlTree.UL(HtmlStyle.blockList, li);
800            summaryContentTree.addContent(ul);
801        }
802    }
803
804    /**
805     * Add the uses list for the module.
806     *
807     * @param tbody the content tree to which the directive will be added
808     */
809    public void addUsesList(Content tbody) {
810        boolean altColor = true;
811        Content typeLinkContent;
812        Content thType;
813        HtmlTree tdSummary;
814        Content description;
815        for (TypeElement t : uses) {
816            // For each uses directive in the module declaration, if we are in the "api" mode and
817            // if there are service types listed using @uses javadoc tag, check if the service type in
818            // the uses directive is specified using the @uses tag. If not, we do not display the
819            // service type in the "api" mode.
820            if (moduleMode == ModuleMode.API && display(usesTrees) && !usesTrees.containsKey(t)) {
821                continue;
822            }
823            typeLinkContent = getLink(new LinkInfoImpl(configuration, LinkInfoImpl.Kind.PACKAGE, t));
824            thType = HtmlTree.TH_ROW_SCOPE(HtmlStyle.colFirst, typeLinkContent);
825            tdSummary = new HtmlTree(HtmlTag.TD);
826        tdSummary.addStyle(HtmlStyle.colLast);
827            if (display(usesTrees)) {
828                description = usesTrees.get(t);
829                if (description != null) {
830                    tdSummary.addContent(description);
831                }
832            }
833            addSummaryComment(t, tdSummary);
834            HtmlTree tr = HtmlTree.TR(thType);
835        tr.addContent(tdSummary);
836        tr.addStyle(altColor ? HtmlStyle.altColor : HtmlStyle.rowColor);
837        tbody.addContent(tr);
838            altColor = !altColor;
839        }
840    }
841
842    /**
843     * Add the provides list for the module.
844     *
845     * @param tbody the content tree to which the directive will be added
846     */
847    public void addProvidesList(Content tbody) {
848        boolean altColor = true;
849        TypeElement srv;
850        SortedSet<TypeElement> implSet;
851        Content description;
852        for (Map.Entry<TypeElement, SortedSet<TypeElement>> entry : provides.entrySet()) {
853            srv = entry.getKey();
854            // For each provides directive in the module declaration, if we are in the "api" mode and
855            // if there are service types listed using @provides javadoc tag, check if the service type in
856            // the provides directive is specified using the @provides tag. If not, we do not display the
857            // service type in the "api" mode.
858            if (moduleMode == ModuleMode.API && display(providesTrees) && !providesTrees.containsKey(srv)) {
859                continue;
860    }
861            implSet = entry.getValue();
862            Content srvLinkContent = getLink(new LinkInfoImpl(configuration, LinkInfoImpl.Kind.PACKAGE, srv));
863            HtmlTree thType = HtmlTree.TH_ROW_SCOPE(HtmlStyle.colFirst, srvLinkContent);
864            HtmlTree tdDesc = new HtmlTree(HtmlTag.TD);
865            tdDesc.addStyle(HtmlStyle.colLast);
866            if (display(providesTrees)) {
867                description = providesTrees.get(srv);
868                if (description != null) {
869                    tdDesc.addContent(description);
870                }
871            }
872            addSummaryComment(srv, tdDesc);
873            // Only display the implementation details in the "all" mode.
874            if (moduleMode == ModuleMode.ALL && !implSet.isEmpty()) {
875                tdDesc.addContent(new HtmlTree(HtmlTag.BR));
876                tdDesc.addContent("(");
877                HtmlTree implSpan = HtmlTree.SPAN(HtmlStyle.implementationLabel, contents.implementation);
878                tdDesc.addContent(implSpan);
879                tdDesc.addContent(Contents.SPACE);
880                String sep = "";
881                for (TypeElement impl : implSet) {
882                    tdDesc.addContent(sep);
883                    tdDesc.addContent(getLink(new LinkInfoImpl(configuration, LinkInfoImpl.Kind.PACKAGE, impl)));
884                    sep = ", ";
885                }
886                tdDesc.addContent(")");
887            }
888            HtmlTree tr = HtmlTree.TR(thType);
889            tr.addContent(tdDesc);
890            tr.addStyle(altColor ? HtmlStyle.altColor : HtmlStyle.rowColor);
891            tbody.addContent(tr);
892            altColor = !altColor;
893        }
894    }
895
896    /**
897     * Add the module deprecation information to the documentation tree.
898     *
899     * @param div the content tree to which the deprecation information will be added
900     */
901    public void addDeprecationInfo(Content div) {
902        List<? extends DocTree> deprs = utils.getBlockTags(mdle, DocTree.Kind.DEPRECATED);
903        if (utils.isDeprecated(mdle)) {
904            CommentHelper ch = utils.getCommentHelper(mdle);
905            HtmlTree deprDiv = new HtmlTree(HtmlTag.DIV);
906            deprDiv.addStyle(HtmlStyle.deprecatedContent);
907            Content deprPhrase = HtmlTree.SPAN(HtmlStyle.deprecatedLabel, getDeprecatedPhrase(mdle));
908            deprDiv.addContent(deprPhrase);
909            if (!deprs.isEmpty()) {
910                List<? extends DocTree> commentTags = ch.getDescription(configuration, deprs.get(0));
911                if (!commentTags.isEmpty()) {
912                    addInlineDeprecatedComment(mdle, deprs.get(0), deprDiv);
913                }
914            }
915            div.addContent(deprDiv);
916        }
917    }
918
919    /**
920     * {@inheritDoc}
921     */
922    @Override
923    public void addModuleDescription(Content moduleContentTree) {
924        if (!utils.getFullBody(mdle).isEmpty()) {
925            Content tree = configuration.allowTag(HtmlTag.SECTION) ? HtmlTree.SECTION() : moduleContentTree;
926            addDeprecationInfo(tree);
927            tree.addContent(HtmlConstants.START_OF_MODULE_DESCRIPTION);
928            tree.addContent(getMarkerAnchor(SectionName.MODULE_DESCRIPTION));
929            addInlineComment(mdle, tree);
930            if (configuration.allowTag(HtmlTag.SECTION)) {
931                moduleContentTree.addContent(tree);
932            }
933        }
934    }
935
936    /**
937     * {@inheritDoc}
938     */
939    @Override
940    public void addModuleTags(Content moduleContentTree) {
941        Content tree = (configuration.allowTag(HtmlTag.SECTION))
942                ? HtmlTree.SECTION()
943                : moduleContentTree;
944        addTagsInfo(mdle, tree);
945        if (configuration.allowTag(HtmlTag.SECTION)) {
946            moduleContentTree.addContent(tree);
947        }
948    }
949
950    /**
951     * Add summary details to the navigation bar.
952     *
953     * @param subDiv the content tree to which the summary detail links will be added
954     */
955    @Override
956    protected void addSummaryDetailLinks(Content subDiv) {
957        Content div = HtmlTree.DIV(getNavSummaryLinks());
958        subDiv.addContent(div);
959    }
960
961    /**
962     * Get summary links for navigation bar.
963     *
964     * @return the content tree for the navigation summary links
965     */
966    protected Content getNavSummaryLinks() {
967        Content li = HtmlTree.LI(contents.moduleSubNavLabel);
968        li.addContent(Contents.SPACE);
969        Content ulNav = HtmlTree.UL(HtmlStyle.subNavList, li);
970        Content liNav = new HtmlTree(HtmlTag.LI);
971        liNav.addContent(!utils.getFullBody(mdle).isEmpty() && !configuration.nocomment
972                ? getHyperLink(SectionName.MODULE_DESCRIPTION, contents.navModuleDescription)
973                : contents.navModuleDescription);
974        addNavGap(liNav);
975        liNav.addContent((display(requires) || display(additionalModules))
976                ? getHyperLink(SectionName.MODULES, contents.navModules)
977                : contents.navModules);
978        addNavGap(liNav);
979        liNav.addContent((display(exportedPackages) || display(openedPackages) || display(concealedPackages)
980                || display(additionalPackages) || display(additionalOpenPackages))
981                ? getHyperLink(SectionName.PACKAGES, contents.navPackages)
982                : contents.navPackages);
983        addNavGap(liNav);
984        liNav.addContent((display(uses) || (moduleMode == ModuleMode.API && display(usesTrees))
985                || display(provides) || (moduleMode == ModuleMode.API && display(providesTrees)))
986                ? getHyperLink(SectionName.SERVICES, contents.navServices)
987                : contents.navServices);
988        ulNav.addContent(liNav);
989        return ulNav;
990    }
991
992    /**
993     * {@inheritDoc}
994     */
995    @Override
996    public void addModuleContent(Content contentTree, Content moduleContentTree) {
997        if (configuration.allowTag(HtmlTag.MAIN)) {
998            mainTree.addContent(moduleContentTree);
999            contentTree.addContent(mainTree);
1000        } else {
1001            contentTree.addContent(moduleContentTree);
1002        }
1003    }
1004
1005    /**
1006     * {@inheritDoc}
1007     */
1008    @Override
1009    public void addModuleFooter(Content contentTree) {
1010        Content htmlTree = (configuration.allowTag(HtmlTag.FOOTER))
1011                ? HtmlTree.FOOTER()
1012                : contentTree;
1013        addNavLinks(false, htmlTree);
1014        addBottom(htmlTree);
1015        if (configuration.allowTag(HtmlTag.FOOTER)) {
1016            contentTree.addContent(htmlTree);
1017        }
1018    }
1019
1020    /**
1021     * {@inheritDoc}
1022     *
1023     * @throws jdk.javadoc.internal.doclets.toolkit.util.DocFileIOException
1024     */
1025    @Override
1026    public void printDocument(Content contentTree) throws DocFileIOException {
1027        printHtmlDocument(configuration.metakeywords.getMetaKeywordsForModule(mdle),
1028                true, contentTree);
1029    }
1030
1031    /**
1032     * Add the module package deprecation information to the documentation tree.
1033     *
1034     * @param li the content tree to which the deprecation information will be added
1035     * @param pkg the PackageDoc that is added
1036     */
1037    public void addPackageDeprecationInfo(Content li, PackageElement pkg) {
1038        List<? extends DocTree> deprs;
1039        if (utils.isDeprecated(pkg)) {
1040            deprs = utils.getDeprecatedTrees(pkg);
1041            HtmlTree deprDiv = new HtmlTree(HtmlTag.DIV);
1042            deprDiv.addStyle(HtmlStyle.deprecatedContent);
1043            Content deprPhrase = HtmlTree.SPAN(HtmlStyle.deprecatedLabel, getDeprecatedPhrase(pkg));
1044            deprDiv.addContent(deprPhrase);
1045            if (!deprs.isEmpty()) {
1046                CommentHelper ch = utils.getCommentHelper(pkg);
1047                List<? extends DocTree> commentTags = ch.getDescription(configuration, deprs.get(0));
1048                if (!commentTags.isEmpty()) {
1049                    addInlineDeprecatedComment(pkg, deprs.get(0), deprDiv);
1050                }
1051            }
1052            li.addContent(deprDiv);
1053        }
1054    }
1055
1056    /**
1057     * Get this module link.
1058     *
1059     * @return a content tree for the module link
1060     */
1061    @Override
1062    protected Content getNavLinkModule() {
1063        Content li = HtmlTree.LI(HtmlStyle.navBarCell1Rev, contents.moduleLabel);
1064        return li;
1065    }
1066
1067    /**
1068     * Get "PREV MODULE" link in the navigation bar.
1069     *
1070     * @return a content tree for the previous link
1071     */
1072    @Override
1073    public Content getNavLinkPrevious() {
1074        Content li;
1075        if (prevModule == null) {
1076            li = HtmlTree.LI(contents.prevModuleLabel);
1077        } else {
1078            li = HtmlTree.LI(getHyperLink(pathToRoot.resolve(DocPaths.moduleSummary(
1079                    prevModule)), contents.prevModuleLabel, "", ""));
1080        }
1081        return li;
1082    }
1083
1084    /**
1085     * Get "NEXT MODULE" link in the navigation bar.
1086     *
1087     * @return a content tree for the next link
1088     */
1089    @Override
1090    public Content getNavLinkNext() {
1091        Content li;
1092        if (nextModule == null) {
1093            li = HtmlTree.LI(contents.nextModuleLabel);
1094        } else {
1095            li = HtmlTree.LI(getHyperLink(pathToRoot.resolve(DocPaths.moduleSummary(
1096                    nextModule)), contents.nextModuleLabel, "", ""));
1097        }
1098        return li;
1099    }
1100}
1101