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