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