1 /*
2  * Copyright (c) 1998, 2020, 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.Set;
29 import java.util.SortedMap;
30 import java.util.TreeMap;
31 import java.util.TreeSet;
32 
33 import javax.lang.model.element.PackageElement;
34 import javax.lang.model.element.TypeElement;
35 
36 import jdk.javadoc.internal.doclets.formats.html.markup.ContentBuilder;
37 import jdk.javadoc.internal.doclets.formats.html.markup.Entity;
38 import jdk.javadoc.internal.doclets.formats.html.markup.HtmlStyle;
39 import jdk.javadoc.internal.doclets.formats.html.markup.TagName;
40 import jdk.javadoc.internal.doclets.formats.html.markup.HtmlTree;
41 import jdk.javadoc.internal.doclets.formats.html.Navigation.PageMode;
42 import jdk.javadoc.internal.doclets.formats.html.markup.StringContent;
43 import jdk.javadoc.internal.doclets.formats.html.markup.Table;
44 import jdk.javadoc.internal.doclets.formats.html.markup.TableHeader;
45 import jdk.javadoc.internal.doclets.toolkit.Content;
46 import jdk.javadoc.internal.doclets.toolkit.util.ClassUseMapper;
47 import jdk.javadoc.internal.doclets.toolkit.util.DocFileIOException;
48 import jdk.javadoc.internal.doclets.toolkit.util.DocPath;
49 import jdk.javadoc.internal.doclets.toolkit.util.DocPaths;
50 
51 /**
52  * Generate package usage information.
53  *
54  *  <p><b>This is NOT part of any supported API.
55  *  If you write code that depends on this, you do so at your own risk.
56  *  This code and its internal interfaces are subject to change or
57  *  deletion without notice.</b>
58  */
59 public class PackageUseWriter extends SubWriterHolderWriter {
60 
61     final PackageElement packageElement;
62     final SortedMap<String, Set<TypeElement>> usingPackageToUsedClasses = new TreeMap<>();
63     final String packageUseTableSummary;
64     private final Navigation navBar;
65 
66     /**
67      * Constructor.
68      *
69      * @param configuration the configuration
70      * @param mapper a mapper to provide details of where elements are used
71      * @param filename the file to be generated
72      * @param pkgElement the package element to be documented
73      */
PackageUseWriter(HtmlConfiguration configuration, ClassUseMapper mapper, DocPath filename, PackageElement pkgElement)74     public PackageUseWriter(HtmlConfiguration configuration,
75                             ClassUseMapper mapper, DocPath filename,
76                             PackageElement pkgElement) {
77         super(configuration, configuration.docPaths.forPackage(pkgElement).resolve(filename));
78         this.packageElement = pkgElement;
79 
80         // by examining all classes in this package, find what packages
81         // use these classes - produce a map between using package and
82         // used classes.
83         for (TypeElement usedClass : utils.getEnclosedTypeElements(pkgElement)) {
84             Set<TypeElement> usingClasses = mapper.classToClass.get(usedClass);
85             if (usingClasses != null) {
86                 for (TypeElement usingClass : usingClasses) {
87                     PackageElement usingPackage = utils.containingPackage(usingClass);
88                     Set<TypeElement> usedClasses = usingPackageToUsedClasses
89                             .get(utils.getPackageName(usingPackage));
90                     if (usedClasses == null) {
91                         usedClasses = new TreeSet<>(comparators.makeGeneralPurposeComparator());
92                         usingPackageToUsedClasses.put(utils.getPackageName(usingPackage),
93                                                       usedClasses);
94                     }
95                     usedClasses.add(usedClass);
96                 }
97             }
98         }
99 
100         packageUseTableSummary = resources.getText("doclet.Use_Table_Summary",
101                 resources.getText("doclet.packages"));
102         this.navBar = new Navigation(packageElement, configuration, PageMode.USE, path);
103     }
104 
105     /**
106      * Generate a class page.
107      *
108      * @param configuration the current configuration of the doclet.
109      * @param mapper        the mapping of the class usage.
110      * @param pkgElement    the package being documented.
111      * @throws DocFileIOException if there is a problem generating the package use page
112      */
generate(HtmlConfiguration configuration, ClassUseMapper mapper, PackageElement pkgElement)113     public static void generate(HtmlConfiguration configuration,
114                                 ClassUseMapper mapper, PackageElement pkgElement)
115             throws DocFileIOException {
116         DocPath filename = DocPaths.PACKAGE_USE;
117         PackageUseWriter pkgusegen = new PackageUseWriter(configuration, mapper, filename, pkgElement);
118         pkgusegen.generatePackageUseFile();
119     }
120 
121     /**
122      * Generate the package use list.
123      * @throws DocFileIOException if there is a problem generating the package use page
124      */
generatePackageUseFile()125     protected void generatePackageUseFile() throws DocFileIOException {
126         HtmlTree body = getPackageUseHeader();
127         Content mainContent = new ContentBuilder();
128         if (usingPackageToUsedClasses.isEmpty()) {
129             mainContent.add(contents.getContent("doclet.ClassUse_No.usage.of.0", utils.getPackageName(packageElement)));
130         } else {
131             addPackageUse(mainContent);
132         }
133         bodyContents.addMainContent(mainContent);
134         HtmlTree footer = HtmlTree.FOOTER();
135         navBar.setUserFooter(getUserHeaderFooter(false));
136         footer.add(navBar.getContent(Navigation.Position.BOTTOM));
137         addBottom(footer);
138         bodyContents.setFooter(footer);
139         body.add(bodyContents);
140         printHtmlDocument(null,
141                 getDescription("use", packageElement),
142                 body);
143     }
144 
145     /**
146      * Add the package use information.
147      *
148      * @param contentTree the content tree to which the package use information will be added
149      */
addPackageUse(Content contentTree)150     protected void addPackageUse(Content contentTree) {
151         Content content = new ContentBuilder();
152         if (configuration.packages.size() > 1) {
153             addPackageList(content);
154         }
155         addClassList(content);
156         contentTree.add(content);
157     }
158 
159     /**
160      * Add the list of packages that use the given package.
161      *
162      * @param contentTree the content tree to which the package list will be added
163      */
addPackageList(Content contentTree)164     protected void addPackageList(Content contentTree) {
165         Content caption = contents.getContent(
166                 "doclet.ClassUse_Packages.that.use.0",
167                 getPackageLink(packageElement, utils.getPackageName(packageElement)));
168         Table table = new Table(HtmlStyle.useSummary, HtmlStyle.summaryTable)
169                 .setCaption(caption)
170                 .setHeader(getPackageTableHeader())
171                 .setColumnStyles(HtmlStyle.colFirst, HtmlStyle.colLast);
172         for (String pkgname: usingPackageToUsedClasses.keySet()) {
173             PackageElement pkg = utils.elementUtils.getPackageElement(pkgname);
174             Content packageLink = links.createLink(getPackageAnchorName(pkg),
175                     new StringContent(utils.getPackageName(pkg)));
176             Content summary = new ContentBuilder();
177             if (pkg != null && !pkg.isUnnamed()) {
178                 addSummaryComment(pkg, summary);
179             } else {
180                 summary.add(Entity.NO_BREAK_SPACE);
181             }
182             table.addRow(packageLink, summary);
183         }
184         contentTree.add(table);
185     }
186 
187     /**
188      * Add the list of classes that use the given package.
189      *
190      * @param contentTree the content tree to which the class list will be added
191      */
addClassList(Content contentTree)192     protected void addClassList(Content contentTree) {
193         TableHeader classTableHeader = new TableHeader(
194                 contents.classLabel, contents.descriptionLabel);
195         HtmlTree ul = new HtmlTree(TagName.UL);
196         ul.setStyle(HtmlStyle.blockList);
197         for (String packageName : usingPackageToUsedClasses.keySet()) {
198             PackageElement usingPackage = utils.elementUtils.getPackageElement(packageName);
199             HtmlTree section = HtmlTree.SECTION(HtmlStyle.detail)
200                     .setId(getPackageAnchorName(usingPackage));
201             String tableSummary = resources.getText("doclet.Use_Table_Summary",
202                                                         resources.getText("doclet.classes"));
203             Content caption = contents.getContent(
204                     "doclet.ClassUse_Classes.in.0.used.by.1",
205                     getPackageLink(packageElement, utils.getPackageName(packageElement)),
206                     getPackageLink(usingPackage, utils.getPackageName(usingPackage)));
207             Table table = new Table(HtmlStyle.useSummary, HtmlStyle.summaryTable)
208                     .setCaption(caption)
209                     .setHeader(classTableHeader)
210                     .setColumnStyles(HtmlStyle.colFirst, HtmlStyle.colLast);
211             for (TypeElement te : usingPackageToUsedClasses.get(packageName)) {
212                 DocPath dp = pathString(te,
213                         DocPaths.CLASS_USE.resolve(docPaths.forName(te)));
214                 Content stringContent = new StringContent(utils.getSimpleName(te));
215                 Content typeContent = links.createLink(dp.fragment(getPackageAnchorName(usingPackage)),
216                         stringContent);
217                 Content summary = new ContentBuilder();
218                 addIndexComment(te, summary);
219 
220                 table.addRow(typeContent, summary);
221             }
222             section.add(table);
223             ul.add(HtmlTree.LI(section));
224         }
225         Content li = HtmlTree.SECTION(HtmlStyle.packageUses, ul);
226         contentTree.add(li);
227     }
228 
229     /**
230      * Get the header for the package use listing.
231      *
232      * @return a content tree representing the package use header
233      */
getPackageUseHeader()234     private HtmlTree getPackageUseHeader() {
235         String packageText = resources.getText("doclet.Package");
236         String name = packageElement.isUnnamed() ? "" : utils.getPackageName(packageElement);
237         String title = resources.getText("doclet.Window_ClassUse_Header", packageText, name);
238         HtmlTree bodyTree = getBody(getWindowTitle(title));
239         Content headerContent = new ContentBuilder();
240         addTop(headerContent);
241         Content linkContent = getModuleLink(utils.elementUtils.getModuleOf(packageElement),
242                 contents.moduleLabel);
243         navBar.setNavLinkModule(linkContent);
244         navBar.setUserHeader(getUserHeaderFooter(true));
245         headerContent.add(navBar.getContent(Navigation.Position.TOP));
246         ContentBuilder headingContent = new ContentBuilder();
247         headingContent.add(contents.getContent("doclet.ClassUse_Title", packageText));
248         headingContent.add(new HtmlTree(TagName.BR));
249         headingContent.add(name);
250         Content heading = HtmlTree.HEADING_TITLE(Headings.PAGE_TITLE_HEADING,
251                 HtmlStyle.title, headingContent);
252         Content div = HtmlTree.DIV(HtmlStyle.header, heading);
253         bodyContents.setHeader(headerContent)
254                 .addMainContent(div);
255         return bodyTree;
256     }
257 }
258