1 /*
   2  * Copyright (c) 1997, 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.markup;
  27 
  28 import java.util.*;
  29 
  30 import javax.lang.model.element.ModuleElement;
  31 import javax.lang.model.element.PackageElement;
  32 import javax.lang.model.element.TypeElement;
  33 
  34 import jdk.javadoc.internal.doclets.formats.html.HtmlConfiguration;
  35 import jdk.javadoc.internal.doclets.formats.html.SectionName;
  36 import jdk.javadoc.internal.doclets.toolkit.Content;
  37 import jdk.javadoc.internal.doclets.toolkit.Messages;
  38 import jdk.javadoc.internal.doclets.toolkit.util.DocFile;
  39 import jdk.javadoc.internal.doclets.toolkit.util.DocLink;
  40 import jdk.javadoc.internal.doclets.toolkit.util.DocPath;
  41 import jdk.javadoc.internal.doclets.toolkit.util.DocPaths;
  42 
  43 
  44 /**
  45  * Class for the Html Format Code Generation specific to JavaDoc.
  46  * This Class contains methods related to the Html Code Generation which
  47  * are used by the Sub-Classes in the package jdk.javadoc.internal.tool.standard.
  48  *
  49  *  <p><b>This is NOT part of any supported API.
  50  *  If you write code that depends on this, you do so at your own risk.
  51  *  This code and its internal interfaces are subject to change or
  52  *  deletion without notice.</b>
  53  *
  54  * @author Atul M Dambalkar
  55  * @author Robert Field
  56  */
  57 public abstract class HtmlDocWriter extends HtmlWriter {
  58 
  59     public static final String CONTENT_TYPE = "text/html";
  60 
  61     private final HtmlConfiguration configuration;
  62     private final DocPath pathToRoot;
  63 
  64     /**
  65      * Constructor. Initializes the destination file name through the super
  66      * class HtmlWriter.
  67      *
  68      * @param configuration the configuration for this doclet
  69      * @param filename String file name.
  70      */
  71     public HtmlDocWriter(HtmlConfiguration configuration, DocPath filename) {
  72         super(configuration, filename);
  73         this.configuration = configuration;
  74         this.pathToRoot = filename.parent().invert();
  75         Messages messages = configuration.getMessages();
  76         messages.notice("doclet.Generating_0",
  77             DocFile.createFileForOutput(configuration, filename).getPath());
  78     }
  79 
  80     public Content getHyperLink(DocPath link, String label) {
  81         return getHyperLink(link, new StringContent(label), false, "", "", "");
  82     }
  83 
  84     /**
  85      * Get Html Hyper Link Content.
  86      *
  87      * @param where      Position of the link in the file. Character '#' is not
  88      *                   needed.
  89      * @param label      Tag for the link.
  90      * @return a content tree for the hyper link
  91      */
  92     public Content getHyperLink(String where,
  93                                Content label) {
  94         return getHyperLink(getDocLink(where), label, "", "");
  95     }
  96 
  97     /**
  98      * Get Html Hyper Link Content.
  99      *
 100      * @param sectionName      The section name to which the link will be created.
 101      * @param label            Tag for the link.
 102      * @return a content tree for the hyper link
 103      */
 104     public Content getHyperLink(SectionName sectionName,
 105                                Content label) {
 106         return getHyperLink(getDocLink(sectionName), label, "", "");
 107     }
 108 
 109     /**
 110      * Get Html Hyper Link Content.
 111      *
 112      * @param sectionName      The section name combined with where to which the link
 113      *                         will be created.
 114      * @param where            The fragment combined with sectionName to which the link
 115      *                         will be created.
 116      * @param label            Tag for the link.
 117      * @return a content tree for the hyper link
 118      */
 119     public Content getHyperLink(SectionName sectionName, String where,
 120                                Content label) {
 121         return getHyperLink(getDocLink(sectionName, where), label, "", "");
 122     }
 123 
 124     /**
 125      * Get the link.
 126      *
 127      * @param where      Position of the link in the file.
 128      * @return a DocLink object for the hyper link
 129      */
 130     public DocLink getDocLink(String where) {
 131         return DocLink.fragment(getName(where));
 132     }
 133 
 134     /**
 135      * Get the link.
 136      *
 137      * @param sectionName      The section name to which the link will be created.
 138      * @return a DocLink object for the hyper link
 139      */
 140     public DocLink getDocLink(SectionName sectionName) {
 141         return DocLink.fragment(sectionName.getName());
 142     }
 143 
 144     /**
 145      * Get the link.
 146      *
 147      * @param sectionName      The section name combined with where to which the link
 148      *                         will be created.
 149      * @param where            The fragment combined with sectionName to which the link
 150      *                         will be created.
 151      * @return a DocLink object for the hyper link
 152      */
 153     public DocLink getDocLink(SectionName sectionName, String where) {
 154         return DocLink.fragment(sectionName.getName() + getName(where));
 155     }
 156 
 157     /**
 158      * Convert the name to a valid HTML name.
 159      *
 160      * @param name the name that needs to be converted to valid HTML name.
 161      * @return a valid HTML name string.
 162      */
 163     public String getName(String name) {
 164         /* The HTML 4 spec at http://www.w3.org/TR/html4/types.html#h-6.2 mentions
 165          * that the name/id should begin with a letter followed by other valid characters.
 166          * The HTML 5 spec (draft) is more permissive on names/ids where the only restriction
 167          * is that it should be at least one character long and should not contain spaces.
 168          * The spec draft is @ http://www.w3.org/html/wg/drafts/html/master/dom.html#the-id-attribute.
 169          *
 170          * For HTML 4, we need to check for non-characters at the beginning of the name and
 171          * substitute it accordingly, "_" and "$" can appear at the beginning of a member name.
 172          * The method substitutes "$" with "Z:Z:D" and will prefix "_" with "Z:Z".
 173          */
 174 
 175         if (configuration.isOutputHtml5()) {
 176             return name.replaceAll(" +", "");
 177         }
 178 
 179         StringBuilder sb = new StringBuilder();
 180         for (int i = 0; i < name.length(); i++) {
 181             char ch = name.charAt(i);
 182             switch (ch) {
 183                 case '(':
 184                 case ')':
 185                 case '<':
 186                 case '>':
 187                 case ',':
 188                     sb.append('-');
 189                     break;
 190                 case ' ':
 191                 case '[':
 192                     break;
 193                 case ']':
 194                     sb.append(":A");
 195                     break;
 196                 // Any appearance of $ needs to be substituted with ":D" and not with hyphen
 197                 // since a field name "P$$ and a method P(), both valid member names, can end
 198                 // up as "P--". A member name beginning with $ needs to be substituted with
 199                 // "Z:Z:D".
 200                 case '$':
 201                     if (i == 0)
 202                         sb.append("Z:Z");
 203                     sb.append(":D");
 204                     break;
 205                 // A member name beginning with _ needs to be prefixed with "Z:Z" since valid anchor
 206                 // names can only begin with a letter.
 207                 case '_':
 208                     if (i == 0)
 209                         sb.append("Z:Z");
 210                     sb.append(ch);
 211                     break;
 212                 default:
 213                     sb.append(ch);
 214             }
 215         }
 216         return sb.toString();
 217     }
 218 
 219     /**
 220      * Get Html hyperlink.
 221      *
 222      * @param link       path of the file.
 223      * @param label      Tag for the link.
 224      * @return a content tree for the hyper link
 225      */
 226     public Content getHyperLink(DocPath link, Content label) {
 227         return getHyperLink(link, label, "", "");
 228     }
 229 
 230     public Content getHyperLink(DocLink link, Content label) {
 231         return getHyperLink(link, label, "", "");
 232     }
 233 
 234     public Content getHyperLink(DocPath link,
 235                                Content label, boolean strong,
 236                                String stylename, String title, String target) {
 237         return getHyperLink(new DocLink(link), label, strong,
 238                 stylename, title, target);
 239     }
 240 
 241     public Content getHyperLink(DocLink link,
 242                                Content label, boolean strong,
 243                                String stylename, String title, String target) {
 244         Content body = label;
 245         if (strong) {
 246             body = HtmlTree.SPAN(HtmlStyle.typeNameLink, body);
 247         }
 248         if (stylename != null && stylename.length() != 0) {
 249             HtmlTree t = new HtmlTree(HtmlTag.FONT, body);
 250             t.addAttr(HtmlAttr.CLASS, stylename);
 251             body = t;
 252         }
 253         HtmlTree l = HtmlTree.A(link.toString(), body);
 254         if (title != null && title.length() != 0) {
 255             l.addAttr(HtmlAttr.TITLE, title);
 256         }
 257         if (target != null && target.length() != 0) {
 258             l.addAttr(HtmlAttr.TARGET, target);
 259         }
 260         return l;
 261     }
 262 
 263     /**
 264      * Get Html Hyper Link.
 265      *
 266      * @param link       String name of the file.
 267      * @param label      Tag for the link.
 268      * @param title      String that describes the link's content for accessibility.
 269      * @param target     Target frame.
 270      * @return a content tree for the hyper link.
 271      */
 272     public Content getHyperLink(DocPath link, Content label, String title, String target) {
 273         return getHyperLink(new DocLink(link), label, title, target);
 274     }
 275 
 276     public Content getHyperLink(DocLink link, Content label, String title, String target) {
 277         HtmlTree anchor = HtmlTree.A(link.toString(), label);
 278         if (title != null && title.length() != 0) {
 279             anchor.addAttr(HtmlAttr.TITLE, title);
 280         }
 281         if (target != null && target.length() != 0) {
 282             anchor.addAttr(HtmlAttr.TARGET, target);
 283         }
 284         return anchor;
 285     }
 286 
 287     public Content getModuleFramesHyperLink(ModuleElement mdle, Content label, String target) {
 288         DocLink mdlLink = new DocLink(DocPaths.moduleFrame(mdle));
 289         DocLink mtFrameLink = new DocLink(DocPaths.moduleTypeFrame(mdle));
 290         DocLink cFrameLink = new DocLink(DocPaths.moduleSummary(mdle));
 291         HtmlTree anchor = HtmlTree.A(mdlLink.toString(), label);
 292         String onclickStr = "updateModuleFrame('" + mtFrameLink + "','" + cFrameLink + "');";
 293         anchor.addAttr(HtmlAttr.TARGET, target);
 294         anchor.addAttr(HtmlAttr.ONCLICK, onclickStr);
 295         return anchor;
 296     }
 297 
 298     /**
 299      * Get the enclosed name of the package
 300      *
 301      * @param te  TypeElement
 302      * @return the name
 303      */
 304     public String getEnclosingPackageName(TypeElement te) {
 305 
 306         PackageElement encl = configuration.utils.containingPackage(te);
 307         return (encl.isUnnamed()) ? "" : (encl.getQualifiedName() + ".");
 308     }
 309 
 310     /**
 311      * Returns a link to the stylesheet file.
 312      *
 313      * @param configuration the configuration for this doclet
 314      * @return an HtmlTree for the lINK tag which provides the stylesheet location
 315      */
 316     public HtmlTree getStyleSheetProperties(HtmlConfiguration configuration) {
 317         String stylesheetfile = configuration.stylesheetfile;
 318         DocPath stylesheet;
 319         if (stylesheetfile.isEmpty()) {
 320             stylesheet = DocPaths.STYLESHEET;
 321         } else {
 322             DocFile file = DocFile.createFileForInput(configuration, stylesheetfile);
 323             stylesheet = DocPath.create(file.getName());
 324         }
 325         HtmlTree link = HtmlTree.LINK("stylesheet", "text/css",
 326                 pathToRoot.resolve(stylesheet).getPath(),
 327                 "Style");
 328         return link;
 329     }
 330 
 331     protected Comment getGeneratedBy(boolean timestamp) {
 332         String text = "Generated by javadoc"; // marker string, deliberately not localized
 333         if (timestamp) {
 334             Calendar calendar = new GregorianCalendar(TimeZone.getDefault());
 335             Date today = calendar.getTime();
 336             text += " ("+ configuration.getDocletSpecificBuildDate() + ") on " + today;
 337         }
 338         return new Comment(text);
 339     }
 340 }