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