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