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