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 java.util.*;
  29 
  30 import javax.lang.model.element.PackageElement;
  31 import javax.lang.model.element.TypeElement;
  32 
  33 import jdk.javadoc.internal.doclets.formats.html.markup.ContentBuilder;
  34 import jdk.javadoc.internal.doclets.formats.html.markup.HtmlConstants;
  35 import jdk.javadoc.internal.doclets.formats.html.markup.HtmlStyle;
  36 import jdk.javadoc.internal.doclets.formats.html.markup.HtmlTag;
  37 import jdk.javadoc.internal.doclets.formats.html.markup.HtmlTree;
  38 import jdk.javadoc.internal.doclets.formats.html.markup.StringContent;
  39 import jdk.javadoc.internal.doclets.toolkit.Content;
  40 import jdk.javadoc.internal.doclets.toolkit.util.ClassUseMapper;
  41 import jdk.javadoc.internal.doclets.toolkit.util.DocFileIOException;
  42 import jdk.javadoc.internal.doclets.toolkit.util.DocPath;
  43 import jdk.javadoc.internal.doclets.toolkit.util.DocPaths;
  44 
  45 /**
  46  * Generate package usage information.
  47  *
  48  *  <p><b>This is NOT part of any supported API.
  49  *  If you write code that depends on this, you do so at your own risk.
  50  *  This code and its internal interfaces are subject to change or
  51  *  deletion without notice.</b>
  52  *
  53  * @author Robert G. Field
  54  * @author Bhavesh Patel (Modified)
  55  */
  56 public class PackageUseWriter extends SubWriterHolderWriter {
  57 
  58     final PackageElement packageElement;
  59     final SortedMap<String, Set<TypeElement>> usingPackageToUsedClasses = new TreeMap<>();
  60     protected HtmlTree mainTree = HtmlTree.MAIN();
  61 
  62     /**
  63      * Constructor.
  64      *
  65      * @param filename the file to be generated.
  66      */
  67     public PackageUseWriter(HtmlConfiguration configuration,
  68                             ClassUseMapper mapper, DocPath filename,
  69                             PackageElement pkgElement) {
  70         super(configuration, DocPath.forPackage(pkgElement).resolve(filename));
  71         this.packageElement = pkgElement;
  72 
  73         // by examining all classes in this package, find what packages
  74         // use these classes - produce a map between using package and
  75         // used classes.
  76         for (TypeElement usedClass : utils.getEnclosedTypeElements(pkgElement)) {
  77             Set<TypeElement> usingClasses = mapper.classToClass.get(usedClass);
  78             if (usingClasses != null) {
  79                 for (TypeElement usingClass : usingClasses) {
  80                     PackageElement usingPackage = utils.containingPackage(usingClass);
  81                     Set<TypeElement> usedClasses = usingPackageToUsedClasses
  82                             .get(utils.getPackageName(usingPackage));
  83                     if (usedClasses == null) {
  84                         usedClasses = new TreeSet<>(utils.makeGeneralPurposeComparator());
  85                         usingPackageToUsedClasses.put(utils.getPackageName(usingPackage),
  86                                                       usedClasses);
  87                     }
  88                     usedClasses.add(usedClass);
  89                 }
  90             }
  91         }
  92     }
  93 
  94     /**
  95      * Generate a class page.
  96      *
  97      * @param configuration the current configuration of the doclet.
  98      * @param mapper        the mapping of the class usage.
  99      * @param pkgElement    the package being documented.
 100      * @throws DocFileIOException if there is a problem generating the package use page
 101      */
 102     public static void generate(HtmlConfiguration configuration,
 103                                 ClassUseMapper mapper, PackageElement pkgElement)
 104             throws DocFileIOException {
 105         DocPath filename = DocPaths.PACKAGE_USE;
 106         PackageUseWriter pkgusegen = new PackageUseWriter(configuration, mapper, filename, pkgElement);
 107         pkgusegen.generatePackageUseFile();
 108     }
 109 
 110     /**
 111      * Generate the package use list.
 112      * @throws DocFileIOException if there is a problem generating the package use page
 113      */
 114     protected void generatePackageUseFile() throws DocFileIOException {
 115         HtmlTree body = getPackageUseHeader();
 116         HtmlTree div = new HtmlTree(HtmlTag.DIV);
 117         div.addStyle(HtmlStyle.contentContainer);
 118         if (usingPackageToUsedClasses.isEmpty()) {
 119             div.addContent(contents.getContent("doclet.ClassUse_No.usage.of.0", utils.getPackageName(packageElement)));
 120         } else {
 121             addPackageUse(div);
 122         }
 123         if (configuration.allowTag(HtmlTag.MAIN)) {
 124             mainTree.addContent(div);
 125             body.addContent(mainTree);
 126         } else {
 127             body.addContent(div);
 128         }
 129         HtmlTree tree = (configuration.allowTag(HtmlTag.FOOTER))
 130                 ? HtmlTree.FOOTER()
 131                 : body;
 132         addNavLinks(false, tree);
 133         addBottom(tree);
 134         if (configuration.allowTag(HtmlTag.FOOTER)) {
 135             body.addContent(tree);
 136         }
 137         printHtmlDocument(null, true, body);
 138     }
 139 
 140     /**
 141      * Add the package use information.
 142      *
 143      * @param contentTree the content tree to which the package use information will be added
 144      */
 145     protected void addPackageUse(Content contentTree) {
 146         HtmlTree ul = new HtmlTree(HtmlTag.UL);
 147         ul.addStyle(HtmlStyle.blockList);
 148         if (configuration.packages.size() > 1) {
 149             addPackageList(ul);
 150         }
 151         addClassList(ul);
 152         contentTree.addContent(ul);
 153     }
 154 
 155     /**
 156      * Add the list of packages that use the given package.
 157      *
 158      * @param contentTree the content tree to which the package list will be added
 159      */
 160     protected void addPackageList(Content contentTree) {
 161         Content caption = getTableCaption(configuration.getContent(
 162                 "doclet.ClassUse_Packages.that.use.0",
 163                 getPackageLink(packageElement, utils.getPackageName(packageElement))));
 164         Content table = (configuration.isOutputHtml5())
 165                 ? HtmlTree.TABLE(HtmlStyle.useSummary, caption)
 166                 : HtmlTree.TABLE(HtmlStyle.useSummary, useTableSummary, caption);
 167         table.addContent(getSummaryTableHeader(packageTableHeader, "col"));
 168         Content tbody = new HtmlTree(HtmlTag.TBODY);
 169         boolean altColor = true;
 170         for (String pkgname: usingPackageToUsedClasses.keySet()) {
 171             PackageElement pkg = utils.elementUtils.getPackageElement(pkgname);
 172             HtmlTree tr = new HtmlTree(HtmlTag.TR);
 173             tr.addStyle(altColor ? HtmlStyle.altColor : HtmlStyle.rowColor);
 174             altColor = !altColor;
 175             addPackageUse(pkg, tr);
 176             tbody.addContent(tr);
 177         }
 178         table.addContent(tbody);
 179         Content li = HtmlTree.LI(HtmlStyle.blockList, table);
 180         contentTree.addContent(li);
 181     }
 182 
 183     /**
 184      * Add the list of classes that use the given package.
 185      *
 186      * @param contentTree the content tree to which the class list will be added
 187      */
 188     protected void addClassList(Content contentTree) {
 189         List<String> classTableHeader = Arrays.asList(
 190                 resources.getText("doclet.Class"), resources.getText("doclet.Description"));
 191         for (String packageName : usingPackageToUsedClasses.keySet()) {
 192             PackageElement usingPackage = utils.elementUtils.getPackageElement(packageName);
 193             HtmlTree li = new HtmlTree(HtmlTag.LI);
 194             li.addStyle(HtmlStyle.blockList);
 195             if (usingPackage != null) {
 196                 li.addContent(getMarkerAnchor(utils.getPackageName(usingPackage)));
 197             }
 198             String tableSummary = configuration.getText("doclet.Use_Table_Summary",
 199                                                         configuration.getText("doclet.classes"));
 200             Content caption = getTableCaption(configuration.getContent(
 201                     "doclet.ClassUse_Classes.in.0.used.by.1",
 202                     getPackageLink(packageElement, utils.getPackageName(packageElement)),
 203                     getPackageLink(usingPackage, utils.getPackageName(usingPackage))));
 204             Content table = (configuration.isOutputHtml5())
 205                     ? HtmlTree.TABLE(HtmlStyle.useSummary, caption)
 206                     : HtmlTree.TABLE(HtmlStyle.useSummary, tableSummary, caption);
 207             table.addContent(getSummaryTableHeader(classTableHeader, "col"));
 208             Content tbody = new HtmlTree(HtmlTag.TBODY);
 209             boolean altColor = true;
 210             for (TypeElement te : usingPackageToUsedClasses.get(packageName)) {
 211                 HtmlTree tr = new HtmlTree(HtmlTag.TR);
 212                 tr.addStyle(altColor ? HtmlStyle.altColor : HtmlStyle.rowColor);
 213                 altColor = !altColor;
 214                 addClassRow(te, usingPackage, tr);
 215                 tbody.addContent(tr);
 216             }
 217             table.addContent(tbody);
 218             li.addContent(table);
 219             contentTree.addContent(li);
 220         }
 221     }
 222 
 223     /**
 224      * Add a row for the class that uses the given package.
 225      *
 226      * @param usedClass the class that uses the given package
 227      * @param pkg  the package to which the class belongs
 228      * @param contentTree the content tree to which the row will be added
 229      */
 230     protected void addClassRow(TypeElement usedClass, PackageElement pkg,
 231             Content contentTree) {
 232         DocPath dp = pathString(usedClass,
 233                 DocPaths.CLASS_USE.resolve(DocPath.forName(utils, usedClass)));
 234         StringContent stringContent = new StringContent(utils.getSimpleName(usedClass));
 235         Content thType = HtmlTree.TH_ROW_SCOPE(HtmlStyle.colFirst,
 236                 getHyperLink(dp.fragment(getPackageAnchorName(pkg)), stringContent));
 237         contentTree.addContent(thType);
 238         HtmlTree tdDesc = new HtmlTree(HtmlTag.TD);
 239         tdDesc.addStyle(HtmlStyle.colLast);
 240         addIndexComment(usedClass, tdDesc);
 241         contentTree.addContent(tdDesc);
 242     }
 243 
 244     /**
 245      * Add the package use information.
 246      *
 247      * @param pkg the package that used the given package
 248      * @param contentTree the content tree to which the information will be added
 249      */
 250     protected void addPackageUse(PackageElement pkg, Content contentTree) {
 251         Content thFirst = HtmlTree.TH_ROW_SCOPE(HtmlStyle.colFirst,
 252                 getHyperLink(utils.getPackageName(pkg),
 253                 new StringContent(utils.getPackageName(pkg))));
 254         contentTree.addContent(thFirst);
 255         HtmlTree tdLast = new HtmlTree(HtmlTag.TD);
 256         tdLast.addStyle(HtmlStyle.colLast);
 257         if (pkg != null && !pkg.isUnnamed()) {
 258             addSummaryComment(pkg, tdLast);
 259         } else {
 260             tdLast.addContent(Contents.SPACE);
 261         }
 262         contentTree.addContent(tdLast);
 263     }
 264 
 265     /**
 266      * Get the header for the package use listing.
 267      *
 268      * @return a content tree representing the package use header
 269      */
 270     protected HtmlTree getPackageUseHeader() {
 271         String packageText = configuration.getText("doclet.Package");
 272         String name = packageElement.isUnnamed() ? "" : utils.getPackageName(packageElement);
 273         String title = configuration.getText("doclet.Window_ClassUse_Header", packageText, name);
 274         HtmlTree bodyTree = getBody(true, getWindowTitle(title));
 275         HtmlTree htmlTree = (configuration.allowTag(HtmlTag.HEADER))
 276                 ? HtmlTree.HEADER()
 277                 : bodyTree;
 278         addTop(htmlTree);
 279         addNavLinks(true, htmlTree);
 280         if (configuration.allowTag(HtmlTag.HEADER)) {
 281             bodyTree.addContent(htmlTree);
 282         }
 283         ContentBuilder headContent = new ContentBuilder();
 284         headContent.addContent(contents.getContent("doclet.ClassUse_Title", packageText));
 285         headContent.addContent(new HtmlTree(HtmlTag.BR));
 286         headContent.addContent(name);
 287         Content heading = HtmlTree.HEADING(HtmlConstants.TITLE_HEADING, true,
 288                 HtmlStyle.title, headContent);
 289         Content div = HtmlTree.DIV(HtmlStyle.header, heading);
 290         if (configuration.allowTag(HtmlTag.MAIN)) {
 291             mainTree.addContent(div);
 292         } else {
 293             bodyTree.addContent(div);
 294         }
 295         return bodyTree;
 296     }
 297 
 298     /**
 299      * Get the module link.
 300      *
 301      * @return a content tree for the module link
 302      */
 303     @Override
 304     protected Content getNavLinkModule() {
 305         Content linkContent = getModuleLink(utils.elementUtils.getModuleOf(packageElement),
 306                 contents.moduleLabel);
 307         Content li = HtmlTree.LI(linkContent);
 308         return li;
 309     }
 310 
 311     /**
 312      * Get this package link.
 313      *
 314      * @return a content tree for the package link
 315      */
 316     @Override
 317     protected Content getNavLinkPackage() {
 318         Content linkContent = getHyperLink(DocPaths.PACKAGE_SUMMARY,
 319                 contents.packageLabel);
 320         Content li = HtmlTree.LI(linkContent);
 321         return li;
 322     }
 323 
 324     /**
 325      * Get the use link.
 326      *
 327      * @return a content tree for the use link
 328      */
 329     @Override
 330     protected Content getNavLinkClassUse() {
 331         Content li = HtmlTree.LI(HtmlStyle.navBarCell1Rev, contents.useLabel);
 332         return li;
 333     }
 334 
 335     /**
 336      * Get the tree link.
 337      *
 338      * @return a content tree for the tree link
 339      */
 340     @Override
 341     protected Content getNavLinkTree() {
 342         Content linkContent = getHyperLink(DocPaths.PACKAGE_TREE,
 343                 contents.treeLabel);
 344         Content li = HtmlTree.LI(linkContent);
 345         return li;
 346     }
 347 }