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