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
26package com.sun.tools.doclets.formats.html.markup;
27
28import java.io.*;
29import java.util.*;
30
31import com.sun.javadoc.*;
32import com.sun.tools.doclets.formats.html.ConfigurationImpl;
33import com.sun.tools.doclets.formats.html.SectionName;
34import com.sun.tools.doclets.internal.toolkit.*;
35import com.sun.tools.doclets.internal.toolkit.util.DocFile;
36import com.sun.tools.doclets.internal.toolkit.util.DocLink;
37import com.sun.tools.doclets.internal.toolkit.util.DocPath;
38import 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@Deprecated
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,
271            Content label, String title, String target) {
272        return getHyperLink(new DocLink(link), label, title, target);
273    }
274
275    public Content getHyperLink(DocLink link,
276            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    /**
288     * Get the name of the package, this class is in.
289     *
290     * @param cd    ClassDoc.
291     */
292    public String getPkgName(ClassDoc cd) {
293        String pkgName = cd.containingPackage().name();
294        if (pkgName.length() > 0) {
295            pkgName += ".";
296            return pkgName;
297        }
298        return "";
299    }
300
301    public boolean getMemberDetailsListPrinted() {
302        return memberDetailsListPrinted;
303    }
304
305    /**
306     * Print the frames version of the Html file header.
307     * Called only when generating an HTML frames file.
308     *
309     * @param title Title of this HTML document
310     * @param configuration the configuration object
311     * @param body the body content tree to be added to the HTML document
312     */
313    public void printFramesDocument(String title, ConfigurationImpl configuration,
314            HtmlTree body) throws IOException {
315        Content htmlDocType = configuration.isOutputHtml5()
316                ? DocType.HTML5
317                : DocType.TRANSITIONAL;
318        Content htmlComment = new Comment(configuration.getText("doclet.New_Page"));
319        Content head = new HtmlTree(HtmlTag.HEAD);
320        head.addContent(getGeneratedBy(!configuration.notimestamp));
321        Content windowTitle = HtmlTree.TITLE(new StringContent(title));
322        head.addContent(windowTitle);
323        Content meta = HtmlTree.META("Content-Type", CONTENT_TYPE,
324                (configuration.charset.length() > 0) ?
325                        configuration.charset : HtmlConstants.HTML_DEFAULT_CHARSET);
326        head.addContent(meta);
327        head.addContent(getStyleSheetProperties(configuration));
328        head.addContent(getFramesJavaScript());
329        Content htmlTree = HtmlTree.HTML(configuration.getLocale().getLanguage(),
330                head, body);
331        Content htmlDocument = new HtmlDocument(htmlDocType,
332                htmlComment, htmlTree);
333        write(htmlDocument);
334    }
335
336    /**
337     * Returns a link to the stylesheet file.
338     *
339     * @return an HtmlTree for the lINK tag which provides the stylesheet location
340     */
341    public HtmlTree getStyleSheetProperties(ConfigurationImpl configuration) {
342        String stylesheetfile = configuration.stylesheetfile;
343        DocPath stylesheet;
344        if (stylesheetfile.isEmpty()) {
345            stylesheet = DocPaths.STYLESHEET;
346        } else {
347            DocFile file = DocFile.createFileForInput(configuration, stylesheetfile);
348            stylesheet = DocPath.create(file.getName());
349        }
350        HtmlTree link = HtmlTree.LINK("stylesheet", "text/css",
351                pathToRoot.resolve(stylesheet).getPath(),
352                "Style");
353        return link;
354    }
355
356    protected Comment getGeneratedBy(boolean timestamp) {
357        String text = "Generated by javadoc"; // marker string, deliberately not localized
358        if (timestamp) {
359            Calendar calendar = new GregorianCalendar(TimeZone.getDefault());
360            Date today = calendar.getTime();
361            text += " ("+ configuration.getDocletSpecificBuildDate() + ") on " + today;
362        }
363        return new Comment(text);
364    }
365}
366