1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/src/share/classes/com/sun/tools/doclets/formats/html/markup/HtmlWriter.java Wed Apr 27 01:34:52 2016 +0800 1.3 @@ -0,0 +1,535 @@ 1.4 +/* 1.5 + * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. 1.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 1.7 + * 1.8 + * This code is free software; you can redistribute it and/or modify it 1.9 + * under the terms of the GNU General Public License version 2 only, as 1.10 + * published by the Free Software Foundation. Oracle designates this 1.11 + * particular file as subject to the "Classpath" exception as provided 1.12 + * by Oracle in the LICENSE file that accompanied this code. 1.13 + * 1.14 + * This code is distributed in the hope that it will be useful, but WITHOUT 1.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 1.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 1.17 + * version 2 for more details (a copy is included in the LICENSE file that 1.18 + * accompanied this code). 1.19 + * 1.20 + * You should have received a copy of the GNU General Public License version 1.21 + * 2 along with this work; if not, write to the Free Software Foundation, 1.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 1.23 + * 1.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 1.25 + * or visit www.oracle.com if you need additional information or have any 1.26 + * questions. 1.27 + */ 1.28 + 1.29 +package com.sun.tools.doclets.formats.html.markup; 1.30 + 1.31 +import java.io.*; 1.32 +import java.util.*; 1.33 +import java.util.regex.Matcher; 1.34 +import java.util.regex.Pattern; 1.35 + 1.36 +import com.sun.tools.doclets.internal.toolkit.*; 1.37 +import com.sun.tools.doclets.internal.toolkit.util.*; 1.38 + 1.39 +/** 1.40 + * Class for the Html format code generation. 1.41 + * Initializes PrintWriter with FileWriter, to enable print 1.42 + * related methods to generate the code to the named File through FileWriter. 1.43 + * 1.44 + * <p><b>This is NOT part of any supported API. 1.45 + * If you write code that depends on this, you do so at your own risk. 1.46 + * This code and its internal interfaces are subject to change or 1.47 + * deletion without notice.</b> 1.48 + * 1.49 + * @since 1.2 1.50 + * @author Atul M Dambalkar 1.51 + * @author Bhavesh Patel (Modified) 1.52 + */ 1.53 +public class HtmlWriter { 1.54 + 1.55 + /** 1.56 + * The window title of this file 1.57 + */ 1.58 + protected String winTitle; 1.59 + 1.60 + /** 1.61 + * The configuration 1.62 + */ 1.63 + protected Configuration configuration; 1.64 + 1.65 + /** 1.66 + * The flag to indicate whether a member details list is printed or not. 1.67 + */ 1.68 + protected boolean memberDetailsListPrinted; 1.69 + 1.70 + /** 1.71 + * Header for table displaying profiles and description.. 1.72 + */ 1.73 + protected final String[] profileTableHeader; 1.74 + 1.75 + /** 1.76 + * Header for tables displaying packages and description.. 1.77 + */ 1.78 + protected final String[] packageTableHeader; 1.79 + 1.80 + /** 1.81 + * Summary for use tables displaying class and package use. 1.82 + */ 1.83 + protected final String useTableSummary; 1.84 + 1.85 + /** 1.86 + * Column header for class docs displaying Modifier and Type header. 1.87 + */ 1.88 + protected final String modifierTypeHeader; 1.89 + 1.90 + public final Content overviewLabel; 1.91 + 1.92 + public final Content defaultPackageLabel; 1.93 + 1.94 + public final Content packageLabel; 1.95 + 1.96 + public final Content profileLabel; 1.97 + 1.98 + public final Content useLabel; 1.99 + 1.100 + public final Content prevLabel; 1.101 + 1.102 + public final Content nextLabel; 1.103 + 1.104 + public final Content prevclassLabel; 1.105 + 1.106 + public final Content nextclassLabel; 1.107 + 1.108 + public final Content summaryLabel; 1.109 + 1.110 + public final Content detailLabel; 1.111 + 1.112 + public final Content framesLabel; 1.113 + 1.114 + public final Content noframesLabel; 1.115 + 1.116 + public final Content treeLabel; 1.117 + 1.118 + public final Content classLabel; 1.119 + 1.120 + public final Content deprecatedLabel; 1.121 + 1.122 + public final Content deprecatedPhrase; 1.123 + 1.124 + public final Content allclassesLabel; 1.125 + 1.126 + public final Content allpackagesLabel; 1.127 + 1.128 + public final Content allprofilesLabel; 1.129 + 1.130 + public final Content indexLabel; 1.131 + 1.132 + public final Content helpLabel; 1.133 + 1.134 + public final Content seeLabel; 1.135 + 1.136 + public final Content descriptionLabel; 1.137 + 1.138 + public final Content prevpackageLabel; 1.139 + 1.140 + public final Content nextpackageLabel; 1.141 + 1.142 + public final Content prevprofileLabel; 1.143 + 1.144 + public final Content nextprofileLabel; 1.145 + 1.146 + public final Content packagesLabel; 1.147 + 1.148 + public final Content profilesLabel; 1.149 + 1.150 + public final Content methodDetailsLabel; 1.151 + 1.152 + public final Content annotationTypeDetailsLabel; 1.153 + 1.154 + public final Content fieldDetailsLabel; 1.155 + 1.156 + public final Content propertyDetailsLabel; 1.157 + 1.158 + public final Content constructorDetailsLabel; 1.159 + 1.160 + public final Content enumConstantsDetailsLabel; 1.161 + 1.162 + public final Content specifiedByLabel; 1.163 + 1.164 + public final Content overridesLabel; 1.165 + 1.166 + public final Content descfrmClassLabel; 1.167 + 1.168 + public final Content descfrmInterfaceLabel; 1.169 + 1.170 + private final Writer writer; 1.171 + 1.172 + private Content script; 1.173 + 1.174 + /** 1.175 + * Constructor. 1.176 + * 1.177 + * @param path The directory path to be created for this file 1.178 + * or null if none to be created. 1.179 + * @exception IOException Exception raised by the FileWriter is passed on 1.180 + * to next level. 1.181 + * @exception UnsupportedEncodingException Exception raised by the 1.182 + * OutputStreamWriter is passed on to next level. 1.183 + */ 1.184 + public HtmlWriter(Configuration configuration, DocPath path) 1.185 + throws IOException, UnsupportedEncodingException { 1.186 + writer = DocFile.createFileForOutput(configuration, path).openWriter(); 1.187 + this.configuration = configuration; 1.188 + this.memberDetailsListPrinted = false; 1.189 + profileTableHeader = new String[] { 1.190 + configuration.getText("doclet.Profile"), 1.191 + configuration.getText("doclet.Description") 1.192 + }; 1.193 + packageTableHeader = new String[] { 1.194 + configuration.getText("doclet.Package"), 1.195 + configuration.getText("doclet.Description") 1.196 + }; 1.197 + useTableSummary = configuration.getText("doclet.Use_Table_Summary", 1.198 + configuration.getText("doclet.packages")); 1.199 + modifierTypeHeader = configuration.getText("doclet.0_and_1", 1.200 + configuration.getText("doclet.Modifier"), 1.201 + configuration.getText("doclet.Type")); 1.202 + overviewLabel = getResource("doclet.Overview"); 1.203 + defaultPackageLabel = new StringContent(DocletConstants.DEFAULT_PACKAGE_NAME); 1.204 + packageLabel = getResource("doclet.Package"); 1.205 + profileLabel = getResource("doclet.Profile"); 1.206 + useLabel = getResource("doclet.navClassUse"); 1.207 + prevLabel = getResource("doclet.Prev"); 1.208 + nextLabel = getResource("doclet.Next"); 1.209 + prevclassLabel = getNonBreakResource("doclet.Prev_Class"); 1.210 + nextclassLabel = getNonBreakResource("doclet.Next_Class"); 1.211 + summaryLabel = getResource("doclet.Summary"); 1.212 + detailLabel = getResource("doclet.Detail"); 1.213 + framesLabel = getResource("doclet.Frames"); 1.214 + noframesLabel = getNonBreakResource("doclet.No_Frames"); 1.215 + treeLabel = getResource("doclet.Tree"); 1.216 + classLabel = getResource("doclet.Class"); 1.217 + deprecatedLabel = getResource("doclet.navDeprecated"); 1.218 + deprecatedPhrase = getResource("doclet.Deprecated"); 1.219 + allclassesLabel = getNonBreakResource("doclet.All_Classes"); 1.220 + allpackagesLabel = getNonBreakResource("doclet.All_Packages"); 1.221 + allprofilesLabel = getNonBreakResource("doclet.All_Profiles"); 1.222 + indexLabel = getResource("doclet.Index"); 1.223 + helpLabel = getResource("doclet.Help"); 1.224 + seeLabel = getResource("doclet.See"); 1.225 + descriptionLabel = getResource("doclet.Description"); 1.226 + prevpackageLabel = getNonBreakResource("doclet.Prev_Package"); 1.227 + nextpackageLabel = getNonBreakResource("doclet.Next_Package"); 1.228 + prevprofileLabel = getNonBreakResource("doclet.Prev_Profile"); 1.229 + nextprofileLabel = getNonBreakResource("doclet.Next_Profile"); 1.230 + packagesLabel = getResource("doclet.Packages"); 1.231 + profilesLabel = getResource("doclet.Profiles"); 1.232 + methodDetailsLabel = getResource("doclet.Method_Detail"); 1.233 + annotationTypeDetailsLabel = getResource("doclet.Annotation_Type_Member_Detail"); 1.234 + fieldDetailsLabel = getResource("doclet.Field_Detail"); 1.235 + propertyDetailsLabel = getResource("doclet.Property_Detail"); 1.236 + constructorDetailsLabel = getResource("doclet.Constructor_Detail"); 1.237 + enumConstantsDetailsLabel = getResource("doclet.Enum_Constant_Detail"); 1.238 + specifiedByLabel = getResource("doclet.Specified_By"); 1.239 + overridesLabel = getResource("doclet.Overrides"); 1.240 + descfrmClassLabel = getResource("doclet.Description_From_Class"); 1.241 + descfrmInterfaceLabel = getResource("doclet.Description_From_Interface"); 1.242 + } 1.243 + 1.244 + public void write(Content c) throws IOException { 1.245 + c.write(writer, true); 1.246 + } 1.247 + 1.248 + public void close() throws IOException { 1.249 + writer.close(); 1.250 + } 1.251 + 1.252 + /** 1.253 + * Get the configuration string as a content. 1.254 + * 1.255 + * @param key the key to look for in the configuration file 1.256 + * @return a content tree for the text 1.257 + */ 1.258 + public Content getResource(String key) { 1.259 + return configuration.getResource(key); 1.260 + } 1.261 + 1.262 + /** 1.263 + * Get the configuration string as a content, replacing spaces 1.264 + * with non-breaking spaces. 1.265 + * 1.266 + * @param key the key to look for in the configuration file 1.267 + * @return a content tree for the text 1.268 + */ 1.269 + public Content getNonBreakResource(String key) { 1.270 + String text = configuration.getText(key); 1.271 + Content c = configuration.newContent(); 1.272 + int start = 0; 1.273 + int p; 1.274 + while ((p = text.indexOf(" ", start)) != -1) { 1.275 + c.addContent(text.substring(start, p)); 1.276 + c.addContent(RawHtml.nbsp); 1.277 + start = p + 1; 1.278 + } 1.279 + c.addContent(text.substring(start)); 1.280 + return c; 1.281 + } 1.282 + 1.283 + /** 1.284 + * Get the configuration string as a content. 1.285 + * 1.286 + * @param key the key to look for in the configuration file 1.287 + * @param o string or content argument added to configuration text 1.288 + * @return a content tree for the text 1.289 + */ 1.290 + public Content getResource(String key, Object o) { 1.291 + return configuration.getResource(key, o); 1.292 + } 1.293 + 1.294 + /** 1.295 + * Get the configuration string as a content. 1.296 + * 1.297 + * @param key the key to look for in the configuration file 1.298 + * @param o1 string or content argument added to configuration text 1.299 + * @param o2 string or content argument added to configuration text 1.300 + * @return a content tree for the text 1.301 + */ 1.302 + public Content getResource(String key, Object o0, Object o1) { 1.303 + return configuration.getResource(key, o0, o1); 1.304 + } 1.305 + 1.306 + /** 1.307 + * Returns an HtmlTree for the SCRIPT tag. 1.308 + * 1.309 + * @return an HtmlTree for the SCRIPT tag 1.310 + */ 1.311 + protected HtmlTree getWinTitleScript(){ 1.312 + HtmlTree script = new HtmlTree(HtmlTag.SCRIPT); 1.313 + if(winTitle != null && winTitle.length() > 0) { 1.314 + script.addAttr(HtmlAttr.TYPE, "text/javascript"); 1.315 + String scriptCode = "<!--" + DocletConstants.NL + 1.316 + " try {" + DocletConstants.NL + 1.317 + " if (location.href.indexOf('is-external=true') == -1) {" + DocletConstants.NL + 1.318 + " parent.document.title=\"" + escapeJavaScriptChars(winTitle) + "\";" + DocletConstants.NL + 1.319 + " }" + DocletConstants.NL + 1.320 + " }" + DocletConstants.NL + 1.321 + " catch(err) {" + DocletConstants.NL + 1.322 + " }" + DocletConstants.NL + 1.323 + "//-->" + DocletConstants.NL; 1.324 + RawHtml scriptContent = new RawHtml(scriptCode); 1.325 + script.addContent(scriptContent); 1.326 + } 1.327 + return script; 1.328 + } 1.329 + 1.330 + /** 1.331 + * Returns a String with escaped special JavaScript characters. 1.332 + * 1.333 + * @param s String that needs to be escaped 1.334 + * @return a valid escaped JavaScript string 1.335 + */ 1.336 + private static String escapeJavaScriptChars(String s) { 1.337 + StringBuilder sb = new StringBuilder(); 1.338 + for (int i = 0; i < s.length(); i++) { 1.339 + char ch = s.charAt(i); 1.340 + switch (ch) { 1.341 + case '\b': 1.342 + sb.append("\\b"); 1.343 + break; 1.344 + case '\t': 1.345 + sb.append("\\t"); 1.346 + break; 1.347 + case '\n': 1.348 + sb.append("\\n"); 1.349 + break; 1.350 + case '\f': 1.351 + sb.append("\\f"); 1.352 + break; 1.353 + case '\r': 1.354 + sb.append("\\r"); 1.355 + break; 1.356 + case '"': 1.357 + sb.append("\\\""); 1.358 + break; 1.359 + case '\'': 1.360 + sb.append("\\\'"); 1.361 + break; 1.362 + case '\\': 1.363 + sb.append("\\\\"); 1.364 + break; 1.365 + default: 1.366 + if (ch < 32 || ch >= 127) { 1.367 + sb.append(String.format("\\u%04X", (int)ch)); 1.368 + } else { 1.369 + sb.append(ch); 1.370 + } 1.371 + break; 1.372 + } 1.373 + } 1.374 + return sb.toString(); 1.375 + } 1.376 + 1.377 + /** 1.378 + * Returns a content tree for the SCRIPT tag for the main page(index.html). 1.379 + * 1.380 + * @return a content for the SCRIPT tag 1.381 + */ 1.382 + protected Content getFramesetJavaScript() { 1.383 + HtmlTree script = new HtmlTree(HtmlTag.SCRIPT); 1.384 + script.addAttr(HtmlAttr.TYPE, "text/javascript"); 1.385 + String scriptCode = DocletConstants.NL + 1.386 + " targetPage = \"\" + window.location.search;" + DocletConstants.NL + 1.387 + " if (targetPage != \"\" && targetPage != \"undefined\")" + DocletConstants.NL + 1.388 + " targetPage = targetPage.substring(1);" + DocletConstants.NL + 1.389 + " if (targetPage.indexOf(\":\") != -1 || (targetPage != \"\" && !validURL(targetPage)))" + DocletConstants.NL + 1.390 + " targetPage = \"undefined\";" + DocletConstants.NL + 1.391 + " function validURL(url) {" + DocletConstants.NL + 1.392 + " try {" + DocletConstants.NL + 1.393 + " url = decodeURIComponent(url);" + DocletConstants.NL + 1.394 + " }" + DocletConstants.NL + 1.395 + " catch (error) {" + DocletConstants.NL + 1.396 + " return false;" + DocletConstants.NL + 1.397 + " }" + DocletConstants.NL + 1.398 + " var pos = url.indexOf(\".html\");" + DocletConstants.NL + 1.399 + " if (pos == -1 || pos != url.length - 5)" + DocletConstants.NL + 1.400 + " return false;" + DocletConstants.NL + 1.401 + " var allowNumber = false;" + DocletConstants.NL + 1.402 + " var allowSep = false;" + DocletConstants.NL + 1.403 + " var seenDot = false;" + DocletConstants.NL + 1.404 + " for (var i = 0; i < url.length - 5; i++) {" + DocletConstants.NL + 1.405 + " var ch = url.charAt(i);" + DocletConstants.NL + 1.406 + " if ('a' <= ch && ch <= 'z' ||" + DocletConstants.NL + 1.407 + " 'A' <= ch && ch <= 'Z' ||" + DocletConstants.NL + 1.408 + " ch == '$' ||" + DocletConstants.NL + 1.409 + " ch == '_' ||" + DocletConstants.NL + 1.410 + " ch.charCodeAt(0) > 127) {" + DocletConstants.NL + 1.411 + " allowNumber = true;" + DocletConstants.NL + 1.412 + " allowSep = true;" + DocletConstants.NL + 1.413 + " } else if ('0' <= ch && ch <= '9'" + DocletConstants.NL + 1.414 + " || ch == '-') {" + DocletConstants.NL + 1.415 + " if (!allowNumber)" + DocletConstants.NL + 1.416 + " return false;" + DocletConstants.NL + 1.417 + " } else if (ch == '/' || ch == '.') {" + DocletConstants.NL + 1.418 + " if (!allowSep)" + DocletConstants.NL + 1.419 + " return false;" + DocletConstants.NL + 1.420 + " allowNumber = false;" + DocletConstants.NL + 1.421 + " allowSep = false;" + DocletConstants.NL + 1.422 + " if (ch == '.')" + DocletConstants.NL + 1.423 + " seenDot = true;" + DocletConstants.NL + 1.424 + " if (ch == '/' && seenDot)" + DocletConstants.NL + 1.425 + " return false;" + DocletConstants.NL + 1.426 + " } else {" + DocletConstants.NL + 1.427 + " return false;"+ DocletConstants.NL + 1.428 + " }" + DocletConstants.NL + 1.429 + " }" + DocletConstants.NL + 1.430 + " return true;" + DocletConstants.NL + 1.431 + " }" + DocletConstants.NL + 1.432 + " function loadFrames() {" + DocletConstants.NL + 1.433 + " if (targetPage != \"\" && targetPage != \"undefined\")" + DocletConstants.NL + 1.434 + " top.classFrame.location = top.targetPage;" + DocletConstants.NL + 1.435 + " }" + DocletConstants.NL; 1.436 + RawHtml scriptContent = new RawHtml(scriptCode); 1.437 + script.addContent(scriptContent); 1.438 + return script; 1.439 + } 1.440 + 1.441 + /** 1.442 + * Returns an HtmlTree for the BODY tag. 1.443 + * 1.444 + * @param includeScript set true if printing windowtitle script 1.445 + * @param title title for the window 1.446 + * @return an HtmlTree for the BODY tag 1.447 + */ 1.448 + public HtmlTree getBody(boolean includeScript, String title) { 1.449 + HtmlTree body = new HtmlTree(HtmlTag.BODY); 1.450 + // Set window title string which is later printed 1.451 + this.winTitle = title; 1.452 + // Don't print windowtitle script for overview-frame, allclasses-frame 1.453 + // and package-frame 1.454 + if (includeScript) { 1.455 + this.script = getWinTitleScript(); 1.456 + body.addContent(script); 1.457 + Content noScript = HtmlTree.NOSCRIPT( 1.458 + HtmlTree.DIV(getResource("doclet.No_Script_Message"))); 1.459 + body.addContent(noScript); 1.460 + } 1.461 + return body; 1.462 + } 1.463 + 1.464 + /** 1.465 + * Generated javascript variables for the document. 1.466 + * 1.467 + * @param typeMap map comprising of method and type relationship 1.468 + * @param methodTypes set comprising of all methods types for this class 1.469 + */ 1.470 + public void generateMethodTypesScript(Map<String,Integer> typeMap, 1.471 + Set<MethodTypes> methodTypes) { 1.472 + String sep = ""; 1.473 + StringBuilder vars = new StringBuilder("var methods = {"); 1.474 + for (Map.Entry<String,Integer> entry : typeMap.entrySet()) { 1.475 + vars.append(sep); 1.476 + sep = ","; 1.477 + vars.append("\""); 1.478 + vars.append(entry.getKey()); 1.479 + vars.append("\":"); 1.480 + vars.append(entry.getValue()); 1.481 + } 1.482 + vars.append("};").append(DocletConstants.NL); 1.483 + sep = ""; 1.484 + vars.append("var tabs = {"); 1.485 + for (MethodTypes entry : methodTypes) { 1.486 + vars.append(sep); 1.487 + sep = ","; 1.488 + vars.append(entry.value()).append(":"); 1.489 + vars.append("[").append("\"").append(entry.tabId()); 1.490 + vars.append("\"").append(sep).append("\"").append(entry.text()).append("\"]"); 1.491 + } 1.492 + vars.append("};").append(DocletConstants.NL); 1.493 + addStyles(HtmlStyle.altColor, vars); 1.494 + addStyles(HtmlStyle.rowColor, vars); 1.495 + addStyles(HtmlStyle.tableTab, vars); 1.496 + addStyles(HtmlStyle.activeTableTab, vars); 1.497 + script.addContent(new RawHtml(vars.toString())); 1.498 + } 1.499 + 1.500 + /** 1.501 + * Adds javascript style variables to the document. 1.502 + * 1.503 + * @param style style to be added as a javascript variable 1.504 + * @param vars variable string to which the style variable will be added 1.505 + */ 1.506 + public void addStyles(HtmlStyle style, StringBuilder vars) { 1.507 + vars.append("var ").append(style).append(" = \"").append(style) 1.508 + .append("\";").append(DocletConstants.NL); 1.509 + } 1.510 + 1.511 + /** 1.512 + * Returns an HtmlTree for the TITLE tag. 1.513 + * 1.514 + * @return an HtmlTree for the TITLE tag 1.515 + */ 1.516 + public HtmlTree getTitle() { 1.517 + HtmlTree title = HtmlTree.TITLE(new StringContent(winTitle)); 1.518 + return title; 1.519 + } 1.520 + 1.521 + public String codeText(String text) { 1.522 + return "<code>" + text + "</code>"; 1.523 + } 1.524 + 1.525 + /** 1.526 + * Return "&nbsp;", non-breaking space. 1.527 + */ 1.528 + public Content getSpace() { 1.529 + return RawHtml.nbsp; 1.530 + } 1.531 + 1.532 + /* 1.533 + * Returns a header for Modifier and Type column of a table. 1.534 + */ 1.535 + public String getModifierTypeHeader() { 1.536 + return modifierTypeHeader; 1.537 + } 1.538 +}