001/* 002 * Copyright (c) 1998, 2022, Oracle and/or its affiliates. All rights reserved. 003 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 004 * 005 * This code is free software; you can redistribute it and/or modify it 006 * under the terms of the GNU General Public License version 2 only, as 007 * published by the Free Software Foundation. Oracle designates this 008 * particular file as subject to the "Classpath" exception as provided 009 * by Oracle in the LICENSE file that accompanied this code. 010 * 011 * This code is distributed in the hope that it will be useful, but WITHOUT 012 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 013 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 014 * version 2 for more details (a copy is included in the LICENSE file that 015 * accompanied this code). 016 * 017 * You should have received a copy of the GNU General Public License version 018 * 2 along with this work; if not, write to the Free Software Foundation, 019 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 020 * 021 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 022 * or visit www.oracle.com if you need additional information or have any 023 * questions. 024 */ 025 026package org.jdrupes.mdoclet.internal.doclets.formats.html; 027 028import java.util.Set; 029import java.util.SortedMap; 030import java.util.TreeMap; 031import java.util.TreeSet; 032 033import javax.lang.model.element.Element; 034import javax.lang.model.element.PackageElement; 035import javax.lang.model.element.TypeElement; 036 037import org.jdrupes.mdoclet.internal.doclets.formats.html.Navigation.PageMode; 038import org.jdrupes.mdoclet.internal.doclets.formats.html.markup.ContentBuilder; 039import org.jdrupes.mdoclet.internal.doclets.formats.html.markup.Entity; 040import org.jdrupes.mdoclet.internal.doclets.formats.html.markup.HtmlStyle; 041import org.jdrupes.mdoclet.internal.doclets.formats.html.markup.HtmlTree; 042import org.jdrupes.mdoclet.internal.doclets.formats.html.markup.TagName; 043import org.jdrupes.mdoclet.internal.doclets.formats.html.markup.Text; 044import org.jdrupes.mdoclet.internal.doclets.toolkit.Content; 045import org.jdrupes.mdoclet.internal.doclets.toolkit.util.ClassUseMapper; 046import org.jdrupes.mdoclet.internal.doclets.toolkit.util.DocFileIOException; 047import org.jdrupes.mdoclet.internal.doclets.toolkit.util.DocPath; 048import org.jdrupes.mdoclet.internal.doclets.toolkit.util.DocPaths; 049 050/** 051 * Generate package usage information. 052 */ 053public class PackageUseWriter extends SubWriterHolderWriter { 054 055 final PackageElement packageElement; 056 final SortedMap<String, Set<TypeElement>> usingPackageToUsedClasses 057 = new TreeMap<>(); 058 059 /** 060 * Constructor. 061 * 062 * @param configuration the configuration 063 * @param mapper a mapper to provide details of where elements are used 064 * @param filename the file to be generated 065 * @param pkgElement the package element to be documented 066 */ 067 public PackageUseWriter(HtmlConfiguration configuration, 068 ClassUseMapper mapper, DocPath filename, 069 PackageElement pkgElement) { 070 super(configuration, 071 configuration.docPaths.forPackage(pkgElement).resolve(filename)); 072 this.packageElement = pkgElement; 073 074 // by examining all classes in this package, find what packages 075 // use these classes - produce a map between using package and 076 // used classes. 077 for (TypeElement usedClass : utils 078 .getEnclosedTypeElements(pkgElement)) { 079 Set<TypeElement> usingClasses = mapper.classToClass.get(usedClass); 080 if (usingClasses != null) { 081 for (TypeElement usingClass : usingClasses) { 082 PackageElement usingPackage 083 = utils.containingPackage(usingClass); 084 Set<TypeElement> usedClasses = usingPackageToUsedClasses 085 .get(utils.getPackageName(usingPackage)); 086 if (usedClasses == null) { 087 usedClasses = new TreeSet<>( 088 comparators.makeGeneralPurposeComparator()); 089 usingPackageToUsedClasses.put( 090 utils.getPackageName(usingPackage), 091 usedClasses); 092 } 093 usedClasses.add(usedClass); 094 } 095 } 096 } 097 } 098 099 /** 100 * Generate a class page. 101 * 102 * @param configuration the current configuration of the doclet. 103 * @param mapper the mapping of the class usage. 104 * @param pkgElement the package being documented. 105 * @throws DocFileIOException if there is a problem generating the package use page 106 */ 107 public static void generate(HtmlConfiguration configuration, 108 ClassUseMapper mapper, PackageElement pkgElement) 109 throws DocFileIOException { 110 DocPath filename = DocPaths.PACKAGE_USE; 111 PackageUseWriter pkgusegen 112 = new PackageUseWriter(configuration, mapper, filename, pkgElement); 113 pkgusegen.generatePackageUseFile(); 114 } 115 116 /** 117 * Generate the package use list. 118 * @throws DocFileIOException if there is a problem generating the package use page 119 */ 120 protected void generatePackageUseFile() throws DocFileIOException { 121 HtmlTree body = getBody(); 122 Content mainContent = new ContentBuilder(); 123 if (usingPackageToUsedClasses.isEmpty()) { 124 mainContent.add(contents.getContent("doclet.ClassUse_No.usage.of.0", 125 getLocalizedPackageName(packageElement))); 126 } else { 127 addPackageUse(mainContent); 128 } 129 bodyContents.addMainContent(mainContent); 130 bodyContents.setFooter(getFooter()); 131 body.add(bodyContents); 132 printHtmlDocument(null, 133 getDescription("use", packageElement), 134 body); 135 } 136 137 /** 138 * Add the package use information. 139 * 140 * @param content the content to which the package use information will be added 141 */ 142 protected void addPackageUse(Content content) { 143 Content c = new ContentBuilder(); 144 if (configuration.packages.size() > 1) { 145 addPackageList(c); 146 } 147 addClassList(c); 148 content.add(c); 149 } 150 151 /** 152 * Add the list of packages that use the given package. 153 * 154 * @param content the content to which the package list will be added 155 */ 156 protected void addPackageList(Content content) { 157 Content caption = contents.getContent( 158 "doclet.ClassUse_Packages.that.use.0", 159 getPackageLink(packageElement, 160 getLocalizedPackageName(packageElement))); 161 var table = new Table<Void>(HtmlStyle.summaryTable) 162 .setCaption(caption) 163 .setHeader(getPackageTableHeader()) 164 .setColumnStyles(HtmlStyle.colFirst, HtmlStyle.colLast); 165 for (String pkgname : usingPackageToUsedClasses.keySet()) { 166 PackageElement pkg = utils.elementUtils.getPackageElement(pkgname); 167 Content packageLink = links.createLink(htmlIds.forPackage(pkg), 168 getLocalizedPackageName(pkg)); 169 Content summary = new ContentBuilder(); 170 if (pkg != null && !pkg.isUnnamed()) { 171 addSummaryComment(pkg, summary); 172 } else { 173 summary.add(Entity.NO_BREAK_SPACE); 174 } 175 table.addRow(packageLink, summary); 176 } 177 content.add(table); 178 } 179 180 /** 181 * Add the list of classes that use the given package. 182 * 183 * @param content the content to which the class list will be added 184 */ 185 protected void addClassList(Content content) { 186 TableHeader classTableHeader = new TableHeader( 187 contents.classLabel, contents.descriptionLabel); 188 var ul = HtmlTree.UL(HtmlStyle.blockList); 189 for (String packageName : usingPackageToUsedClasses.keySet()) { 190 PackageElement usingPackage 191 = utils.elementUtils.getPackageElement(packageName); 192 var section = HtmlTree.SECTION(HtmlStyle.detail) 193 .setId(htmlIds.forPackage(usingPackage)); 194 Content caption = contents.getContent( 195 "doclet.ClassUse_Classes.in.0.used.by.1", 196 getPackageLink(packageElement, 197 getLocalizedPackageName(packageElement)), 198 getPackageLink(usingPackage, 199 getLocalizedPackageName(usingPackage))); 200 var table = new Table<Void>(HtmlStyle.summaryTable) 201 .setCaption(caption) 202 .setHeader(classTableHeader) 203 .setColumnStyles(HtmlStyle.colFirst, HtmlStyle.colLast); 204 for (TypeElement te : usingPackageToUsedClasses.get(packageName)) { 205 DocPath dp = pathString(te, 206 DocPaths.CLASS_USE.resolve(docPaths.forName(te))); 207 Content stringContent = Text.of(utils.getSimpleName(te)); 208 Content typeContent = links.createLink( 209 dp.fragment(htmlIds.forPackage(usingPackage).name()), 210 stringContent); 211 Content summary = new ContentBuilder(); 212 addIndexComment(te, summary); 213 214 table.addRow(typeContent, summary); 215 } 216 section.add(table); 217 ul.add(HtmlTree.LI(section)); 218 } 219 var li = HtmlTree.SECTION(HtmlStyle.packageUses, ul); 220 content.add(li); 221 } 222 223 /** 224 * {@return the package use HTML BODY element} 225 */ 226 private HtmlTree getBody() { 227 String packageText = resources.getText("doclet.Package"); 228 String name = packageElement.isUnnamed() ? "" 229 : utils.getPackageName(packageElement); 230 String title = resources.getText("doclet.Window_ClassUse_Header", 231 packageText, name); 232 HtmlTree body = getBody(getWindowTitle(title)); 233 ContentBuilder headingContent = new ContentBuilder(); 234 headingContent 235 .add(contents.getContent("doclet.ClassUse_Title", packageText)); 236 headingContent.add(new HtmlTree(TagName.BR)); 237 headingContent.add(name); 238 var heading = HtmlTree.HEADING_TITLE(Headings.PAGE_TITLE_HEADING, 239 HtmlStyle.title, headingContent); 240 var div = HtmlTree.DIV(HtmlStyle.header, heading); 241 bodyContents.setHeader(getHeader(PageMode.USE, packageElement)) 242 .addMainContent(div); 243 return body; 244 } 245 246 @Override 247 protected Navigation getNavBar(PageMode pageMode, Element element) { 248 Content linkContent 249 = getModuleLink(utils.elementUtils.getModuleOf(element), 250 contents.moduleLabel); 251 return super.getNavBar(pageMode, element) 252 .setNavLinkModule(linkContent); 253 } 254}