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