TagletWriterImpl.java revision 3233:b5d08bc0d224
1177867Sjfv/*
2169240Sjfv * Copyright (c) 2003, 2016, Oracle and/or its affiliates. All rights reserved.
3238262Sjfv * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4169240Sjfv *
5169240Sjfv * This code is free software; you can redistribute it and/or modify it
6169240Sjfv * under the terms of the GNU General Public License version 2 only, as
7169240Sjfv * published by the Free Software Foundation.  Oracle designates this
8169240Sjfv * particular file as subject to the "Classpath" exception as provided
9169240Sjfv * by Oracle in the LICENSE file that accompanied this code.
10169240Sjfv *
11169240Sjfv * This code is distributed in the hope that it will be useful, but WITHOUT
12169240Sjfv * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13169240Sjfv * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14169240Sjfv * version 2 for more details (a copy is included in the LICENSE file that
15169240Sjfv * accompanied this code).
16169240Sjfv *
17169240Sjfv * You should have received a copy of the GNU General Public License version
18169240Sjfv * 2 along with this work; if not, write to the Free Software Foundation,
19169240Sjfv * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20169240Sjfv *
21169240Sjfv * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22169240Sjfv * or visit www.oracle.com if you need additional information or have any
23169240Sjfv * questions.
24169240Sjfv */
25169240Sjfv
26169240Sjfvpackage jdk.javadoc.internal.doclets.formats.html;
27169240Sjfv
28169240Sjfvimport java.util.List;
29169240Sjfvimport javax.lang.model.element.Element;
30169240Sjfvimport javax.lang.model.element.PackageElement;
31169240Sjfvimport javax.lang.model.element.TypeElement;
32177867Sjfvimport javax.lang.model.element.VariableElement;
33177867Sjfvimport javax.lang.model.type.TypeMirror;
34169240Sjfvimport javax.lang.model.util.SimpleElementVisitor9;
35169240Sjfv
36169240Sjfvimport com.sun.source.doctree.DocTree;
37169240Sjfvimport com.sun.source.doctree.IndexTree;
38173788Sjfvimport com.sun.tools.javac.util.DefinedBy;
39173788Sjfv
40169240Sjfvimport jdk.javadoc.internal.doclets.formats.html.markup.ContentBuilder;
41169240Sjfvimport jdk.javadoc.internal.doclets.formats.html.markup.HtmlStyle;
42177867Sjfvimport jdk.javadoc.internal.doclets.formats.html.markup.HtmlTree;
43177867Sjfvimport jdk.javadoc.internal.doclets.formats.html.markup.RawHtml;
44177867Sjfvimport jdk.javadoc.internal.doclets.formats.html.markup.StringContent;
45177867Sjfvimport jdk.javadoc.internal.doclets.toolkit.Configuration;
46177867Sjfvimport jdk.javadoc.internal.doclets.toolkit.Content;
47190872Sjfvimport jdk.javadoc.internal.doclets.toolkit.builders.SerializedFormBuilder;
48177867Sjfvimport jdk.javadoc.internal.doclets.toolkit.taglets.TagletWriter;
49177867Sjfvimport jdk.javadoc.internal.doclets.toolkit.util.CommentHelper;
50169240Sjfvimport jdk.javadoc.internal.doclets.toolkit.util.DocLink;
51169240Sjfvimport jdk.javadoc.internal.doclets.toolkit.util.DocPath;
52169240Sjfvimport jdk.javadoc.internal.doclets.toolkit.util.DocPaths;
53169240Sjfvimport jdk.javadoc.internal.doclets.toolkit.util.DocletConstants;
54169240Sjfvimport jdk.javadoc.internal.doclets.toolkit.util.MessageRetriever;
55218588Sjfvimport jdk.javadoc.internal.doclets.toolkit.util.Utils;
56218588Sjfv
57169240Sjfv/**
58169240Sjfv * The taglet writer that writes HTML.
59169240Sjfv *
60169240Sjfv *  <p><b>This is NOT part of any supported API.
61169240Sjfv *  If you write code that depends on this, you do so at your own risk.
62169240Sjfv *  This code and its internal interfaces are subject to change or
63185353Sjfv *  deletion without notice.</b>
64185353Sjfv *
65169240Sjfv * @author Jamie Ho
66169240Sjfv * @author Bhavesh Patel (Modified)
67238262Sjfv */
68169240Sjfv
69238262Sjfvpublic class TagletWriterImpl extends TagletWriter {
70169240Sjfv
71169240Sjfv    private final HtmlDocletWriter htmlWriter;
72169240Sjfv    private final ConfigurationImpl configuration;
73173788Sjfv    private final Utils utils;
74238262Sjfv
75218581Sjfv    public TagletWriterImpl(HtmlDocletWriter htmlWriter, boolean isFirstSentence) {
76169240Sjfv        super(isFirstSentence);
77169240Sjfv        this.htmlWriter = htmlWriter;
78169240Sjfv        configuration = htmlWriter.configuration;
79169240Sjfv        this.utils = configuration.utils;
80169240Sjfv    }
81238262Sjfv
82169240Sjfv    /**
83169240Sjfv     * {@inheritDoc}
84169240Sjfv     */
85169240Sjfv    public Content getOutputInstance() {
86169240Sjfv        return new ContentBuilder();
87169240Sjfv    }
88169240Sjfv
89169240Sjfv    /**
90173788Sjfv     * {@inheritDoc}
91169240Sjfv     */
92169240Sjfv    protected Content codeTagOutput(Element element, DocTree tag) {
93169240Sjfv        CommentHelper ch = utils.getCommentHelper(element);
94169240Sjfv        String str = utils.normalizeNewlines(ch.getText(tag));
95169240Sjfv        StringContent content = new StringContent(str);
96169240Sjfv        Content result = HtmlTree.CODE(content);
97        return result;
98    }
99
100    protected Content indexTagOutput(Element element, DocTree tag) {
101        CommentHelper ch = utils.getCommentHelper(element);
102        IndexTree itt = (IndexTree)tag;
103
104        String tagText =  ch.getText(itt.getSearchTerm());
105        if (tagText.charAt(0) == '"' && tagText.charAt(tagText.length() - 1) == '"') {
106            tagText = tagText.substring(1, tagText.length() - 1);
107        }
108        String desc = ch.getText(itt.getDescription());
109
110        String anchorName = htmlWriter.getName(tagText);
111        Content result = HtmlTree.A_ID(anchorName, new StringContent(tagText));
112        if (configuration.createindex && !tagText.isEmpty()) {
113            SearchIndexItem si = new SearchIndexItem();
114            si.setLabel(tagText);
115            si.setDescription(desc);
116            new SimpleElementVisitor9<Void, Void>() {
117                @Override @DefinedBy(DefinedBy.Api.LANGUAGE_MODEL)
118                public Void visitPackage(PackageElement e, Void p) {
119                    si.setUrl(DocPath.forPackage(e).getPath()
120                            + "/" + DocPaths.PACKAGE_SUMMARY.getPath() + "#" + anchorName);
121                    si.setHolder(utils.getSimpleName(element));
122                    return null;
123                }
124
125                @Override @DefinedBy(DefinedBy.Api.LANGUAGE_MODEL)
126                public Void visitType(TypeElement e, Void p) {
127                    si.setUrl(DocPath.forClass(utils, e).getPath() + "#" + anchorName);
128                    si.setHolder(utils.getFullyQualifiedName(e));
129                    return null;
130                }
131
132                @Override @DefinedBy(DefinedBy.Api.LANGUAGE_MODEL)
133                public Void visitVariable(VariableElement e, Void p) {
134                    TypeElement te = utils.getEnclosingTypeElement(e);
135                    si.setUrl(DocPath.forClass(utils, te).getPath() + "#" + anchorName);
136                    si.setHolder(utils.getFullyQualifiedName(e) + "." + utils.getSimpleName(e));
137                    return null;
138                }
139
140                @Override @DefinedBy(DefinedBy.Api.LANGUAGE_MODEL)
141                protected Void defaultAction(Element e, Void p) {
142                    TypeElement te = utils.getEnclosingTypeElement(e);
143                    si.setUrl(DocPath.forClass(utils, te).getPath() + "#" + anchorName);
144                    si.setHolder(utils.getFullyQualifiedName(e));
145                    return null;
146                }
147            }.visit(element);
148            si.setCategory(configuration.getResource("doclet.SearchTags").toString());
149            configuration.tagSearchIndex.add(si);
150        }
151        return result;
152    }
153
154    /**
155     * {@inheritDoc}
156     */
157    public Content getDocRootOutput() {
158        String path;
159        if (htmlWriter.pathToRoot.isEmpty())
160            path = ".";
161        else
162            path = htmlWriter.pathToRoot.getPath();
163        return new StringContent(path);
164    }
165
166    /**
167     * {@inheritDoc}
168     */
169    public Content deprecatedTagOutput(Element element) {
170        ContentBuilder result = new ContentBuilder();
171        CommentHelper ch = utils.getCommentHelper(element);
172        List<? extends DocTree> deprs = utils.getBlockTags(element, DocTree.Kind.DEPRECATED);
173        if (utils.isTypeElement(element)) {
174            if (utils.isDeprecated(element)) {
175                result.addContent(HtmlTree.SPAN(HtmlStyle.deprecatedLabel,
176                        new StringContent(configuration.getText("doclet.Deprecated"))));
177                result.addContent(RawHtml.nbsp);
178                if (!deprs.isEmpty()) {
179                    List<? extends DocTree> commentTags = ch.getDescription(configuration, deprs.get(0));
180                    if (!commentTags.isEmpty()) {
181                        result.addContent(commentTagsToOutput(null, element, commentTags, false));
182                    }
183                }
184            }
185        } else {
186            if (utils.isDeprecated(element)) {
187                result.addContent(HtmlTree.SPAN(HtmlStyle.deprecatedLabel,
188                        new StringContent(configuration.getText("doclet.Deprecated"))));
189                result.addContent(RawHtml.nbsp);
190                if (!deprs.isEmpty()) {
191                    List<? extends DocTree> bodyTags = ch.getBody(configuration, deprs.get(0));
192                    Content body = commentTagsToOutput(null, element, bodyTags, false);
193                    if (!body.isEmpty())
194                        result.addContent(HtmlTree.SPAN(HtmlStyle.deprecationComment, body));
195                }
196            } else {
197                if (utils.isDeprecated(utils.getEnclosingTypeElement(element))) {
198                    result.addContent(HtmlTree.SPAN(HtmlStyle.deprecatedLabel,
199                            new StringContent(configuration.getText("doclet.Deprecated"))));
200                    result.addContent(RawHtml.nbsp);
201                }
202            }
203        }
204        return result;
205    }
206
207    /**
208     * {@inheritDoc}
209     */
210    protected Content literalTagOutput(Element element, DocTree tag) {
211        CommentHelper ch = utils.getCommentHelper(element);
212        Content result = new StringContent(utils.normalizeNewlines(ch.getText(tag)));
213        return result;
214    }
215
216    /**
217     * {@inheritDoc}
218     */
219    public MessageRetriever getMsgRetriever() {
220        return configuration.message;
221    }
222
223    /**
224     * {@inheritDoc}
225     */
226    public Content getParamHeader(String header) {
227        HtmlTree result = HtmlTree.DT(HtmlTree.SPAN(HtmlStyle.paramLabel,
228                new StringContent(header)));
229        return result;
230    }
231
232    /**
233     * {@inheritDoc}
234     */
235    public Content paramTagOutput(Element element, DocTree paramTag, String paramName) {
236        ContentBuilder body = new ContentBuilder();
237        CommentHelper ch = utils.getCommentHelper(element);
238        body.addContent(HtmlTree.CODE(new RawHtml(paramName)));
239        body.addContent(" - ");
240        List<? extends DocTree> description = ch.getDescription(configuration, paramTag);
241        body.addContent(htmlWriter.commentTagsToContent(paramTag, element, description, false));
242        HtmlTree result = HtmlTree.DD(body);
243        return result;
244    }
245
246    /**
247     * {@inheritDoc}
248     */
249    public Content propertyTagOutput(Element element, DocTree tag, String prefix) {
250        Content body = new ContentBuilder();
251        CommentHelper ch = utils.getCommentHelper(element);
252        body.addContent(new RawHtml(prefix));
253        body.addContent(" ");
254        body.addContent(HtmlTree.CODE(new RawHtml(ch.getText(tag))));
255        body.addContent(".");
256        Content result = HtmlTree.P(body);
257        return result;
258    }
259
260    /**
261     * {@inheritDoc}
262     */
263    public Content returnTagOutput(Element element, DocTree returnTag) {
264        ContentBuilder result = new ContentBuilder();
265        CommentHelper ch = utils.getCommentHelper(element);
266        result.addContent(HtmlTree.DT(HtmlTree.SPAN(HtmlStyle.returnLabel,
267                new StringContent(configuration.getText("doclet.Returns")))));
268        result.addContent(HtmlTree.DD(htmlWriter.commentTagsToContent(
269                returnTag, element, ch.getDescription(configuration, returnTag), false)));
270        return result;
271    }
272
273    /**
274     * {@inheritDoc}
275     */
276    public Content seeTagOutput(Element holder, List<? extends DocTree> seeTags) {
277        ContentBuilder body = new ContentBuilder();
278        if (!seeTags.isEmpty()) {
279            for (DocTree dt : seeTags) {
280                appendSeparatorIfNotEmpty(body);
281                body.addContent(htmlWriter.seeTagToContent(holder, dt));
282            }
283        }
284        if (utils.isVariableElement(holder) && ((VariableElement)holder).getConstantValue() != null &&
285                htmlWriter instanceof ClassWriterImpl) {
286            //Automatically add link to constant values page for constant fields.
287            appendSeparatorIfNotEmpty(body);
288            DocPath constantsPath =
289                    htmlWriter.pathToRoot.resolve(DocPaths.CONSTANT_VALUES);
290            String whichConstant =
291                    ((ClassWriterImpl) htmlWriter).getTypeElement().getQualifiedName() + "." +
292                    utils.getSimpleName(holder);
293            DocLink link = constantsPath.fragment(whichConstant);
294            body.addContent(htmlWriter.getHyperLink(link,
295                    new StringContent(configuration.getText("doclet.Constants_Summary"))));
296        }
297        if (utils.isClass(holder) && utils.isSerializable((TypeElement)holder)) {
298            //Automatically add link to serialized form page for serializable classes.
299            if (SerializedFormBuilder.serialInclude(utils, holder) &&
300                      SerializedFormBuilder.serialInclude(utils, utils.containingPackage(holder))) {
301                appendSeparatorIfNotEmpty(body);
302                DocPath serialPath = htmlWriter.pathToRoot.resolve(DocPaths.SERIALIZED_FORM);
303                DocLink link = serialPath.fragment(utils.getFullyQualifiedName(holder));
304                body.addContent(htmlWriter.getHyperLink(link,
305                        new StringContent(configuration.getText("doclet.Serialized_Form"))));
306            }
307        }
308        if (body.isEmpty())
309            return body;
310
311        ContentBuilder result = new ContentBuilder();
312        result.addContent(HtmlTree.DT(HtmlTree.SPAN(HtmlStyle.seeLabel,
313                new StringContent(configuration.getText("doclet.See_Also")))));
314        result.addContent(HtmlTree.DD(body));
315        return result;
316
317    }
318
319    private void appendSeparatorIfNotEmpty(ContentBuilder body) {
320        if (!body.isEmpty()) {
321            body.addContent(", ");
322            body.addContent(DocletConstants.NL);
323        }
324    }
325
326    /**
327     * {@inheritDoc}
328     */
329    public Content simpleTagOutput(Element element, List<? extends DocTree> simpleTags, String header) {
330        CommentHelper ch = utils.getCommentHelper(element);
331        ContentBuilder result = new ContentBuilder();
332        result.addContent(HtmlTree.DT(HtmlTree.SPAN(HtmlStyle.simpleTagLabel, new RawHtml(header))));
333        ContentBuilder body = new ContentBuilder();
334        boolean many = false;
335        for (DocTree simpleTag : simpleTags) {
336            if (many) {
337                body.addContent(", ");
338            }
339            List<? extends DocTree> bodyTags = ch.getBody(configuration, simpleTag);
340            body.addContent(htmlWriter.commentTagsToContent(simpleTag, element, bodyTags, false));
341            many = true;
342        }
343        result.addContent(HtmlTree.DD(body));
344        return result;
345    }
346
347    /**
348     * {@inheritDoc}
349     */
350    public Content simpleTagOutput(Element element, DocTree simpleTag, String header) {
351        ContentBuilder result = new ContentBuilder();
352        result.addContent(HtmlTree.DT(HtmlTree.SPAN(HtmlStyle.simpleTagLabel, new RawHtml(header))));
353        CommentHelper ch = utils.getCommentHelper(element);
354        List<? extends DocTree> description = ch.getDescription(configuration, simpleTag);
355        Content body = htmlWriter.commentTagsToContent(simpleTag, element, description, false);
356        result.addContent(HtmlTree.DD(body));
357        return result;
358    }
359
360    /**
361     * {@inheritDoc}
362     */
363    public Content getThrowsHeader() {
364        HtmlTree result = HtmlTree.DT(HtmlTree.SPAN(HtmlStyle.throwsLabel,
365                new StringContent(configuration.getText("doclet.Throws"))));
366        return result;
367    }
368
369    /**
370     * {@inheritDoc}
371     */
372    public Content throwsTagOutput(Element element, DocTree throwsTag) {
373        ContentBuilder body = new ContentBuilder();
374        CommentHelper ch = utils.getCommentHelper(element);
375        Element exception = ch.getException(configuration, throwsTag);
376        Content excName;
377        if (exception == null) {
378            excName = new RawHtml(ch.getExceptionName(throwsTag).toString());
379        } else if (exception.asType() == null) {
380            excName = new RawHtml(utils.getFullyQualifiedName(exception));
381        } else {
382            LinkInfoImpl link = new LinkInfoImpl(configuration, LinkInfoImpl.Kind.MEMBER,
383                                                 exception.asType());
384            link.excludeTypeBounds = true;
385            excName = htmlWriter.getLink(link);
386        }
387        body.addContent(HtmlTree.CODE(excName));
388        List<? extends DocTree> description = ch.getDescription(configuration, throwsTag);
389        Content desc = htmlWriter.commentTagsToContent(throwsTag, element, description, false);
390        if (desc != null && !desc.isEmpty()) {
391            body.addContent(" - ");
392            body.addContent(desc);
393        }
394        HtmlTree result = HtmlTree.DD(body);
395        return result;
396    }
397
398    /**
399     * {@inheritDoc}
400     */
401    public Content throwsTagOutput(TypeMirror throwsType) {
402        HtmlTree result = HtmlTree.DD(HtmlTree.CODE(htmlWriter.getLink(
403                new LinkInfoImpl(configuration, LinkInfoImpl.Kind.MEMBER, throwsType))));
404        return result;
405    }
406
407    /**
408     * {@inheritDoc}
409     */
410    public Content valueTagOutput(VariableElement field, String constantVal, boolean includeLink) {
411        return includeLink ?
412            htmlWriter.getDocLink(LinkInfoImpl.Kind.VALUE_TAG, field,
413                constantVal, false) : new RawHtml(constantVal);
414    }
415
416    /**
417     * {@inheritDoc}
418     */
419    public Content commentTagsToOutput(DocTree holderTag, List<? extends DocTree> tags) {
420        return commentTagsToOutput(holderTag, null, tags, false);
421    }
422
423    /**
424     * {@inheritDoc}
425     */
426    public Content commentTagsToOutput(Element holder, List<? extends DocTree> tags) {
427        return commentTagsToOutput(null, holder, tags, false);
428    }
429
430    /**
431     * {@inheritDoc}
432     */
433    public Content commentTagsToOutput(DocTree holderTag,
434        Element holder, List<? extends DocTree> tags, boolean isFirstSentence) {
435        return htmlWriter.commentTagsToContent(holderTag, holder,
436                tags, isFirstSentence);
437    }
438
439    /**
440     * {@inheritDoc}
441     */
442    public Configuration configuration() {
443        return configuration;
444    }
445}
446