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