src/share/classes/com/sun/tools/doclets/formats/html/HtmlDocletWriter.java

Thu, 31 Aug 2017 15:17:03 +0800

author
aoqi
date
Thu, 31 Aug 2017 15:17:03 +0800
changeset 2525
2eb010b6cb22
parent 2415
7ceaee0e497b
parent 0
959103a6100f
child 3932
b8a6df910f59
permissions
-rw-r--r--

merge

aoqi@0 1 /*
aoqi@0 2 * Copyright (c) 1998, 2013, Oracle and/or its affiliates. All rights reserved.
aoqi@0 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
aoqi@0 4 *
aoqi@0 5 * This code is free software; you can redistribute it and/or modify it
aoqi@0 6 * under the terms of the GNU General Public License version 2 only, as
aoqi@0 7 * published by the Free Software Foundation. Oracle designates this
aoqi@0 8 * particular file as subject to the "Classpath" exception as provided
aoqi@0 9 * by Oracle in the LICENSE file that accompanied this code.
aoqi@0 10 *
aoqi@0 11 * This code is distributed in the hope that it will be useful, but WITHOUT
aoqi@0 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
aoqi@0 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
aoqi@0 14 * version 2 for more details (a copy is included in the LICENSE file that
aoqi@0 15 * accompanied this code).
aoqi@0 16 *
aoqi@0 17 * You should have received a copy of the GNU General Public License version
aoqi@0 18 * 2 along with this work; if not, write to the Free Software Foundation,
aoqi@0 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
aoqi@0 20 *
aoqi@0 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
aoqi@0 22 * or visit www.oracle.com if you need additional information or have any
aoqi@0 23 * questions.
aoqi@0 24 */
aoqi@0 25
aoqi@0 26 package com.sun.tools.doclets.formats.html;
aoqi@0 27
aoqi@0 28 import java.io.*;
aoqi@0 29 import java.text.SimpleDateFormat;
aoqi@0 30 import java.util.*;
aoqi@0 31 import java.util.regex.Matcher;
aoqi@0 32 import java.util.regex.Pattern;
aoqi@0 33
aoqi@0 34 import com.sun.javadoc.*;
aoqi@0 35 import com.sun.tools.doclets.formats.html.markup.*;
aoqi@0 36 import com.sun.tools.doclets.internal.toolkit.*;
aoqi@0 37 import com.sun.tools.doclets.internal.toolkit.taglets.*;
aoqi@0 38 import com.sun.tools.doclets.internal.toolkit.util.*;
aoqi@0 39 import com.sun.tools.javac.util.StringUtils;
aoqi@0 40
aoqi@0 41 /**
aoqi@0 42 * Class for the Html Format Code Generation specific to JavaDoc.
aoqi@0 43 * This Class contains methods related to the Html Code Generation which
aoqi@0 44 * are used extensively while generating the entire documentation.
aoqi@0 45 *
aoqi@0 46 * <p><b>This is NOT part of any supported API.
aoqi@0 47 * If you write code that depends on this, you do so at your own risk.
aoqi@0 48 * This code and its internal interfaces are subject to change or
aoqi@0 49 * deletion without notice.</b>
aoqi@0 50 *
aoqi@0 51 * @since 1.2
aoqi@0 52 * @author Atul M Dambalkar
aoqi@0 53 * @author Robert Field
aoqi@0 54 * @author Bhavesh Patel (Modified)
aoqi@0 55 */
aoqi@0 56 public class HtmlDocletWriter extends HtmlDocWriter {
aoqi@0 57
aoqi@0 58 /**
aoqi@0 59 * Relative path from the file getting generated to the destination
aoqi@0 60 * directory. For example, if the file getting generated is
aoqi@0 61 * "java/lang/Object.html", then the path to the root is "../..".
aoqi@0 62 * This string can be empty if the file getting generated is in
aoqi@0 63 * the destination directory.
aoqi@0 64 */
aoqi@0 65 public final DocPath pathToRoot;
aoqi@0 66
aoqi@0 67 /**
aoqi@0 68 * Platform-independent path from the current or the
aoqi@0 69 * destination directory to the file getting generated.
aoqi@0 70 * Used when creating the file.
aoqi@0 71 */
aoqi@0 72 public final DocPath path;
aoqi@0 73
aoqi@0 74 /**
aoqi@0 75 * Name of the file getting generated. If the file getting generated is
aoqi@0 76 * "java/lang/Object.html", then the filename is "Object.html".
aoqi@0 77 */
aoqi@0 78 public final DocPath filename;
aoqi@0 79
aoqi@0 80 /**
aoqi@0 81 * The global configuration information for this run.
aoqi@0 82 */
aoqi@0 83 public final ConfigurationImpl configuration;
aoqi@0 84
aoqi@0 85 /**
aoqi@0 86 * To check whether annotation heading is printed or not.
aoqi@0 87 */
aoqi@0 88 protected boolean printedAnnotationHeading = false;
aoqi@0 89
aoqi@0 90 /**
aoqi@0 91 * To check whether annotation field heading is printed or not.
aoqi@0 92 */
aoqi@0 93 protected boolean printedAnnotationFieldHeading = false;
aoqi@0 94
aoqi@0 95 /**
aoqi@0 96 * To check whether the repeated annotations is documented or not.
aoqi@0 97 */
aoqi@0 98 private boolean isAnnotationDocumented = false;
aoqi@0 99
aoqi@0 100 /**
aoqi@0 101 * To check whether the container annotations is documented or not.
aoqi@0 102 */
aoqi@0 103 private boolean isContainerDocumented = false;
aoqi@0 104
aoqi@0 105 /**
aoqi@0 106 * Constructor to construct the HtmlStandardWriter object.
aoqi@0 107 *
aoqi@0 108 * @param path File to be generated.
aoqi@0 109 */
aoqi@0 110 public HtmlDocletWriter(ConfigurationImpl configuration, DocPath path)
aoqi@0 111 throws IOException {
aoqi@0 112 super(configuration, path);
aoqi@0 113 this.configuration = configuration;
aoqi@0 114 this.path = path;
aoqi@0 115 this.pathToRoot = path.parent().invert();
aoqi@0 116 this.filename = path.basename();
aoqi@0 117 }
aoqi@0 118
aoqi@0 119 /**
aoqi@0 120 * Replace {&#064;docRoot} tag used in options that accept HTML text, such
aoqi@0 121 * as -header, -footer, -top and -bottom, and when converting a relative
aoqi@0 122 * HREF where commentTagsToString inserts a {&#064;docRoot} where one was
aoqi@0 123 * missing. (Also see DocRootTaglet for {&#064;docRoot} tags in doc
aoqi@0 124 * comments.)
aoqi@0 125 * <p>
aoqi@0 126 * Replace {&#064;docRoot} tag in htmlstr with the relative path to the
aoqi@0 127 * destination directory from the directory where the file is being
aoqi@0 128 * written, looping to handle all such tags in htmlstr.
aoqi@0 129 * <p>
aoqi@0 130 * For example, for "-d docs" and -header containing {&#064;docRoot}, when
aoqi@0 131 * the HTML page for source file p/C1.java is being generated, the
aoqi@0 132 * {&#064;docRoot} tag would be inserted into the header as "../",
aoqi@0 133 * the relative path from docs/p/ to docs/ (the document root).
aoqi@0 134 * <p>
aoqi@0 135 * Note: This doc comment was written with '&amp;#064;' representing '@'
aoqi@0 136 * to prevent the inline tag from being interpreted.
aoqi@0 137 */
aoqi@0 138 public String replaceDocRootDir(String htmlstr) {
aoqi@0 139 // Return if no inline tags exist
aoqi@0 140 int index = htmlstr.indexOf("{@");
aoqi@0 141 if (index < 0) {
aoqi@0 142 return htmlstr;
aoqi@0 143 }
aoqi@0 144 Matcher docrootMatcher = docrootPattern.matcher(htmlstr);
aoqi@0 145 if (!docrootMatcher.find()) {
aoqi@0 146 return htmlstr;
aoqi@0 147 }
aoqi@0 148 StringBuilder buf = new StringBuilder();
aoqi@0 149 int prevEnd = 0;
aoqi@0 150 do {
aoqi@0 151 int match = docrootMatcher.start();
aoqi@0 152 // append htmlstr up to start of next {@docroot}
aoqi@0 153 buf.append(htmlstr.substring(prevEnd, match));
aoqi@0 154 prevEnd = docrootMatcher.end();
aoqi@0 155 if (configuration.docrootparent.length() > 0 && htmlstr.startsWith("/..", prevEnd)) {
aoqi@0 156 // Insert the absolute link if {@docRoot} is followed by "/..".
aoqi@0 157 buf.append(configuration.docrootparent);
aoqi@0 158 prevEnd += 3;
aoqi@0 159 } else {
aoqi@0 160 // Insert relative path where {@docRoot} was located
aoqi@0 161 buf.append(pathToRoot.isEmpty() ? "." : pathToRoot.getPath());
aoqi@0 162 }
aoqi@0 163 // Append slash if next character is not a slash
aoqi@0 164 if (prevEnd < htmlstr.length() && htmlstr.charAt(prevEnd) != '/') {
aoqi@0 165 buf.append('/');
aoqi@0 166 }
aoqi@0 167 } while (docrootMatcher.find());
aoqi@0 168 buf.append(htmlstr.substring(prevEnd));
aoqi@0 169 return buf.toString();
aoqi@0 170 }
aoqi@0 171 //where:
aoqi@0 172 // Note: {@docRoot} is not case sensitive when passed in w/command line option:
aoqi@0 173 private static final Pattern docrootPattern =
aoqi@0 174 Pattern.compile(Pattern.quote("{@docroot}"), Pattern.CASE_INSENSITIVE);
aoqi@0 175
aoqi@0 176 /**
aoqi@0 177 * Get the script to show or hide the All classes link.
aoqi@0 178 *
aoqi@0 179 * @param id id of the element to show or hide
aoqi@0 180 * @return a content tree for the script
aoqi@0 181 */
aoqi@0 182 public Content getAllClassesLinkScript(String id) {
aoqi@0 183 HtmlTree script = new HtmlTree(HtmlTag.SCRIPT);
aoqi@0 184 script.addAttr(HtmlAttr.TYPE, "text/javascript");
aoqi@0 185 String scriptCode = "<!--" + DocletConstants.NL +
aoqi@0 186 " allClassesLink = document.getElementById(\"" + id + "\");" + DocletConstants.NL +
aoqi@0 187 " if(window==top) {" + DocletConstants.NL +
aoqi@0 188 " allClassesLink.style.display = \"block\";" + DocletConstants.NL +
aoqi@0 189 " }" + DocletConstants.NL +
aoqi@0 190 " else {" + DocletConstants.NL +
aoqi@0 191 " allClassesLink.style.display = \"none\";" + DocletConstants.NL +
aoqi@0 192 " }" + DocletConstants.NL +
aoqi@0 193 " //-->" + DocletConstants.NL;
aoqi@0 194 Content scriptContent = new RawHtml(scriptCode);
aoqi@0 195 script.addContent(scriptContent);
aoqi@0 196 Content div = HtmlTree.DIV(script);
aoqi@0 197 return div;
aoqi@0 198 }
aoqi@0 199
aoqi@0 200 /**
aoqi@0 201 * Add method information.
aoqi@0 202 *
aoqi@0 203 * @param method the method to be documented
aoqi@0 204 * @param dl the content tree to which the method information will be added
aoqi@0 205 */
aoqi@0 206 private void addMethodInfo(MethodDoc method, Content dl) {
aoqi@0 207 ClassDoc[] intfacs = method.containingClass().interfaces();
aoqi@0 208 MethodDoc overriddenMethod = method.overriddenMethod();
aoqi@0 209 // Check whether there is any implementation or overridden info to be
aoqi@0 210 // printed. If no overridden or implementation info needs to be
aoqi@0 211 // printed, do not print this section.
aoqi@0 212 if ((intfacs.length > 0 &&
aoqi@0 213 new ImplementedMethods(method, this.configuration).build().length > 0) ||
aoqi@0 214 overriddenMethod != null) {
aoqi@0 215 MethodWriterImpl.addImplementsInfo(this, method, dl);
aoqi@0 216 if (overriddenMethod != null) {
aoqi@0 217 MethodWriterImpl.addOverridden(this,
aoqi@0 218 method.overriddenType(), overriddenMethod, dl);
aoqi@0 219 }
aoqi@0 220 }
aoqi@0 221 }
aoqi@0 222
aoqi@0 223 /**
aoqi@0 224 * Adds the tags information.
aoqi@0 225 *
aoqi@0 226 * @param doc the doc for which the tags will be generated
aoqi@0 227 * @param htmltree the documentation tree to which the tags will be added
aoqi@0 228 */
aoqi@0 229 protected void addTagsInfo(Doc doc, Content htmltree) {
aoqi@0 230 if (configuration.nocomment) {
aoqi@0 231 return;
aoqi@0 232 }
aoqi@0 233 Content dl = new HtmlTree(HtmlTag.DL);
aoqi@0 234 if (doc instanceof MethodDoc) {
aoqi@0 235 addMethodInfo((MethodDoc) doc, dl);
aoqi@0 236 }
aoqi@0 237 Content output = new ContentBuilder();
aoqi@0 238 TagletWriter.genTagOuput(configuration.tagletManager, doc,
aoqi@0 239 configuration.tagletManager.getCustomTaglets(doc),
aoqi@0 240 getTagletWriterInstance(false), output);
aoqi@0 241 dl.addContent(output);
aoqi@0 242 htmltree.addContent(dl);
aoqi@0 243 }
aoqi@0 244
aoqi@0 245 /**
aoqi@0 246 * Check whether there are any tags for Serialization Overview
aoqi@0 247 * section to be printed.
aoqi@0 248 *
aoqi@0 249 * @param field the FieldDoc object to check for tags.
aoqi@0 250 * @return true if there are tags to be printed else return false.
aoqi@0 251 */
aoqi@0 252 protected boolean hasSerializationOverviewTags(FieldDoc field) {
aoqi@0 253 Content output = new ContentBuilder();
aoqi@0 254 TagletWriter.genTagOuput(configuration.tagletManager, field,
aoqi@0 255 configuration.tagletManager.getCustomTaglets(field),
aoqi@0 256 getTagletWriterInstance(false), output);
aoqi@0 257 return !output.isEmpty();
aoqi@0 258 }
aoqi@0 259
aoqi@0 260 /**
aoqi@0 261 * Returns a TagletWriter that knows how to write HTML.
aoqi@0 262 *
aoqi@0 263 * @return a TagletWriter that knows how to write HTML.
aoqi@0 264 */
aoqi@0 265 public TagletWriter getTagletWriterInstance(boolean isFirstSentence) {
aoqi@0 266 return new TagletWriterImpl(this, isFirstSentence);
aoqi@0 267 }
aoqi@0 268
aoqi@0 269 /**
aoqi@0 270 * Get Package link, with target frame.
aoqi@0 271 *
aoqi@0 272 * @param pd The link will be to the "package-summary.html" page for this package
aoqi@0 273 * @param target name of the target frame
aoqi@0 274 * @param label tag for the link
aoqi@0 275 * @return a content for the target package link
aoqi@0 276 */
aoqi@0 277 public Content getTargetPackageLink(PackageDoc pd, String target,
aoqi@0 278 Content label) {
aoqi@0 279 return getHyperLink(pathString(pd, DocPaths.PACKAGE_SUMMARY), label, "", target);
aoqi@0 280 }
aoqi@0 281
aoqi@0 282 /**
aoqi@0 283 * Get Profile Package link, with target frame.
aoqi@0 284 *
aoqi@0 285 * @param pd the packageDoc object
aoqi@0 286 * @param target name of the target frame
aoqi@0 287 * @param label tag for the link
aoqi@0 288 * @param profileName the name of the profile being documented
aoqi@0 289 * @return a content for the target profile packages link
aoqi@0 290 */
aoqi@0 291 public Content getTargetProfilePackageLink(PackageDoc pd, String target,
aoqi@0 292 Content label, String profileName) {
aoqi@0 293 return getHyperLink(pathString(pd, DocPaths.profilePackageSummary(profileName)),
aoqi@0 294 label, "", target);
aoqi@0 295 }
aoqi@0 296
aoqi@0 297 /**
aoqi@0 298 * Get Profile link, with target frame.
aoqi@0 299 *
aoqi@0 300 * @param target name of the target frame
aoqi@0 301 * @param label tag for the link
aoqi@0 302 * @param profileName the name of the profile being documented
aoqi@0 303 * @return a content for the target profile link
aoqi@0 304 */
aoqi@0 305 public Content getTargetProfileLink(String target, Content label,
aoqi@0 306 String profileName) {
aoqi@0 307 return getHyperLink(pathToRoot.resolve(
aoqi@0 308 DocPaths.profileSummary(profileName)), label, "", target);
aoqi@0 309 }
aoqi@0 310
aoqi@0 311 /**
aoqi@0 312 * Get the type name for profile search.
aoqi@0 313 *
aoqi@0 314 * @param cd the classDoc object for which the type name conversion is needed
aoqi@0 315 * @return a type name string for the type
aoqi@0 316 */
aoqi@0 317 public String getTypeNameForProfile(ClassDoc cd) {
aoqi@0 318 StringBuilder typeName =
aoqi@0 319 new StringBuilder((cd.containingPackage()).name().replace(".", "/"));
aoqi@0 320 typeName.append("/")
aoqi@0 321 .append(cd.name().replace(".", "$"));
aoqi@0 322 return typeName.toString();
aoqi@0 323 }
aoqi@0 324
aoqi@0 325 /**
aoqi@0 326 * Check if a type belongs to a profile.
aoqi@0 327 *
aoqi@0 328 * @param cd the classDoc object that needs to be checked
aoqi@0 329 * @param profileValue the profile in which the type needs to be checked
aoqi@0 330 * @return true if the type is in the profile
aoqi@0 331 */
aoqi@0 332 public boolean isTypeInProfile(ClassDoc cd, int profileValue) {
aoqi@0 333 return (configuration.profiles.getProfile(getTypeNameForProfile(cd)) <= profileValue);
aoqi@0 334 }
aoqi@0 335
aoqi@0 336 public void addClassesSummary(ClassDoc[] classes, String label,
aoqi@0 337 String tableSummary, String[] tableHeader, Content summaryContentTree,
aoqi@0 338 int profileValue) {
aoqi@0 339 if(classes.length > 0) {
aoqi@0 340 Arrays.sort(classes);
aoqi@0 341 Content caption = getTableCaption(new RawHtml(label));
aoqi@0 342 Content table = HtmlTree.TABLE(HtmlStyle.typeSummary, 0, 3, 0,
aoqi@0 343 tableSummary, caption);
aoqi@0 344 table.addContent(getSummaryTableHeader(tableHeader, "col"));
aoqi@0 345 Content tbody = new HtmlTree(HtmlTag.TBODY);
aoqi@0 346 for (int i = 0; i < classes.length; i++) {
aoqi@0 347 if (!isTypeInProfile(classes[i], profileValue)) {
aoqi@0 348 continue;
aoqi@0 349 }
aoqi@0 350 if (!Util.isCoreClass(classes[i]) ||
aoqi@0 351 !configuration.isGeneratedDoc(classes[i])) {
aoqi@0 352 continue;
aoqi@0 353 }
aoqi@0 354 Content classContent = getLink(new LinkInfoImpl(
aoqi@0 355 configuration, LinkInfoImpl.Kind.PACKAGE, classes[i]));
aoqi@0 356 Content tdClass = HtmlTree.TD(HtmlStyle.colFirst, classContent);
aoqi@0 357 HtmlTree tr = HtmlTree.TR(tdClass);
aoqi@0 358 if (i%2 == 0)
aoqi@0 359 tr.addStyle(HtmlStyle.altColor);
aoqi@0 360 else
aoqi@0 361 tr.addStyle(HtmlStyle.rowColor);
aoqi@0 362 HtmlTree tdClassDescription = new HtmlTree(HtmlTag.TD);
aoqi@0 363 tdClassDescription.addStyle(HtmlStyle.colLast);
aoqi@0 364 if (Util.isDeprecated(classes[i])) {
aoqi@0 365 tdClassDescription.addContent(deprecatedLabel);
aoqi@0 366 if (classes[i].tags("deprecated").length > 0) {
aoqi@0 367 addSummaryDeprecatedComment(classes[i],
aoqi@0 368 classes[i].tags("deprecated")[0], tdClassDescription);
aoqi@0 369 }
aoqi@0 370 }
aoqi@0 371 else
aoqi@0 372 addSummaryComment(classes[i], tdClassDescription);
aoqi@0 373 tr.addContent(tdClassDescription);
aoqi@0 374 tbody.addContent(tr);
aoqi@0 375 }
aoqi@0 376 table.addContent(tbody);
aoqi@0 377 summaryContentTree.addContent(table);
aoqi@0 378 }
aoqi@0 379 }
aoqi@0 380
aoqi@0 381 /**
aoqi@0 382 * Generates the HTML document tree and prints it out.
aoqi@0 383 *
aoqi@0 384 * @param metakeywords Array of String keywords for META tag. Each element
aoqi@0 385 * of the array is assigned to a separate META tag.
aoqi@0 386 * Pass in null for no array
aoqi@0 387 * @param includeScript true if printing windowtitle script
aoqi@0 388 * false for files that appear in the left-hand frames
aoqi@0 389 * @param body the body htmltree to be included in the document
aoqi@0 390 */
aoqi@0 391 public void printHtmlDocument(String[] metakeywords, boolean includeScript,
aoqi@0 392 Content body) throws IOException {
aoqi@0 393 Content htmlDocType = DocType.TRANSITIONAL;
aoqi@0 394 Content htmlComment = new Comment(configuration.getText("doclet.New_Page"));
aoqi@0 395 Content head = new HtmlTree(HtmlTag.HEAD);
aoqi@0 396 head.addContent(getGeneratedBy(!configuration.notimestamp));
aoqi@0 397 if (configuration.charset.length() > 0) {
aoqi@0 398 Content meta = HtmlTree.META("Content-Type", CONTENT_TYPE,
aoqi@0 399 configuration.charset);
aoqi@0 400 head.addContent(meta);
aoqi@0 401 }
aoqi@0 402 head.addContent(getTitle());
aoqi@0 403 if (!configuration.notimestamp) {
aoqi@0 404 SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
aoqi@0 405 Content meta = HtmlTree.META("date", dateFormat.format(new Date()));
aoqi@0 406 head.addContent(meta);
aoqi@0 407 }
aoqi@0 408 if (metakeywords != null) {
aoqi@0 409 for (int i=0; i < metakeywords.length; i++) {
aoqi@0 410 Content meta = HtmlTree.META("keywords", metakeywords[i]);
aoqi@0 411 head.addContent(meta);
aoqi@0 412 }
aoqi@0 413 }
aoqi@0 414 head.addContent(getStyleSheetProperties());
aoqi@0 415 head.addContent(getScriptProperties());
aoqi@0 416 Content htmlTree = HtmlTree.HTML(configuration.getLocale().getLanguage(),
aoqi@0 417 head, body);
aoqi@0 418 Content htmlDocument = new HtmlDocument(htmlDocType,
aoqi@0 419 htmlComment, htmlTree);
aoqi@0 420 write(htmlDocument);
aoqi@0 421 }
aoqi@0 422
aoqi@0 423 /**
aoqi@0 424 * Get the window title.
aoqi@0 425 *
aoqi@0 426 * @param title the title string to construct the complete window title
aoqi@0 427 * @return the window title string
aoqi@0 428 */
aoqi@0 429 public String getWindowTitle(String title) {
aoqi@0 430 if (configuration.windowtitle.length() > 0) {
aoqi@0 431 title += " (" + configuration.windowtitle + ")";
aoqi@0 432 }
aoqi@0 433 return title;
aoqi@0 434 }
aoqi@0 435
aoqi@0 436 /**
aoqi@0 437 * Get user specified header and the footer.
aoqi@0 438 *
aoqi@0 439 * @param header if true print the user provided header else print the
aoqi@0 440 * user provided footer.
aoqi@0 441 */
aoqi@0 442 public Content getUserHeaderFooter(boolean header) {
aoqi@0 443 String content;
aoqi@0 444 if (header) {
aoqi@0 445 content = replaceDocRootDir(configuration.header);
aoqi@0 446 } else {
aoqi@0 447 if (configuration.footer.length() != 0) {
aoqi@0 448 content = replaceDocRootDir(configuration.footer);
aoqi@0 449 } else {
aoqi@0 450 content = replaceDocRootDir(configuration.header);
aoqi@0 451 }
aoqi@0 452 }
aoqi@0 453 Content rawContent = new RawHtml(content);
aoqi@0 454 return rawContent;
aoqi@0 455 }
aoqi@0 456
aoqi@0 457 /**
aoqi@0 458 * Adds the user specified top.
aoqi@0 459 *
aoqi@0 460 * @param body the content tree to which user specified top will be added
aoqi@0 461 */
aoqi@0 462 public void addTop(Content body) {
aoqi@0 463 Content top = new RawHtml(replaceDocRootDir(configuration.top));
aoqi@0 464 body.addContent(top);
aoqi@0 465 }
aoqi@0 466
aoqi@0 467 /**
aoqi@0 468 * Adds the user specified bottom.
aoqi@0 469 *
aoqi@0 470 * @param body the content tree to which user specified bottom will be added
aoqi@0 471 */
aoqi@0 472 public void addBottom(Content body) {
aoqi@0 473 Content bottom = new RawHtml(replaceDocRootDir(configuration.bottom));
aoqi@0 474 Content small = HtmlTree.SMALL(bottom);
aoqi@0 475 Content p = HtmlTree.P(HtmlStyle.legalCopy, small);
aoqi@0 476 body.addContent(p);
aoqi@0 477 }
aoqi@0 478
aoqi@0 479 /**
aoqi@0 480 * Adds the navigation bar for the Html page at the top and and the bottom.
aoqi@0 481 *
aoqi@0 482 * @param header If true print navigation bar at the top of the page else
aoqi@0 483 * @param body the HtmlTree to which the nav links will be added
aoqi@0 484 */
aoqi@0 485 protected void addNavLinks(boolean header, Content body) {
aoqi@0 486 if (!configuration.nonavbar) {
aoqi@0 487 String allClassesId = "allclasses_";
aoqi@0 488 HtmlTree navDiv = new HtmlTree(HtmlTag.DIV);
aoqi@0 489 Content skipNavLinks = configuration.getResource("doclet.Skip_navigation_links");
aoqi@0 490 if (header) {
aoqi@0 491 body.addContent(HtmlConstants.START_OF_TOP_NAVBAR);
aoqi@0 492 navDiv.addStyle(HtmlStyle.topNav);
aoqi@0 493 allClassesId += "navbar_top";
aoqi@0 494 Content a = getMarkerAnchor(SectionName.NAVBAR_TOP);
aoqi@0 495 //WCAG - Hyperlinks should contain text or an image with alt text - for AT tools
aoqi@0 496 navDiv.addContent(a);
aoqi@0 497 Content skipLinkContent = HtmlTree.DIV(HtmlStyle.skipNav, getHyperLink(
aoqi@0 498 getDocLink(SectionName.SKIP_NAVBAR_TOP), skipNavLinks,
aoqi@0 499 skipNavLinks.toString(), ""));
aoqi@0 500 navDiv.addContent(skipLinkContent);
aoqi@0 501 } else {
aoqi@0 502 body.addContent(HtmlConstants.START_OF_BOTTOM_NAVBAR);
aoqi@0 503 navDiv.addStyle(HtmlStyle.bottomNav);
aoqi@0 504 allClassesId += "navbar_bottom";
aoqi@0 505 Content a = getMarkerAnchor(SectionName.NAVBAR_BOTTOM);
aoqi@0 506 navDiv.addContent(a);
aoqi@0 507 Content skipLinkContent = HtmlTree.DIV(HtmlStyle.skipNav, getHyperLink(
aoqi@0 508 getDocLink(SectionName.SKIP_NAVBAR_BOTTOM), skipNavLinks,
aoqi@0 509 skipNavLinks.toString(), ""));
aoqi@0 510 navDiv.addContent(skipLinkContent);
aoqi@0 511 }
aoqi@0 512 if (header) {
aoqi@0 513 navDiv.addContent(getMarkerAnchor(SectionName.NAVBAR_TOP_FIRSTROW));
aoqi@0 514 } else {
aoqi@0 515 navDiv.addContent(getMarkerAnchor(SectionName.NAVBAR_BOTTOM_FIRSTROW));
aoqi@0 516 }
aoqi@0 517 HtmlTree navList = new HtmlTree(HtmlTag.UL);
aoqi@0 518 navList.addStyle(HtmlStyle.navList);
aoqi@0 519 navList.addAttr(HtmlAttr.TITLE,
aoqi@0 520 configuration.getText("doclet.Navigation"));
aoqi@0 521 if (configuration.createoverview) {
aoqi@0 522 navList.addContent(getNavLinkContents());
aoqi@0 523 }
aoqi@0 524 if (configuration.packages.length == 1) {
aoqi@0 525 navList.addContent(getNavLinkPackage(configuration.packages[0]));
aoqi@0 526 } else if (configuration.packages.length > 1) {
aoqi@0 527 navList.addContent(getNavLinkPackage());
aoqi@0 528 }
aoqi@0 529 navList.addContent(getNavLinkClass());
aoqi@0 530 if(configuration.classuse) {
aoqi@0 531 navList.addContent(getNavLinkClassUse());
aoqi@0 532 }
aoqi@0 533 if(configuration.createtree) {
aoqi@0 534 navList.addContent(getNavLinkTree());
aoqi@0 535 }
aoqi@0 536 if(!(configuration.nodeprecated ||
aoqi@0 537 configuration.nodeprecatedlist)) {
aoqi@0 538 navList.addContent(getNavLinkDeprecated());
aoqi@0 539 }
aoqi@0 540 if(configuration.createindex) {
aoqi@0 541 navList.addContent(getNavLinkIndex());
aoqi@0 542 }
aoqi@0 543 if (!configuration.nohelp) {
aoqi@0 544 navList.addContent(getNavLinkHelp());
aoqi@0 545 }
aoqi@0 546 navDiv.addContent(navList);
aoqi@0 547 Content aboutDiv = HtmlTree.DIV(HtmlStyle.aboutLanguage, getUserHeaderFooter(header));
aoqi@0 548 navDiv.addContent(aboutDiv);
aoqi@0 549 body.addContent(navDiv);
aoqi@0 550 Content ulNav = HtmlTree.UL(HtmlStyle.navList, getNavLinkPrevious());
aoqi@0 551 ulNav.addContent(getNavLinkNext());
aoqi@0 552 Content subDiv = HtmlTree.DIV(HtmlStyle.subNav, ulNav);
aoqi@0 553 Content ulFrames = HtmlTree.UL(HtmlStyle.navList, getNavShowLists());
aoqi@0 554 ulFrames.addContent(getNavHideLists(filename));
aoqi@0 555 subDiv.addContent(ulFrames);
aoqi@0 556 HtmlTree ulAllClasses = HtmlTree.UL(HtmlStyle.navList, getNavLinkClassIndex());
aoqi@0 557 ulAllClasses.addAttr(HtmlAttr.ID, allClassesId.toString());
aoqi@0 558 subDiv.addContent(ulAllClasses);
aoqi@0 559 subDiv.addContent(getAllClassesLinkScript(allClassesId.toString()));
aoqi@0 560 addSummaryDetailLinks(subDiv);
aoqi@0 561 if (header) {
aoqi@0 562 subDiv.addContent(getMarkerAnchor(SectionName.SKIP_NAVBAR_TOP));
aoqi@0 563 body.addContent(subDiv);
aoqi@0 564 body.addContent(HtmlConstants.END_OF_TOP_NAVBAR);
aoqi@0 565 } else {
aoqi@0 566 subDiv.addContent(getMarkerAnchor(SectionName.SKIP_NAVBAR_BOTTOM));
aoqi@0 567 body.addContent(subDiv);
aoqi@0 568 body.addContent(HtmlConstants.END_OF_BOTTOM_NAVBAR);
aoqi@0 569 }
aoqi@0 570 }
aoqi@0 571 }
aoqi@0 572
aoqi@0 573 /**
aoqi@0 574 * Get the word "NEXT" to indicate that no link is available. Override
aoqi@0 575 * this method to customize next link.
aoqi@0 576 *
aoqi@0 577 * @return a content tree for the link
aoqi@0 578 */
aoqi@0 579 protected Content getNavLinkNext() {
aoqi@0 580 return getNavLinkNext(null);
aoqi@0 581 }
aoqi@0 582
aoqi@0 583 /**
aoqi@0 584 * Get the word "PREV" to indicate that no link is available. Override
aoqi@0 585 * this method to customize prev link.
aoqi@0 586 *
aoqi@0 587 * @return a content tree for the link
aoqi@0 588 */
aoqi@0 589 protected Content getNavLinkPrevious() {
aoqi@0 590 return getNavLinkPrevious(null);
aoqi@0 591 }
aoqi@0 592
aoqi@0 593 /**
aoqi@0 594 * Do nothing. This is the default method.
aoqi@0 595 */
aoqi@0 596 protected void addSummaryDetailLinks(Content navDiv) {
aoqi@0 597 }
aoqi@0 598
aoqi@0 599 /**
aoqi@0 600 * Get link to the "overview-summary.html" page.
aoqi@0 601 *
aoqi@0 602 * @return a content tree for the link
aoqi@0 603 */
aoqi@0 604 protected Content getNavLinkContents() {
aoqi@0 605 Content linkContent = getHyperLink(pathToRoot.resolve(DocPaths.OVERVIEW_SUMMARY),
aoqi@0 606 overviewLabel, "", "");
aoqi@0 607 Content li = HtmlTree.LI(linkContent);
aoqi@0 608 return li;
aoqi@0 609 }
aoqi@0 610
aoqi@0 611 /**
aoqi@0 612 * Get link to the "package-summary.html" page for the package passed.
aoqi@0 613 *
aoqi@0 614 * @param pkg Package to which link will be generated
aoqi@0 615 * @return a content tree for the link
aoqi@0 616 */
aoqi@0 617 protected Content getNavLinkPackage(PackageDoc pkg) {
aoqi@0 618 Content linkContent = getPackageLink(pkg,
aoqi@0 619 packageLabel);
aoqi@0 620 Content li = HtmlTree.LI(linkContent);
aoqi@0 621 return li;
aoqi@0 622 }
aoqi@0 623
aoqi@0 624 /**
aoqi@0 625 * Get the word "Package" , to indicate that link is not available here.
aoqi@0 626 *
aoqi@0 627 * @return a content tree for the link
aoqi@0 628 */
aoqi@0 629 protected Content getNavLinkPackage() {
aoqi@0 630 Content li = HtmlTree.LI(packageLabel);
aoqi@0 631 return li;
aoqi@0 632 }
aoqi@0 633
aoqi@0 634 /**
aoqi@0 635 * Get the word "Use", to indicate that link is not available.
aoqi@0 636 *
aoqi@0 637 * @return a content tree for the link
aoqi@0 638 */
aoqi@0 639 protected Content getNavLinkClassUse() {
aoqi@0 640 Content li = HtmlTree.LI(useLabel);
aoqi@0 641 return li;
aoqi@0 642 }
aoqi@0 643
aoqi@0 644 /**
aoqi@0 645 * Get link for previous file.
aoqi@0 646 *
aoqi@0 647 * @param prev File name for the prev link
aoqi@0 648 * @return a content tree for the link
aoqi@0 649 */
aoqi@0 650 public Content getNavLinkPrevious(DocPath prev) {
aoqi@0 651 Content li;
aoqi@0 652 if (prev != null) {
aoqi@0 653 li = HtmlTree.LI(getHyperLink(prev, prevLabel, "", ""));
aoqi@0 654 }
aoqi@0 655 else
aoqi@0 656 li = HtmlTree.LI(prevLabel);
aoqi@0 657 return li;
aoqi@0 658 }
aoqi@0 659
aoqi@0 660 /**
aoqi@0 661 * Get link for next file. If next is null, just print the label
aoqi@0 662 * without linking it anywhere.
aoqi@0 663 *
aoqi@0 664 * @param next File name for the next link
aoqi@0 665 * @return a content tree for the link
aoqi@0 666 */
aoqi@0 667 public Content getNavLinkNext(DocPath next) {
aoqi@0 668 Content li;
aoqi@0 669 if (next != null) {
aoqi@0 670 li = HtmlTree.LI(getHyperLink(next, nextLabel, "", ""));
aoqi@0 671 }
aoqi@0 672 else
aoqi@0 673 li = HtmlTree.LI(nextLabel);
aoqi@0 674 return li;
aoqi@0 675 }
aoqi@0 676
aoqi@0 677 /**
aoqi@0 678 * Get "FRAMES" link, to switch to the frame version of the output.
aoqi@0 679 *
aoqi@0 680 * @param link File to be linked, "index.html"
aoqi@0 681 * @return a content tree for the link
aoqi@0 682 */
aoqi@0 683 protected Content getNavShowLists(DocPath link) {
aoqi@0 684 DocLink dl = new DocLink(link, path.getPath(), null);
aoqi@0 685 Content framesContent = getHyperLink(dl, framesLabel, "", "_top");
aoqi@0 686 Content li = HtmlTree.LI(framesContent);
aoqi@0 687 return li;
aoqi@0 688 }
aoqi@0 689
aoqi@0 690 /**
aoqi@0 691 * Get "FRAMES" link, to switch to the frame version of the output.
aoqi@0 692 *
aoqi@0 693 * @return a content tree for the link
aoqi@0 694 */
aoqi@0 695 protected Content getNavShowLists() {
aoqi@0 696 return getNavShowLists(pathToRoot.resolve(DocPaths.INDEX));
aoqi@0 697 }
aoqi@0 698
aoqi@0 699 /**
aoqi@0 700 * Get "NO FRAMES" link, to switch to the non-frame version of the output.
aoqi@0 701 *
aoqi@0 702 * @param link File to be linked
aoqi@0 703 * @return a content tree for the link
aoqi@0 704 */
aoqi@0 705 protected Content getNavHideLists(DocPath link) {
aoqi@0 706 Content noFramesContent = getHyperLink(link, noframesLabel, "", "_top");
aoqi@0 707 Content li = HtmlTree.LI(noFramesContent);
aoqi@0 708 return li;
aoqi@0 709 }
aoqi@0 710
aoqi@0 711 /**
aoqi@0 712 * Get "Tree" link in the navigation bar. If there is only one package
aoqi@0 713 * specified on the command line, then the "Tree" link will be to the
aoqi@0 714 * only "package-tree.html" file otherwise it will be to the
aoqi@0 715 * "overview-tree.html" file.
aoqi@0 716 *
aoqi@0 717 * @return a content tree for the link
aoqi@0 718 */
aoqi@0 719 protected Content getNavLinkTree() {
aoqi@0 720 Content treeLinkContent;
aoqi@0 721 PackageDoc[] packages = configuration.root.specifiedPackages();
aoqi@0 722 if (packages.length == 1 && configuration.root.specifiedClasses().length == 0) {
aoqi@0 723 treeLinkContent = getHyperLink(pathString(packages[0],
aoqi@0 724 DocPaths.PACKAGE_TREE), treeLabel,
aoqi@0 725 "", "");
aoqi@0 726 } else {
aoqi@0 727 treeLinkContent = getHyperLink(pathToRoot.resolve(DocPaths.OVERVIEW_TREE),
aoqi@0 728 treeLabel, "", "");
aoqi@0 729 }
aoqi@0 730 Content li = HtmlTree.LI(treeLinkContent);
aoqi@0 731 return li;
aoqi@0 732 }
aoqi@0 733
aoqi@0 734 /**
aoqi@0 735 * Get the overview tree link for the main tree.
aoqi@0 736 *
aoqi@0 737 * @param label the label for the link
aoqi@0 738 * @return a content tree for the link
aoqi@0 739 */
aoqi@0 740 protected Content getNavLinkMainTree(String label) {
aoqi@0 741 Content mainTreeContent = getHyperLink(pathToRoot.resolve(DocPaths.OVERVIEW_TREE),
aoqi@0 742 new StringContent(label));
aoqi@0 743 Content li = HtmlTree.LI(mainTreeContent);
aoqi@0 744 return li;
aoqi@0 745 }
aoqi@0 746
aoqi@0 747 /**
aoqi@0 748 * Get the word "Class", to indicate that class link is not available.
aoqi@0 749 *
aoqi@0 750 * @return a content tree for the link
aoqi@0 751 */
aoqi@0 752 protected Content getNavLinkClass() {
aoqi@0 753 Content li = HtmlTree.LI(classLabel);
aoqi@0 754 return li;
aoqi@0 755 }
aoqi@0 756
aoqi@0 757 /**
aoqi@0 758 * Get "Deprecated" API link in the navigation bar.
aoqi@0 759 *
aoqi@0 760 * @return a content tree for the link
aoqi@0 761 */
aoqi@0 762 protected Content getNavLinkDeprecated() {
aoqi@0 763 Content linkContent = getHyperLink(pathToRoot.resolve(DocPaths.DEPRECATED_LIST),
aoqi@0 764 deprecatedLabel, "", "");
aoqi@0 765 Content li = HtmlTree.LI(linkContent);
aoqi@0 766 return li;
aoqi@0 767 }
aoqi@0 768
aoqi@0 769 /**
aoqi@0 770 * Get link for generated index. If the user has used "-splitindex"
aoqi@0 771 * command line option, then link to file "index-files/index-1.html" is
aoqi@0 772 * generated otherwise link to file "index-all.html" is generated.
aoqi@0 773 *
aoqi@0 774 * @return a content tree for the link
aoqi@0 775 */
aoqi@0 776 protected Content getNavLinkClassIndex() {
aoqi@0 777 Content allClassesContent = getHyperLink(pathToRoot.resolve(
aoqi@0 778 DocPaths.ALLCLASSES_NOFRAME),
aoqi@0 779 allclassesLabel, "", "");
aoqi@0 780 Content li = HtmlTree.LI(allClassesContent);
aoqi@0 781 return li;
aoqi@0 782 }
aoqi@0 783
aoqi@0 784 /**
aoqi@0 785 * Get link for generated class index.
aoqi@0 786 *
aoqi@0 787 * @return a content tree for the link
aoqi@0 788 */
aoqi@0 789 protected Content getNavLinkIndex() {
aoqi@0 790 Content linkContent = getHyperLink(pathToRoot.resolve(
aoqi@0 791 (configuration.splitindex
aoqi@0 792 ? DocPaths.INDEX_FILES.resolve(DocPaths.indexN(1))
aoqi@0 793 : DocPaths.INDEX_ALL)),
aoqi@0 794 indexLabel, "", "");
aoqi@0 795 Content li = HtmlTree.LI(linkContent);
aoqi@0 796 return li;
aoqi@0 797 }
aoqi@0 798
aoqi@0 799 /**
aoqi@0 800 * Get help file link. If user has provided a help file, then generate a
aoqi@0 801 * link to the user given file, which is already copied to current or
aoqi@0 802 * destination directory.
aoqi@0 803 *
aoqi@0 804 * @return a content tree for the link
aoqi@0 805 */
aoqi@0 806 protected Content getNavLinkHelp() {
aoqi@0 807 String helpfile = configuration.helpfile;
aoqi@0 808 DocPath helpfilenm;
aoqi@0 809 if (helpfile.isEmpty()) {
aoqi@0 810 helpfilenm = DocPaths.HELP_DOC;
aoqi@0 811 } else {
aoqi@0 812 DocFile file = DocFile.createFileForInput(configuration, helpfile);
aoqi@0 813 helpfilenm = DocPath.create(file.getName());
aoqi@0 814 }
aoqi@0 815 Content linkContent = getHyperLink(pathToRoot.resolve(helpfilenm),
aoqi@0 816 helpLabel, "", "");
aoqi@0 817 Content li = HtmlTree.LI(linkContent);
aoqi@0 818 return li;
aoqi@0 819 }
aoqi@0 820
aoqi@0 821 /**
aoqi@0 822 * Get summary table header.
aoqi@0 823 *
aoqi@0 824 * @param header the header for the table
aoqi@0 825 * @param scope the scope of the headers
aoqi@0 826 * @return a content tree for the header
aoqi@0 827 */
aoqi@0 828 public Content getSummaryTableHeader(String[] header, String scope) {
aoqi@0 829 Content tr = new HtmlTree(HtmlTag.TR);
aoqi@0 830 int size = header.length;
aoqi@0 831 Content tableHeader;
aoqi@0 832 if (size == 1) {
aoqi@0 833 tableHeader = new StringContent(header[0]);
aoqi@0 834 tr.addContent(HtmlTree.TH(HtmlStyle.colOne, scope, tableHeader));
aoqi@0 835 return tr;
aoqi@0 836 }
aoqi@0 837 for (int i = 0; i < size; i++) {
aoqi@0 838 tableHeader = new StringContent(header[i]);
aoqi@0 839 if(i == 0)
aoqi@0 840 tr.addContent(HtmlTree.TH(HtmlStyle.colFirst, scope, tableHeader));
aoqi@0 841 else if(i == (size - 1))
aoqi@0 842 tr.addContent(HtmlTree.TH(HtmlStyle.colLast, scope, tableHeader));
aoqi@0 843 else
aoqi@0 844 tr.addContent(HtmlTree.TH(scope, tableHeader));
aoqi@0 845 }
aoqi@0 846 return tr;
aoqi@0 847 }
aoqi@0 848
aoqi@0 849 /**
aoqi@0 850 * Get table caption.
aoqi@0 851 *
aoqi@0 852 * @param rawText the caption for the table which could be raw Html
aoqi@0 853 * @return a content tree for the caption
aoqi@0 854 */
aoqi@0 855 public Content getTableCaption(Content title) {
aoqi@0 856 Content captionSpan = HtmlTree.SPAN(title);
aoqi@0 857 Content space = getSpace();
aoqi@0 858 Content tabSpan = HtmlTree.SPAN(HtmlStyle.tabEnd, space);
aoqi@0 859 Content caption = HtmlTree.CAPTION(captionSpan);
aoqi@0 860 caption.addContent(tabSpan);
aoqi@0 861 return caption;
aoqi@0 862 }
aoqi@0 863
aoqi@0 864 /**
aoqi@0 865 * Get the marker anchor which will be added to the documentation tree.
aoqi@0 866 *
aoqi@0 867 * @param anchorName the anchor name attribute
aoqi@0 868 * @return a content tree for the marker anchor
aoqi@0 869 */
aoqi@0 870 public Content getMarkerAnchor(String anchorName) {
aoqi@0 871 return getMarkerAnchor(getName(anchorName), null);
aoqi@0 872 }
aoqi@0 873
aoqi@0 874 /**
aoqi@0 875 * Get the marker anchor which will be added to the documentation tree.
aoqi@0 876 *
aoqi@0 877 * @param sectionName the section name anchor attribute for page
aoqi@0 878 * @return a content tree for the marker anchor
aoqi@0 879 */
aoqi@0 880 public Content getMarkerAnchor(SectionName sectionName) {
aoqi@0 881 return getMarkerAnchor(sectionName.getName(), null);
aoqi@0 882 }
aoqi@0 883
aoqi@0 884 /**
aoqi@0 885 * Get the marker anchor which will be added to the documentation tree.
aoqi@0 886 *
aoqi@0 887 * @param sectionName the section name anchor attribute for page
aoqi@0 888 * @param anchorName the anchor name combined with section name attribute for the page
aoqi@0 889 * @return a content tree for the marker anchor
aoqi@0 890 */
aoqi@0 891 public Content getMarkerAnchor(SectionName sectionName, String anchorName) {
aoqi@0 892 return getMarkerAnchor(sectionName.getName() + getName(anchorName), null);
aoqi@0 893 }
aoqi@0 894
aoqi@0 895 /**
aoqi@0 896 * Get the marker anchor which will be added to the documentation tree.
aoqi@0 897 *
aoqi@0 898 * @param anchorName the anchor name attribute
aoqi@0 899 * @param anchorContent the content that should be added to the anchor
aoqi@0 900 * @return a content tree for the marker anchor
aoqi@0 901 */
aoqi@0 902 public Content getMarkerAnchor(String anchorName, Content anchorContent) {
aoqi@0 903 if (anchorContent == null)
aoqi@0 904 anchorContent = new Comment(" ");
aoqi@0 905 Content markerAnchor = HtmlTree.A_NAME(anchorName, anchorContent);
aoqi@0 906 return markerAnchor;
aoqi@0 907 }
aoqi@0 908
aoqi@0 909 /**
aoqi@0 910 * Returns a packagename content.
aoqi@0 911 *
aoqi@0 912 * @param packageDoc the package to check
aoqi@0 913 * @return package name content
aoqi@0 914 */
aoqi@0 915 public Content getPackageName(PackageDoc packageDoc) {
aoqi@0 916 return packageDoc == null || packageDoc.name().length() == 0 ?
aoqi@0 917 defaultPackageLabel :
aoqi@0 918 getPackageLabel(packageDoc.name());
aoqi@0 919 }
aoqi@0 920
aoqi@0 921 /**
aoqi@0 922 * Returns a package name label.
aoqi@0 923 *
aoqi@0 924 * @param packageName the package name
aoqi@0 925 * @return the package name content
aoqi@0 926 */
aoqi@0 927 public Content getPackageLabel(String packageName) {
aoqi@0 928 return new StringContent(packageName);
aoqi@0 929 }
aoqi@0 930
aoqi@0 931 /**
aoqi@0 932 * Add package deprecation information to the documentation tree
aoqi@0 933 *
aoqi@0 934 * @param deprPkgs list of deprecated packages
aoqi@0 935 * @param headingKey the caption for the deprecated package table
aoqi@0 936 * @param tableSummary the summary for the deprecated package table
aoqi@0 937 * @param tableHeader table headers for the deprecated package table
aoqi@0 938 * @param contentTree the content tree to which the deprecated package table will be added
aoqi@0 939 */
aoqi@0 940 protected void addPackageDeprecatedAPI(List<Doc> deprPkgs, String headingKey,
aoqi@0 941 String tableSummary, String[] tableHeader, Content contentTree) {
aoqi@0 942 if (deprPkgs.size() > 0) {
aoqi@0 943 Content table = HtmlTree.TABLE(HtmlStyle.deprecatedSummary, 0, 3, 0, tableSummary,
aoqi@0 944 getTableCaption(configuration.getResource(headingKey)));
aoqi@0 945 table.addContent(getSummaryTableHeader(tableHeader, "col"));
aoqi@0 946 Content tbody = new HtmlTree(HtmlTag.TBODY);
aoqi@0 947 for (int i = 0; i < deprPkgs.size(); i++) {
aoqi@0 948 PackageDoc pkg = (PackageDoc) deprPkgs.get(i);
aoqi@0 949 HtmlTree td = HtmlTree.TD(HtmlStyle.colOne,
aoqi@0 950 getPackageLink(pkg, getPackageName(pkg)));
aoqi@0 951 if (pkg.tags("deprecated").length > 0) {
aoqi@0 952 addInlineDeprecatedComment(pkg, pkg.tags("deprecated")[0], td);
aoqi@0 953 }
aoqi@0 954 HtmlTree tr = HtmlTree.TR(td);
aoqi@0 955 if (i % 2 == 0) {
aoqi@0 956 tr.addStyle(HtmlStyle.altColor);
aoqi@0 957 } else {
aoqi@0 958 tr.addStyle(HtmlStyle.rowColor);
aoqi@0 959 }
aoqi@0 960 tbody.addContent(tr);
aoqi@0 961 }
aoqi@0 962 table.addContent(tbody);
aoqi@0 963 Content li = HtmlTree.LI(HtmlStyle.blockList, table);
aoqi@0 964 Content ul = HtmlTree.UL(HtmlStyle.blockList, li);
aoqi@0 965 contentTree.addContent(ul);
aoqi@0 966 }
aoqi@0 967 }
aoqi@0 968
aoqi@0 969 /**
aoqi@0 970 * Return the path to the class page for a classdoc.
aoqi@0 971 *
aoqi@0 972 * @param cd Class to which the path is requested.
aoqi@0 973 * @param name Name of the file(doesn't include path).
aoqi@0 974 */
aoqi@0 975 protected DocPath pathString(ClassDoc cd, DocPath name) {
aoqi@0 976 return pathString(cd.containingPackage(), name);
aoqi@0 977 }
aoqi@0 978
aoqi@0 979 /**
aoqi@0 980 * Return path to the given file name in the given package. So if the name
aoqi@0 981 * passed is "Object.html" and the name of the package is "java.lang", and
aoqi@0 982 * if the relative path is "../.." then returned string will be
aoqi@0 983 * "../../java/lang/Object.html"
aoqi@0 984 *
aoqi@0 985 * @param pd Package in which the file name is assumed to be.
aoqi@0 986 * @param name File name, to which path string is.
aoqi@0 987 */
aoqi@0 988 protected DocPath pathString(PackageDoc pd, DocPath name) {
aoqi@0 989 return pathToRoot.resolve(DocPath.forPackage(pd).resolve(name));
aoqi@0 990 }
aoqi@0 991
aoqi@0 992 /**
aoqi@0 993 * Return the link to the given package.
aoqi@0 994 *
aoqi@0 995 * @param pkg the package to link to.
aoqi@0 996 * @param label the label for the link.
aoqi@0 997 * @return a content tree for the package link.
aoqi@0 998 */
aoqi@0 999 public Content getPackageLink(PackageDoc pkg, String label) {
aoqi@0 1000 return getPackageLink(pkg, new StringContent(label));
aoqi@0 1001 }
aoqi@0 1002
aoqi@0 1003 /**
aoqi@0 1004 * Return the link to the given package.
aoqi@0 1005 *
aoqi@0 1006 * @param pkg the package to link to.
aoqi@0 1007 * @param label the label for the link.
aoqi@0 1008 * @return a content tree for the package link.
aoqi@0 1009 */
aoqi@0 1010 public Content getPackageLink(PackageDoc pkg, Content label) {
aoqi@0 1011 boolean included = pkg != null && pkg.isIncluded();
aoqi@0 1012 if (! included) {
aoqi@0 1013 PackageDoc[] packages = configuration.packages;
aoqi@0 1014 for (int i = 0; i < packages.length; i++) {
aoqi@0 1015 if (packages[i].equals(pkg)) {
aoqi@0 1016 included = true;
aoqi@0 1017 break;
aoqi@0 1018 }
aoqi@0 1019 }
aoqi@0 1020 }
aoqi@0 1021 if (included || pkg == null) {
aoqi@0 1022 return getHyperLink(pathString(pkg, DocPaths.PACKAGE_SUMMARY),
aoqi@0 1023 label);
aoqi@0 1024 } else {
aoqi@0 1025 DocLink crossPkgLink = getCrossPackageLink(Util.getPackageName(pkg));
aoqi@0 1026 if (crossPkgLink != null) {
aoqi@0 1027 return getHyperLink(crossPkgLink, label);
aoqi@0 1028 } else {
aoqi@0 1029 return label;
aoqi@0 1030 }
aoqi@0 1031 }
aoqi@0 1032 }
aoqi@0 1033
aoqi@0 1034 public Content italicsClassName(ClassDoc cd, boolean qual) {
aoqi@0 1035 Content name = new StringContent((qual)? cd.qualifiedName(): cd.name());
aoqi@0 1036 return (cd.isInterface())? HtmlTree.SPAN(HtmlStyle.interfaceName, name): name;
aoqi@0 1037 }
aoqi@0 1038
aoqi@0 1039 /**
aoqi@0 1040 * Add the link to the content tree.
aoqi@0 1041 *
aoqi@0 1042 * @param doc program element doc for which the link will be added
aoqi@0 1043 * @param label label for the link
aoqi@0 1044 * @param htmltree the content tree to which the link will be added
aoqi@0 1045 */
aoqi@0 1046 public void addSrcLink(ProgramElementDoc doc, Content label, Content htmltree) {
aoqi@0 1047 if (doc == null) {
aoqi@0 1048 return;
aoqi@0 1049 }
aoqi@0 1050 ClassDoc cd = doc.containingClass();
aoqi@0 1051 if (cd == null) {
aoqi@0 1052 //d must be a class doc since in has no containing class.
aoqi@0 1053 cd = (ClassDoc) doc;
aoqi@0 1054 }
aoqi@0 1055 DocPath href = pathToRoot
aoqi@0 1056 .resolve(DocPaths.SOURCE_OUTPUT)
aoqi@0 1057 .resolve(DocPath.forClass(cd));
aoqi@0 1058 Content linkContent = getHyperLink(href.fragment(SourceToHTMLConverter.getAnchorName(doc)), label, "", "");
aoqi@0 1059 htmltree.addContent(linkContent);
aoqi@0 1060 }
aoqi@0 1061
aoqi@0 1062 /**
aoqi@0 1063 * Return the link to the given class.
aoqi@0 1064 *
aoqi@0 1065 * @param linkInfo the information about the link.
aoqi@0 1066 *
aoqi@0 1067 * @return the link for the given class.
aoqi@0 1068 */
aoqi@0 1069 public Content getLink(LinkInfoImpl linkInfo) {
aoqi@0 1070 LinkFactoryImpl factory = new LinkFactoryImpl(this);
aoqi@0 1071 return factory.getLink(linkInfo);
aoqi@0 1072 }
aoqi@0 1073
aoqi@0 1074 /**
aoqi@0 1075 * Return the type parameters for the given class.
aoqi@0 1076 *
aoqi@0 1077 * @param linkInfo the information about the link.
aoqi@0 1078 * @return the type for the given class.
aoqi@0 1079 */
aoqi@0 1080 public Content getTypeParameterLinks(LinkInfoImpl linkInfo) {
aoqi@0 1081 LinkFactoryImpl factory = new LinkFactoryImpl(this);
aoqi@0 1082 return factory.getTypeParameterLinks(linkInfo, false);
aoqi@0 1083 }
aoqi@0 1084
aoqi@0 1085 /*************************************************************
aoqi@0 1086 * Return a class cross link to external class documentation.
aoqi@0 1087 * The name must be fully qualified to determine which package
aoqi@0 1088 * the class is in. The -link option does not allow users to
aoqi@0 1089 * link to external classes in the "default" package.
aoqi@0 1090 *
aoqi@0 1091 * @param qualifiedClassName the qualified name of the external class.
aoqi@0 1092 * @param refMemName the name of the member being referenced. This should
aoqi@0 1093 * be null or empty string if no member is being referenced.
aoqi@0 1094 * @param label the label for the external link.
aoqi@0 1095 * @param strong true if the link should be strong.
aoqi@0 1096 * @param style the style of the link.
aoqi@0 1097 * @param code true if the label should be code font.
aoqi@0 1098 */
aoqi@0 1099 public Content getCrossClassLink(String qualifiedClassName, String refMemName,
aoqi@0 1100 Content label, boolean strong, String style,
aoqi@0 1101 boolean code) {
aoqi@0 1102 String className = "";
aoqi@0 1103 String packageName = qualifiedClassName == null ? "" : qualifiedClassName;
aoqi@0 1104 int periodIndex;
aoqi@0 1105 while ((periodIndex = packageName.lastIndexOf('.')) != -1) {
aoqi@0 1106 className = packageName.substring(periodIndex + 1, packageName.length()) +
aoqi@0 1107 (className.length() > 0 ? "." + className : "");
aoqi@0 1108 Content defaultLabel = new StringContent(className);
aoqi@0 1109 if (code)
aoqi@0 1110 defaultLabel = HtmlTree.CODE(defaultLabel);
aoqi@0 1111 packageName = packageName.substring(0, periodIndex);
aoqi@0 1112 if (getCrossPackageLink(packageName) != null) {
aoqi@0 1113 //The package exists in external documentation, so link to the external
aoqi@0 1114 //class (assuming that it exists). This is definitely a limitation of
aoqi@0 1115 //the -link option. There are ways to determine if an external package
aoqi@0 1116 //exists, but no way to determine if the external class exists. We just
aoqi@0 1117 //have to assume that it does.
aoqi@0 1118 DocLink link = configuration.extern.getExternalLink(packageName, pathToRoot,
aoqi@0 1119 className + ".html", refMemName);
aoqi@0 1120 return getHyperLink(link,
aoqi@0 1121 (label == null) || label.isEmpty() ? defaultLabel : label,
aoqi@0 1122 strong, style,
aoqi@0 1123 configuration.getText("doclet.Href_Class_Or_Interface_Title", packageName),
aoqi@0 1124 "");
aoqi@0 1125 }
aoqi@0 1126 }
aoqi@0 1127 return null;
aoqi@0 1128 }
aoqi@0 1129
aoqi@0 1130 public boolean isClassLinkable(ClassDoc cd) {
aoqi@0 1131 if (cd.isIncluded()) {
aoqi@0 1132 return configuration.isGeneratedDoc(cd);
aoqi@0 1133 }
aoqi@0 1134 return configuration.extern.isExternal(cd);
aoqi@0 1135 }
aoqi@0 1136
aoqi@0 1137 public DocLink getCrossPackageLink(String pkgName) {
aoqi@0 1138 return configuration.extern.getExternalLink(pkgName, pathToRoot,
aoqi@0 1139 DocPaths.PACKAGE_SUMMARY.getPath());
aoqi@0 1140 }
aoqi@0 1141
aoqi@0 1142 /**
aoqi@0 1143 * Get the class link.
aoqi@0 1144 *
aoqi@0 1145 * @param context the id of the context where the link will be added
aoqi@0 1146 * @param cd the class doc to link to
aoqi@0 1147 * @return a content tree for the link
aoqi@0 1148 */
aoqi@0 1149 public Content getQualifiedClassLink(LinkInfoImpl.Kind context, ClassDoc cd) {
aoqi@0 1150 return getLink(new LinkInfoImpl(configuration, context, cd)
aoqi@0 1151 .label(configuration.getClassName(cd)));
aoqi@0 1152 }
aoqi@0 1153
aoqi@0 1154 /**
aoqi@0 1155 * Add the class link.
aoqi@0 1156 *
aoqi@0 1157 * @param context the id of the context where the link will be added
aoqi@0 1158 * @param cd the class doc to link to
aoqi@0 1159 * @param contentTree the content tree to which the link will be added
aoqi@0 1160 */
aoqi@0 1161 public void addPreQualifiedClassLink(LinkInfoImpl.Kind context, ClassDoc cd, Content contentTree) {
aoqi@0 1162 addPreQualifiedClassLink(context, cd, false, contentTree);
aoqi@0 1163 }
aoqi@0 1164
aoqi@0 1165 /**
aoqi@0 1166 * Retrieve the class link with the package portion of the label in
aoqi@0 1167 * plain text. If the qualifier is excluded, it will not be included in the
aoqi@0 1168 * link label.
aoqi@0 1169 *
aoqi@0 1170 * @param cd the class to link to.
aoqi@0 1171 * @param isStrong true if the link should be strong.
aoqi@0 1172 * @return the link with the package portion of the label in plain text.
aoqi@0 1173 */
aoqi@0 1174 public Content getPreQualifiedClassLink(LinkInfoImpl.Kind context,
aoqi@0 1175 ClassDoc cd, boolean isStrong) {
aoqi@0 1176 ContentBuilder classlink = new ContentBuilder();
aoqi@0 1177 PackageDoc pd = cd.containingPackage();
aoqi@0 1178 if (pd != null && ! configuration.shouldExcludeQualifier(pd.name())) {
aoqi@0 1179 classlink.addContent(getPkgName(cd));
aoqi@0 1180 }
aoqi@0 1181 classlink.addContent(getLink(new LinkInfoImpl(configuration,
aoqi@0 1182 context, cd).label(cd.name()).strong(isStrong)));
aoqi@0 1183 return classlink;
aoqi@0 1184 }
aoqi@0 1185
aoqi@0 1186 /**
aoqi@0 1187 * Add the class link with the package portion of the label in
aoqi@0 1188 * plain text. If the qualifier is excluded, it will not be included in the
aoqi@0 1189 * link label.
aoqi@0 1190 *
aoqi@0 1191 * @param context the id of the context where the link will be added
aoqi@0 1192 * @param cd the class to link to
aoqi@0 1193 * @param isStrong true if the link should be strong
aoqi@0 1194 * @param contentTree the content tree to which the link with be added
aoqi@0 1195 */
aoqi@0 1196 public void addPreQualifiedClassLink(LinkInfoImpl.Kind context,
aoqi@0 1197 ClassDoc cd, boolean isStrong, Content contentTree) {
aoqi@0 1198 PackageDoc pd = cd.containingPackage();
aoqi@0 1199 if(pd != null && ! configuration.shouldExcludeQualifier(pd.name())) {
aoqi@0 1200 contentTree.addContent(getPkgName(cd));
aoqi@0 1201 }
aoqi@0 1202 contentTree.addContent(getLink(new LinkInfoImpl(configuration,
aoqi@0 1203 context, cd).label(cd.name()).strong(isStrong)));
aoqi@0 1204 }
aoqi@0 1205
aoqi@0 1206 /**
aoqi@0 1207 * Add the class link, with only class name as the strong link and prefixing
aoqi@0 1208 * plain package name.
aoqi@0 1209 *
aoqi@0 1210 * @param context the id of the context where the link will be added
aoqi@0 1211 * @param cd the class to link to
aoqi@0 1212 * @param contentTree the content tree to which the link with be added
aoqi@0 1213 */
aoqi@0 1214 public void addPreQualifiedStrongClassLink(LinkInfoImpl.Kind context, ClassDoc cd, Content contentTree) {
aoqi@0 1215 addPreQualifiedClassLink(context, cd, true, contentTree);
aoqi@0 1216 }
aoqi@0 1217
aoqi@0 1218 /**
aoqi@0 1219 * Get the link for the given member.
aoqi@0 1220 *
aoqi@0 1221 * @param context the id of the context where the link will be added
aoqi@0 1222 * @param doc the member being linked to
aoqi@0 1223 * @param label the label for the link
aoqi@0 1224 * @return a content tree for the doc link
aoqi@0 1225 */
aoqi@0 1226 public Content getDocLink(LinkInfoImpl.Kind context, MemberDoc doc, String label) {
aoqi@0 1227 return getDocLink(context, doc.containingClass(), doc,
aoqi@0 1228 new StringContent(label));
aoqi@0 1229 }
aoqi@0 1230
aoqi@0 1231 /**
aoqi@0 1232 * Return the link for the given member.
aoqi@0 1233 *
aoqi@0 1234 * @param context the id of the context where the link will be printed.
aoqi@0 1235 * @param doc the member being linked to.
aoqi@0 1236 * @param label the label for the link.
aoqi@0 1237 * @param strong true if the link should be strong.
aoqi@0 1238 * @return the link for the given member.
aoqi@0 1239 */
aoqi@0 1240 public Content getDocLink(LinkInfoImpl.Kind context, MemberDoc doc, String label,
aoqi@0 1241 boolean strong) {
aoqi@0 1242 return getDocLink(context, doc.containingClass(), doc, label, strong);
aoqi@0 1243 }
aoqi@0 1244
aoqi@0 1245 /**
aoqi@0 1246 * Return the link for the given member.
aoqi@0 1247 *
aoqi@0 1248 * @param context the id of the context where the link will be printed.
aoqi@0 1249 * @param classDoc the classDoc that we should link to. This is not
aoqi@0 1250 * necessarily equal to doc.containingClass(). We may be
aoqi@0 1251 * inheriting comments.
aoqi@0 1252 * @param doc the member being linked to.
aoqi@0 1253 * @param label the label for the link.
aoqi@0 1254 * @param strong true if the link should be strong.
aoqi@0 1255 * @return the link for the given member.
aoqi@0 1256 */
aoqi@0 1257 public Content getDocLink(LinkInfoImpl.Kind context, ClassDoc classDoc, MemberDoc doc,
aoqi@0 1258 String label, boolean strong) {
aoqi@0 1259 return getDocLink(context, classDoc, doc, label, strong, false);
aoqi@0 1260 }
aoqi@0 1261 public Content getDocLink(LinkInfoImpl.Kind context, ClassDoc classDoc, MemberDoc doc,
aoqi@0 1262 Content label, boolean strong) {
aoqi@0 1263 return getDocLink(context, classDoc, doc, label, strong, false);
aoqi@0 1264 }
aoqi@0 1265
aoqi@0 1266 /**
aoqi@0 1267 * Return the link for the given member.
aoqi@0 1268 *
aoqi@0 1269 * @param context the id of the context where the link will be printed.
aoqi@0 1270 * @param classDoc the classDoc that we should link to. This is not
aoqi@0 1271 * necessarily equal to doc.containingClass(). We may be
aoqi@0 1272 * inheriting comments.
aoqi@0 1273 * @param doc the member being linked to.
aoqi@0 1274 * @param label the label for the link.
aoqi@0 1275 * @param strong true if the link should be strong.
aoqi@0 1276 * @param isProperty true if the doc parameter is a JavaFX property.
aoqi@0 1277 * @return the link for the given member.
aoqi@0 1278 */
aoqi@0 1279 public Content getDocLink(LinkInfoImpl.Kind context, ClassDoc classDoc, MemberDoc doc,
aoqi@0 1280 String label, boolean strong, boolean isProperty) {
aoqi@0 1281 return getDocLink(context, classDoc, doc, new StringContent(check(label)), strong, isProperty);
aoqi@0 1282 }
aoqi@0 1283
aoqi@0 1284 String check(String s) {
aoqi@0 1285 if (s.matches(".*[&<>].*"))throw new IllegalArgumentException(s);
aoqi@0 1286 return s;
aoqi@0 1287 }
aoqi@0 1288
aoqi@0 1289 public Content getDocLink(LinkInfoImpl.Kind context, ClassDoc classDoc, MemberDoc doc,
aoqi@0 1290 Content label, boolean strong, boolean isProperty) {
aoqi@0 1291 if (! (doc.isIncluded() ||
aoqi@0 1292 Util.isLinkable(classDoc, configuration))) {
aoqi@0 1293 return label;
aoqi@0 1294 } else if (doc instanceof ExecutableMemberDoc) {
aoqi@0 1295 ExecutableMemberDoc emd = (ExecutableMemberDoc)doc;
aoqi@0 1296 return getLink(new LinkInfoImpl(configuration, context, classDoc)
aoqi@0 1297 .label(label).where(getName(getAnchor(emd, isProperty))).strong(strong));
aoqi@0 1298 } else if (doc instanceof MemberDoc) {
aoqi@0 1299 return getLink(new LinkInfoImpl(configuration, context, classDoc)
aoqi@0 1300 .label(label).where(getName(doc.name())).strong(strong));
aoqi@0 1301 } else {
aoqi@0 1302 return label;
aoqi@0 1303 }
aoqi@0 1304 }
aoqi@0 1305
aoqi@0 1306 /**
aoqi@0 1307 * Return the link for the given member.
aoqi@0 1308 *
aoqi@0 1309 * @param context the id of the context where the link will be added
aoqi@0 1310 * @param classDoc the classDoc that we should link to. This is not
aoqi@0 1311 * necessarily equal to doc.containingClass(). We may be
aoqi@0 1312 * inheriting comments
aoqi@0 1313 * @param doc the member being linked to
aoqi@0 1314 * @param label the label for the link
aoqi@0 1315 * @return the link for the given member
aoqi@0 1316 */
aoqi@0 1317 public Content getDocLink(LinkInfoImpl.Kind context, ClassDoc classDoc, MemberDoc doc,
aoqi@0 1318 Content label) {
aoqi@0 1319 if (! (doc.isIncluded() ||
aoqi@0 1320 Util.isLinkable(classDoc, configuration))) {
aoqi@0 1321 return label;
aoqi@0 1322 } else if (doc instanceof ExecutableMemberDoc) {
aoqi@0 1323 ExecutableMemberDoc emd = (ExecutableMemberDoc) doc;
aoqi@0 1324 return getLink(new LinkInfoImpl(configuration, context, classDoc)
aoqi@0 1325 .label(label).where(getName(getAnchor(emd))));
aoqi@0 1326 } else if (doc instanceof MemberDoc) {
aoqi@0 1327 return getLink(new LinkInfoImpl(configuration, context, classDoc)
aoqi@0 1328 .label(label).where(getName(doc.name())));
aoqi@0 1329 } else {
aoqi@0 1330 return label;
aoqi@0 1331 }
aoqi@0 1332 }
aoqi@0 1333
aoqi@0 1334 public String getAnchor(ExecutableMemberDoc emd) {
aoqi@0 1335 return getAnchor(emd, false);
aoqi@0 1336 }
aoqi@0 1337
aoqi@0 1338 public String getAnchor(ExecutableMemberDoc emd, boolean isProperty) {
aoqi@0 1339 if (isProperty) {
aoqi@0 1340 return emd.name();
aoqi@0 1341 }
aoqi@0 1342 StringBuilder signature = new StringBuilder(emd.signature());
aoqi@0 1343 StringBuilder signatureParsed = new StringBuilder();
aoqi@0 1344 int counter = 0;
aoqi@0 1345 for (int i = 0; i < signature.length(); i++) {
aoqi@0 1346 char c = signature.charAt(i);
aoqi@0 1347 if (c == '<') {
aoqi@0 1348 counter++;
aoqi@0 1349 } else if (c == '>') {
aoqi@0 1350 counter--;
aoqi@0 1351 } else if (counter == 0) {
aoqi@0 1352 signatureParsed.append(c);
aoqi@0 1353 }
aoqi@0 1354 }
aoqi@0 1355 return emd.name() + signatureParsed.toString();
aoqi@0 1356 }
aoqi@0 1357
aoqi@0 1358 public Content seeTagToContent(SeeTag see) {
aoqi@0 1359 String tagName = see.name();
aoqi@0 1360 if (! (tagName.startsWith("@link") || tagName.equals("@see"))) {
aoqi@0 1361 return new ContentBuilder();
aoqi@0 1362 }
aoqi@0 1363
aoqi@0 1364 String seetext = replaceDocRootDir(Util.normalizeNewlines(see.text()));
aoqi@0 1365
aoqi@0 1366 //Check if @see is an href or "string"
aoqi@0 1367 if (seetext.startsWith("<") || seetext.startsWith("\"")) {
aoqi@0 1368 return new RawHtml(seetext);
aoqi@0 1369 }
aoqi@0 1370
aoqi@0 1371 boolean plain = tagName.equalsIgnoreCase("@linkplain");
aoqi@0 1372 Content label = plainOrCode(plain, new RawHtml(see.label()));
aoqi@0 1373
aoqi@0 1374 //The text from the @see tag. We will output this text when a label is not specified.
aoqi@0 1375 Content text = plainOrCode(plain, new RawHtml(seetext));
aoqi@0 1376
aoqi@0 1377 ClassDoc refClass = see.referencedClass();
aoqi@0 1378 String refClassName = see.referencedClassName();
aoqi@0 1379 MemberDoc refMem = see.referencedMember();
aoqi@0 1380 String refMemName = see.referencedMemberName();
aoqi@0 1381
aoqi@0 1382 if (refClass == null) {
aoqi@0 1383 //@see is not referencing an included class
aoqi@0 1384 PackageDoc refPackage = see.referencedPackage();
aoqi@0 1385 if (refPackage != null && refPackage.isIncluded()) {
aoqi@0 1386 //@see is referencing an included package
aoqi@0 1387 if (label.isEmpty())
aoqi@0 1388 label = plainOrCode(plain, new StringContent(refPackage.name()));
aoqi@0 1389 return getPackageLink(refPackage, label);
aoqi@0 1390 } else {
aoqi@0 1391 //@see is not referencing an included class or package. Check for cross links.
aoqi@0 1392 Content classCrossLink;
aoqi@0 1393 DocLink packageCrossLink = getCrossPackageLink(refClassName);
aoqi@0 1394 if (packageCrossLink != null) {
aoqi@0 1395 //Package cross link found
aoqi@0 1396 return getHyperLink(packageCrossLink,
aoqi@0 1397 (label.isEmpty() ? text : label));
aoqi@0 1398 } else if ((classCrossLink = getCrossClassLink(refClassName,
aoqi@0 1399 refMemName, label, false, "", !plain)) != null) {
aoqi@0 1400 //Class cross link found (possibly to a member in the class)
aoqi@0 1401 return classCrossLink;
aoqi@0 1402 } else {
aoqi@0 1403 //No cross link found so print warning
aoqi@0 1404 configuration.getDocletSpecificMsg().warning(see.position(), "doclet.see.class_or_package_not_found",
aoqi@0 1405 tagName, seetext);
aoqi@0 1406 return (label.isEmpty() ? text: label);
aoqi@0 1407 }
aoqi@0 1408 }
aoqi@0 1409 } else if (refMemName == null) {
aoqi@0 1410 // Must be a class reference since refClass is not null and refMemName is null.
aoqi@0 1411 if (label.isEmpty()) {
aoqi@0 1412 label = plainOrCode(plain, new StringContent(refClass.name()));
aoqi@0 1413 }
aoqi@0 1414 return getLink(new LinkInfoImpl(configuration, LinkInfoImpl.Kind.DEFAULT, refClass)
aoqi@0 1415 .label(label));
aoqi@0 1416 } else if (refMem == null) {
aoqi@0 1417 // Must be a member reference since refClass is not null and refMemName is not null.
aoqi@0 1418 // However, refMem is null, so this referenced member does not exist.
aoqi@0 1419 return (label.isEmpty() ? text: label);
aoqi@0 1420 } else {
aoqi@0 1421 // Must be a member reference since refClass is not null and refMemName is not null.
aoqi@0 1422 // refMem is not null, so this @see tag must be referencing a valid member.
aoqi@0 1423 ClassDoc containing = refMem.containingClass();
aoqi@0 1424 if (see.text().trim().startsWith("#") &&
aoqi@0 1425 ! (containing.isPublic() ||
aoqi@0 1426 Util.isLinkable(containing, configuration))) {
aoqi@0 1427 // Since the link is relative and the holder is not even being
aoqi@0 1428 // documented, this must be an inherited link. Redirect it.
aoqi@0 1429 // The current class either overrides the referenced member or
aoqi@0 1430 // inherits it automatically.
aoqi@0 1431 if (this instanceof ClassWriterImpl) {
aoqi@0 1432 containing = ((ClassWriterImpl) this).getClassDoc();
aoqi@0 1433 } else if (!containing.isPublic()){
aoqi@0 1434 configuration.getDocletSpecificMsg().warning(
aoqi@0 1435 see.position(), "doclet.see.class_or_package_not_accessible",
aoqi@0 1436 tagName, containing.qualifiedName());
aoqi@0 1437 } else {
aoqi@0 1438 configuration.getDocletSpecificMsg().warning(
aoqi@0 1439 see.position(), "doclet.see.class_or_package_not_found",
aoqi@0 1440 tagName, seetext);
aoqi@0 1441 }
aoqi@0 1442 }
aoqi@0 1443 if (configuration.currentcd != containing) {
aoqi@0 1444 refMemName = containing.name() + "." + refMemName;
aoqi@0 1445 }
aoqi@0 1446 if (refMem instanceof ExecutableMemberDoc) {
aoqi@0 1447 if (refMemName.indexOf('(') < 0) {
aoqi@0 1448 refMemName += ((ExecutableMemberDoc)refMem).signature();
aoqi@0 1449 }
aoqi@0 1450 }
aoqi@0 1451
aoqi@0 1452 text = plainOrCode(plain, new StringContent(refMemName));
aoqi@0 1453
aoqi@0 1454 return getDocLink(LinkInfoImpl.Kind.SEE_TAG, containing,
aoqi@0 1455 refMem, (label.isEmpty() ? text: label), false);
aoqi@0 1456 }
aoqi@0 1457 }
aoqi@0 1458
aoqi@0 1459 private Content plainOrCode(boolean plain, Content body) {
aoqi@0 1460 return (plain || body.isEmpty()) ? body : HtmlTree.CODE(body);
aoqi@0 1461 }
aoqi@0 1462
aoqi@0 1463 /**
aoqi@0 1464 * Add the inline comment.
aoqi@0 1465 *
aoqi@0 1466 * @param doc the doc for which the inline comment will be added
aoqi@0 1467 * @param tag the inline tag to be added
aoqi@0 1468 * @param htmltree the content tree to which the comment will be added
aoqi@0 1469 */
aoqi@0 1470 public void addInlineComment(Doc doc, Tag tag, Content htmltree) {
aoqi@0 1471 addCommentTags(doc, tag, tag.inlineTags(), false, false, htmltree);
aoqi@0 1472 }
aoqi@0 1473
aoqi@0 1474 /**
aoqi@0 1475 * Add the inline deprecated comment.
aoqi@0 1476 *
aoqi@0 1477 * @param doc the doc for which the inline deprecated comment will be added
aoqi@0 1478 * @param tag the inline tag to be added
aoqi@0 1479 * @param htmltree the content tree to which the comment will be added
aoqi@0 1480 */
aoqi@0 1481 public void addInlineDeprecatedComment(Doc doc, Tag tag, Content htmltree) {
aoqi@0 1482 addCommentTags(doc, tag.inlineTags(), true, false, htmltree);
aoqi@0 1483 }
aoqi@0 1484
aoqi@0 1485 /**
aoqi@0 1486 * Adds the summary content.
aoqi@0 1487 *
aoqi@0 1488 * @param doc the doc for which the summary will be generated
aoqi@0 1489 * @param htmltree the documentation tree to which the summary will be added
aoqi@0 1490 */
aoqi@0 1491 public void addSummaryComment(Doc doc, Content htmltree) {
aoqi@0 1492 addSummaryComment(doc, doc.firstSentenceTags(), htmltree);
aoqi@0 1493 }
aoqi@0 1494
aoqi@0 1495 /**
aoqi@0 1496 * Adds the summary content.
aoqi@0 1497 *
aoqi@0 1498 * @param doc the doc for which the summary will be generated
aoqi@0 1499 * @param firstSentenceTags the first sentence tags for the doc
aoqi@0 1500 * @param htmltree the documentation tree to which the summary will be added
aoqi@0 1501 */
aoqi@0 1502 public void addSummaryComment(Doc doc, Tag[] firstSentenceTags, Content htmltree) {
aoqi@0 1503 addCommentTags(doc, firstSentenceTags, false, true, htmltree);
aoqi@0 1504 }
aoqi@0 1505
aoqi@0 1506 public void addSummaryDeprecatedComment(Doc doc, Tag tag, Content htmltree) {
aoqi@0 1507 addCommentTags(doc, tag.firstSentenceTags(), true, true, htmltree);
aoqi@0 1508 }
aoqi@0 1509
aoqi@0 1510 /**
aoqi@0 1511 * Adds the inline comment.
aoqi@0 1512 *
aoqi@0 1513 * @param doc the doc for which the inline comments will be generated
aoqi@0 1514 * @param htmltree the documentation tree to which the inline comments will be added
aoqi@0 1515 */
aoqi@0 1516 public void addInlineComment(Doc doc, Content htmltree) {
aoqi@0 1517 addCommentTags(doc, doc.inlineTags(), false, false, htmltree);
aoqi@0 1518 }
aoqi@0 1519
aoqi@0 1520 /**
aoqi@0 1521 * Adds the comment tags.
aoqi@0 1522 *
aoqi@0 1523 * @param doc the doc for which the comment tags will be generated
aoqi@0 1524 * @param tags the first sentence tags for the doc
aoqi@0 1525 * @param depr true if it is deprecated
aoqi@0 1526 * @param first true if the first sentence tags should be added
aoqi@0 1527 * @param htmltree the documentation tree to which the comment tags will be added
aoqi@0 1528 */
aoqi@0 1529 private void addCommentTags(Doc doc, Tag[] tags, boolean depr,
aoqi@0 1530 boolean first, Content htmltree) {
aoqi@0 1531 addCommentTags(doc, null, tags, depr, first, htmltree);
aoqi@0 1532 }
aoqi@0 1533
aoqi@0 1534 /**
aoqi@0 1535 * Adds the comment tags.
aoqi@0 1536 *
aoqi@0 1537 * @param doc the doc for which the comment tags will be generated
aoqi@0 1538 * @param holderTag the block tag context for the inline tags
aoqi@0 1539 * @param tags the first sentence tags for the doc
aoqi@0 1540 * @param depr true if it is deprecated
aoqi@0 1541 * @param first true if the first sentence tags should be added
aoqi@0 1542 * @param htmltree the documentation tree to which the comment tags will be added
aoqi@0 1543 */
aoqi@0 1544 private void addCommentTags(Doc doc, Tag holderTag, Tag[] tags, boolean depr,
aoqi@0 1545 boolean first, Content htmltree) {
aoqi@0 1546 if(configuration.nocomment){
aoqi@0 1547 return;
aoqi@0 1548 }
aoqi@0 1549 Content div;
aoqi@0 1550 Content result = commentTagsToContent(null, doc, tags, first);
aoqi@0 1551 if (depr) {
aoqi@0 1552 Content italic = HtmlTree.SPAN(HtmlStyle.deprecationComment, result);
aoqi@0 1553 div = HtmlTree.DIV(HtmlStyle.block, italic);
aoqi@0 1554 htmltree.addContent(div);
aoqi@0 1555 }
aoqi@0 1556 else {
aoqi@0 1557 div = HtmlTree.DIV(HtmlStyle.block, result);
aoqi@0 1558 htmltree.addContent(div);
aoqi@0 1559 }
aoqi@0 1560 if (tags.length == 0) {
aoqi@0 1561 htmltree.addContent(getSpace());
aoqi@0 1562 }
aoqi@0 1563 }
aoqi@0 1564
aoqi@0 1565 /**
aoqi@0 1566 * Converts inline tags and text to text strings, expanding the
aoqi@0 1567 * inline tags along the way. Called wherever text can contain
aoqi@0 1568 * an inline tag, such as in comments or in free-form text arguments
aoqi@0 1569 * to non-inline tags.
aoqi@0 1570 *
aoqi@0 1571 * @param holderTag specific tag where comment resides
aoqi@0 1572 * @param doc specific doc where comment resides
aoqi@0 1573 * @param tags array of text tags and inline tags (often alternating)
aoqi@0 1574 * present in the text of interest for this doc
aoqi@0 1575 * @param isFirstSentence true if text is first sentence
aoqi@0 1576 */
aoqi@0 1577 public Content commentTagsToContent(Tag holderTag, Doc doc, Tag[] tags,
aoqi@0 1578 boolean isFirstSentence) {
aoqi@0 1579 Content result = new ContentBuilder();
aoqi@0 1580 boolean textTagChange = false;
aoqi@0 1581 // Array of all possible inline tags for this javadoc run
aoqi@0 1582 configuration.tagletManager.checkTags(doc, tags, true);
aoqi@0 1583 for (int i = 0; i < tags.length; i++) {
aoqi@0 1584 Tag tagelem = tags[i];
aoqi@0 1585 String tagName = tagelem.name();
aoqi@0 1586 if (tagelem instanceof SeeTag) {
aoqi@0 1587 result.addContent(seeTagToContent((SeeTag) tagelem));
aoqi@0 1588 } else if (! tagName.equals("Text")) {
aoqi@0 1589 boolean wasEmpty = result.isEmpty();
aoqi@0 1590 Content output;
aoqi@0 1591 if (configuration.docrootparent.length() > 0
aoqi@0 1592 && tagelem.name().equals("@docRoot")
aoqi@0 1593 && ((tags[i + 1]).text()).startsWith("/..")) {
aoqi@0 1594 // If Xdocrootparent switch ON, set the flag to remove the /.. occurrence after
aoqi@0 1595 // {@docRoot} tag in the very next Text tag.
aoqi@0 1596 textTagChange = true;
aoqi@0 1597 // Replace the occurrence of {@docRoot}/.. with the absolute link.
aoqi@0 1598 output = new StringContent(configuration.docrootparent);
aoqi@0 1599 } else {
aoqi@0 1600 output = TagletWriter.getInlineTagOuput(
aoqi@0 1601 configuration.tagletManager, holderTag,
aoqi@0 1602 tagelem, getTagletWriterInstance(isFirstSentence));
aoqi@0 1603 }
aoqi@0 1604 if (output != null)
aoqi@0 1605 result.addContent(output);
aoqi@0 1606 if (wasEmpty && isFirstSentence && tagelem.name().equals("@inheritDoc") && !result.isEmpty()) {
aoqi@0 1607 break;
aoqi@0 1608 } else {
aoqi@0 1609 continue;
aoqi@0 1610 }
aoqi@0 1611 } else {
aoqi@0 1612 String text = tagelem.text();
aoqi@0 1613 //If Xdocrootparent switch ON, remove the /.. occurrence after {@docRoot} tag.
aoqi@0 1614 if (textTagChange) {
aoqi@0 1615 text = text.replaceFirst("/..", "");
aoqi@0 1616 textTagChange = false;
aoqi@0 1617 }
aoqi@0 1618 //This is just a regular text tag. The text may contain html links (<a>)
aoqi@0 1619 //or inline tag {@docRoot}, which will be handled as special cases.
aoqi@0 1620 text = redirectRelativeLinks(tagelem.holder(), text);
aoqi@0 1621
aoqi@0 1622 // Replace @docRoot only if not represented by an instance of DocRootTaglet,
aoqi@0 1623 // that is, only if it was not present in a source file doc comment.
aoqi@0 1624 // This happens when inserted by the doclet (a few lines
aoqi@0 1625 // above in this method). [It might also happen when passed in on the command
aoqi@0 1626 // line as a text argument to an option (like -header).]
aoqi@0 1627 text = replaceDocRootDir(text);
aoqi@0 1628 if (isFirstSentence) {
aoqi@0 1629 text = removeNonInlineHtmlTags(text);
aoqi@0 1630 }
aoqi@0 1631 text = Util.replaceTabs(configuration, text);
aoqi@0 1632 text = Util.normalizeNewlines(text);
aoqi@0 1633 result.addContent(new RawHtml(text));
aoqi@0 1634 }
aoqi@0 1635 }
aoqi@0 1636 return result;
aoqi@0 1637 }
aoqi@0 1638
aoqi@0 1639 /**
aoqi@0 1640 * Return true if relative links should not be redirected.
aoqi@0 1641 *
aoqi@0 1642 * @return Return true if a relative link should not be redirected.
aoqi@0 1643 */
aoqi@0 1644 private boolean shouldNotRedirectRelativeLinks() {
aoqi@0 1645 return this instanceof AnnotationTypeWriter ||
aoqi@0 1646 this instanceof ClassWriter ||
aoqi@0 1647 this instanceof PackageSummaryWriter;
aoqi@0 1648 }
aoqi@0 1649
aoqi@0 1650 /**
aoqi@0 1651 * Suppose a piece of documentation has a relative link. When you copy
aoqi@0 1652 * that documentation to another place such as the index or class-use page,
aoqi@0 1653 * that relative link will no longer work. We should redirect those links
aoqi@0 1654 * so that they will work again.
aoqi@0 1655 * <p>
aoqi@0 1656 * Here is the algorithm used to fix the link:
aoqi@0 1657 * <p>
aoqi@0 1658 * {@literal <relative link> => docRoot + <relative path to file> + <relative link> }
aoqi@0 1659 * <p>
aoqi@0 1660 * For example, suppose com.sun.javadoc.RootDoc has this link:
aoqi@0 1661 * {@literal <a href="package-summary.html">The package Page</a> }
aoqi@0 1662 * <p>
aoqi@0 1663 * If this link appeared in the index, we would redirect
aoqi@0 1664 * the link like this:
aoqi@0 1665 *
aoqi@0 1666 * {@literal <a href="./com/sun/javadoc/package-summary.html">The package Page</a>}
aoqi@0 1667 *
aoqi@0 1668 * @param doc the Doc object whose documentation is being written.
aoqi@0 1669 * @param text the text being written.
aoqi@0 1670 *
aoqi@0 1671 * @return the text, with all the relative links redirected to work.
aoqi@0 1672 */
aoqi@0 1673 private String redirectRelativeLinks(Doc doc, String text) {
aoqi@0 1674 if (doc == null || shouldNotRedirectRelativeLinks()) {
aoqi@0 1675 return text;
aoqi@0 1676 }
aoqi@0 1677
aoqi@0 1678 DocPath redirectPathFromRoot;
aoqi@0 1679 if (doc instanceof ClassDoc) {
aoqi@0 1680 redirectPathFromRoot = DocPath.forPackage(((ClassDoc) doc).containingPackage());
aoqi@0 1681 } else if (doc instanceof MemberDoc) {
aoqi@0 1682 redirectPathFromRoot = DocPath.forPackage(((MemberDoc) doc).containingPackage());
aoqi@0 1683 } else if (doc instanceof PackageDoc) {
aoqi@0 1684 redirectPathFromRoot = DocPath.forPackage((PackageDoc) doc);
aoqi@0 1685 } else {
aoqi@0 1686 return text;
aoqi@0 1687 }
aoqi@0 1688
aoqi@0 1689 //Redirect all relative links.
aoqi@0 1690 int end, begin = StringUtils.indexOfIgnoreCase(text, "<a");
aoqi@0 1691 if(begin >= 0){
aoqi@0 1692 StringBuilder textBuff = new StringBuilder(text);
aoqi@0 1693
aoqi@0 1694 while(begin >=0){
aoqi@0 1695 if (textBuff.length() > begin + 2 && ! Character.isWhitespace(textBuff.charAt(begin+2))) {
aoqi@0 1696 begin = StringUtils.indexOfIgnoreCase(textBuff.toString(), "<a", begin + 1);
aoqi@0 1697 continue;
aoqi@0 1698 }
aoqi@0 1699
aoqi@0 1700 begin = textBuff.indexOf("=", begin) + 1;
aoqi@0 1701 end = textBuff.indexOf(">", begin +1);
aoqi@0 1702 if(begin == 0){
aoqi@0 1703 //Link has no equal symbol.
aoqi@0 1704 configuration.root.printWarning(
aoqi@0 1705 doc.position(),
aoqi@0 1706 configuration.getText("doclet.malformed_html_link_tag", text));
aoqi@0 1707 break;
aoqi@0 1708 }
aoqi@0 1709 if (end == -1) {
aoqi@0 1710 //Break without warning. This <a> tag is not necessarily malformed. The text
aoqi@0 1711 //might be missing '>' character because the href has an inline tag.
aoqi@0 1712 break;
aoqi@0 1713 }
aoqi@0 1714 if (textBuff.substring(begin, end).indexOf("\"") != -1){
aoqi@0 1715 begin = textBuff.indexOf("\"", begin) + 1;
aoqi@0 1716 end = textBuff.indexOf("\"", begin +1);
aoqi@0 1717 if (begin == 0 || end == -1){
aoqi@0 1718 //Link is missing a quote.
aoqi@0 1719 break;
aoqi@0 1720 }
aoqi@0 1721 }
aoqi@0 1722 String relativeLink = textBuff.substring(begin, end);
aoqi@0 1723 String relativeLinkLowerCase = StringUtils.toLowerCase(relativeLink);
aoqi@0 1724 if (!(relativeLinkLowerCase.startsWith("mailto:") ||
aoqi@0 1725 relativeLinkLowerCase.startsWith("http:") ||
aoqi@0 1726 relativeLinkLowerCase.startsWith("https:") ||
aoqi@0 1727 relativeLinkLowerCase.startsWith("file:"))) {
aoqi@0 1728 relativeLink = "{@"+(new DocRootTaglet()).getName() + "}/"
aoqi@0 1729 + redirectPathFromRoot.resolve(relativeLink).getPath();
aoqi@0 1730 textBuff.replace(begin, end, relativeLink);
aoqi@0 1731 }
aoqi@0 1732 begin = StringUtils.indexOfIgnoreCase(textBuff.toString(), "<a", begin + 1);
aoqi@0 1733 }
aoqi@0 1734 return textBuff.toString();
aoqi@0 1735 }
aoqi@0 1736 return text;
aoqi@0 1737 }
aoqi@0 1738
aoqi@0 1739 static final Set<String> blockTags = new HashSet<String>();
aoqi@0 1740 static {
aoqi@0 1741 for (HtmlTag t: HtmlTag.values()) {
aoqi@0 1742 if (t.blockType == HtmlTag.BlockType.BLOCK)
aoqi@0 1743 blockTags.add(t.value);
aoqi@0 1744 }
aoqi@0 1745 }
aoqi@0 1746
aoqi@0 1747 public static String removeNonInlineHtmlTags(String text) {
aoqi@0 1748 final int len = text.length();
aoqi@0 1749
aoqi@0 1750 int startPos = 0; // start of text to copy
aoqi@0 1751 int lessThanPos = text.indexOf('<'); // position of latest '<'
aoqi@0 1752 if (lessThanPos < 0) {
aoqi@0 1753 return text;
aoqi@0 1754 }
aoqi@0 1755
aoqi@0 1756 StringBuilder result = new StringBuilder();
aoqi@0 1757 main: while (lessThanPos != -1) {
aoqi@0 1758 int currPos = lessThanPos + 1;
aoqi@0 1759 if (currPos == len)
aoqi@0 1760 break;
aoqi@0 1761 char ch = text.charAt(currPos);
aoqi@0 1762 if (ch == '/') {
aoqi@0 1763 if (++currPos == len)
aoqi@0 1764 break;
aoqi@0 1765 ch = text.charAt(currPos);
aoqi@0 1766 }
aoqi@0 1767 int tagPos = currPos;
aoqi@0 1768 while (isHtmlTagLetterOrDigit(ch)) {
aoqi@0 1769 if (++currPos == len)
aoqi@0 1770 break main;
aoqi@0 1771 ch = text.charAt(currPos);
aoqi@0 1772 }
aoqi@0 1773 if (ch == '>' && blockTags.contains(StringUtils.toLowerCase(text.substring(tagPos, currPos)))) {
aoqi@0 1774 result.append(text, startPos, lessThanPos);
aoqi@0 1775 startPos = currPos + 1;
aoqi@0 1776 }
aoqi@0 1777 lessThanPos = text.indexOf('<', currPos);
aoqi@0 1778 }
aoqi@0 1779 result.append(text.substring(startPos));
aoqi@0 1780
aoqi@0 1781 return result.toString();
aoqi@0 1782 }
aoqi@0 1783
aoqi@0 1784 private static boolean isHtmlTagLetterOrDigit(char ch) {
aoqi@0 1785 return ('a' <= ch && ch <= 'z') ||
aoqi@0 1786 ('A' <= ch && ch <= 'Z') ||
aoqi@0 1787 ('1' <= ch && ch <= '6');
aoqi@0 1788 }
aoqi@0 1789
aoqi@0 1790 /**
aoqi@0 1791 * Returns a link to the stylesheet file.
aoqi@0 1792 *
aoqi@0 1793 * @return an HtmlTree for the lINK tag which provides the stylesheet location
aoqi@0 1794 */
aoqi@0 1795 public HtmlTree getStyleSheetProperties() {
aoqi@0 1796 String stylesheetfile = configuration.stylesheetfile;
aoqi@0 1797 DocPath stylesheet;
aoqi@0 1798 if (stylesheetfile.isEmpty()) {
aoqi@0 1799 stylesheet = DocPaths.STYLESHEET;
aoqi@0 1800 } else {
aoqi@0 1801 DocFile file = DocFile.createFileForInput(configuration, stylesheetfile);
aoqi@0 1802 stylesheet = DocPath.create(file.getName());
aoqi@0 1803 }
aoqi@0 1804 HtmlTree link = HtmlTree.LINK("stylesheet", "text/css",
aoqi@0 1805 pathToRoot.resolve(stylesheet).getPath(),
aoqi@0 1806 "Style");
aoqi@0 1807 return link;
aoqi@0 1808 }
aoqi@0 1809
aoqi@0 1810 /**
aoqi@0 1811 * Returns a link to the JavaScript file.
aoqi@0 1812 *
aoqi@0 1813 * @return an HtmlTree for the Script tag which provides the JavaScript location
aoqi@0 1814 */
aoqi@0 1815 public HtmlTree getScriptProperties() {
aoqi@0 1816 HtmlTree script = HtmlTree.SCRIPT("text/javascript",
aoqi@0 1817 pathToRoot.resolve(DocPaths.JAVASCRIPT).getPath());
aoqi@0 1818 return script;
aoqi@0 1819 }
aoqi@0 1820
aoqi@0 1821 /**
aoqi@0 1822 * According to
aoqi@0 1823 * <cite>The Java&trade; Language Specification</cite>,
aoqi@0 1824 * all the outer classes and static nested classes are core classes.
aoqi@0 1825 */
aoqi@0 1826 public boolean isCoreClass(ClassDoc cd) {
aoqi@0 1827 return cd.containingClass() == null || cd.isStatic();
aoqi@0 1828 }
aoqi@0 1829
aoqi@0 1830 /**
aoqi@0 1831 * Adds the annotatation types for the given packageDoc.
aoqi@0 1832 *
aoqi@0 1833 * @param packageDoc the package to write annotations for.
aoqi@0 1834 * @param htmltree the documentation tree to which the annotation info will be
aoqi@0 1835 * added
aoqi@0 1836 */
aoqi@0 1837 public void addAnnotationInfo(PackageDoc packageDoc, Content htmltree) {
aoqi@0 1838 addAnnotationInfo(packageDoc, packageDoc.annotations(), htmltree);
aoqi@0 1839 }
aoqi@0 1840
aoqi@0 1841 /**
aoqi@0 1842 * Add the annotation types of the executable receiver.
aoqi@0 1843 *
aoqi@0 1844 * @param method the executable to write the receiver annotations for.
aoqi@0 1845 * @param descList list of annotation description.
aoqi@0 1846 * @param htmltree the documentation tree to which the annotation info will be
aoqi@0 1847 * added
aoqi@0 1848 */
aoqi@0 1849 public void addReceiverAnnotationInfo(ExecutableMemberDoc method, AnnotationDesc[] descList,
aoqi@0 1850 Content htmltree) {
aoqi@0 1851 addAnnotationInfo(0, method, descList, false, htmltree);
aoqi@0 1852 }
aoqi@0 1853
aoqi@0 1854 /**
aoqi@0 1855 * Adds the annotatation types for the given doc.
aoqi@0 1856 *
aoqi@0 1857 * @param doc the package to write annotations for
aoqi@0 1858 * @param htmltree the content tree to which the annotation types will be added
aoqi@0 1859 */
aoqi@0 1860 public void addAnnotationInfo(ProgramElementDoc doc, Content htmltree) {
aoqi@0 1861 addAnnotationInfo(doc, doc.annotations(), htmltree);
aoqi@0 1862 }
aoqi@0 1863
aoqi@0 1864 /**
aoqi@0 1865 * Add the annotatation types for the given doc and parameter.
aoqi@0 1866 *
aoqi@0 1867 * @param indent the number of spaces to indent the parameters.
aoqi@0 1868 * @param doc the doc to write annotations for.
aoqi@0 1869 * @param param the parameter to write annotations for.
aoqi@0 1870 * @param tree the content tree to which the annotation types will be added
aoqi@0 1871 */
aoqi@0 1872 public boolean addAnnotationInfo(int indent, Doc doc, Parameter param,
aoqi@0 1873 Content tree) {
aoqi@0 1874 return addAnnotationInfo(indent, doc, param.annotations(), false, tree);
aoqi@0 1875 }
aoqi@0 1876
aoqi@0 1877 /**
aoqi@0 1878 * Adds the annotatation types for the given doc.
aoqi@0 1879 *
aoqi@0 1880 * @param doc the doc to write annotations for.
aoqi@0 1881 * @param descList the array of {@link AnnotationDesc}.
aoqi@0 1882 * @param htmltree the documentation tree to which the annotation info will be
aoqi@0 1883 * added
aoqi@0 1884 */
aoqi@0 1885 private void addAnnotationInfo(Doc doc, AnnotationDesc[] descList,
aoqi@0 1886 Content htmltree) {
aoqi@0 1887 addAnnotationInfo(0, doc, descList, true, htmltree);
aoqi@0 1888 }
aoqi@0 1889
aoqi@0 1890 /**
aoqi@0 1891 * Adds the annotation types for the given doc.
aoqi@0 1892 *
aoqi@0 1893 * @param indent the number of extra spaces to indent the annotations.
aoqi@0 1894 * @param doc the doc to write annotations for.
aoqi@0 1895 * @param descList the array of {@link AnnotationDesc}.
aoqi@0 1896 * @param htmltree the documentation tree to which the annotation info will be
aoqi@0 1897 * added
aoqi@0 1898 */
aoqi@0 1899 private boolean addAnnotationInfo(int indent, Doc doc,
aoqi@0 1900 AnnotationDesc[] descList, boolean lineBreak, Content htmltree) {
aoqi@0 1901 List<Content> annotations = getAnnotations(indent, descList, lineBreak);
aoqi@0 1902 String sep ="";
aoqi@0 1903 if (annotations.isEmpty()) {
aoqi@0 1904 return false;
aoqi@0 1905 }
aoqi@0 1906 for (Content annotation: annotations) {
aoqi@0 1907 htmltree.addContent(sep);
aoqi@0 1908 htmltree.addContent(annotation);
aoqi@0 1909 sep = " ";
aoqi@0 1910 }
aoqi@0 1911 return true;
aoqi@0 1912 }
aoqi@0 1913
aoqi@0 1914 /**
aoqi@0 1915 * Return the string representations of the annotation types for
aoqi@0 1916 * the given doc.
aoqi@0 1917 *
aoqi@0 1918 * @param indent the number of extra spaces to indent the annotations.
aoqi@0 1919 * @param descList the array of {@link AnnotationDesc}.
aoqi@0 1920 * @param linkBreak if true, add new line between each member value.
aoqi@0 1921 * @return an array of strings representing the annotations being
aoqi@0 1922 * documented.
aoqi@0 1923 */
aoqi@0 1924 private List<Content> getAnnotations(int indent, AnnotationDesc[] descList, boolean linkBreak) {
aoqi@0 1925 return getAnnotations(indent, descList, linkBreak, true);
aoqi@0 1926 }
aoqi@0 1927
aoqi@0 1928 /**
aoqi@0 1929 * Return the string representations of the annotation types for
aoqi@0 1930 * the given doc.
aoqi@0 1931 *
aoqi@0 1932 * A {@code null} {@code elementType} indicates that all the
aoqi@0 1933 * annotations should be returned without any filtering.
aoqi@0 1934 *
aoqi@0 1935 * @param indent the number of extra spaces to indent the annotations.
aoqi@0 1936 * @param descList the array of {@link AnnotationDesc}.
aoqi@0 1937 * @param linkBreak if true, add new line between each member value.
aoqi@0 1938 * @param elementType the type of targeted element (used for filtering
aoqi@0 1939 * type annotations from declaration annotations)
aoqi@0 1940 * @return an array of strings representing the annotations being
aoqi@0 1941 * documented.
aoqi@0 1942 */
aoqi@0 1943 public List<Content> getAnnotations(int indent, AnnotationDesc[] descList, boolean linkBreak,
aoqi@0 1944 boolean isJava5DeclarationLocation) {
aoqi@0 1945 List<Content> results = new ArrayList<Content>();
aoqi@0 1946 ContentBuilder annotation;
aoqi@0 1947 for (int i = 0; i < descList.length; i++) {
aoqi@0 1948 AnnotationTypeDoc annotationDoc = descList[i].annotationType();
aoqi@0 1949 // If an annotation is not documented, do not add it to the list. If
aoqi@0 1950 // the annotation is of a repeatable type, and if it is not documented
aoqi@0 1951 // and also if its container annotation is not documented, do not add it
aoqi@0 1952 // to the list. If an annotation of a repeatable type is not documented
aoqi@0 1953 // but its container is documented, it will be added to the list.
aoqi@0 1954 if (! Util.isDocumentedAnnotation(annotationDoc) &&
aoqi@0 1955 (!isAnnotationDocumented && !isContainerDocumented)) {
aoqi@0 1956 continue;
aoqi@0 1957 }
aoqi@0 1958 /* TODO: check logic here to correctly handle declaration
aoqi@0 1959 * and type annotations.
aoqi@0 1960 if (Util.isDeclarationAnnotation(annotationDoc, isJava5DeclarationLocation)) {
aoqi@0 1961 continue;
aoqi@0 1962 }*/
aoqi@0 1963 annotation = new ContentBuilder();
aoqi@0 1964 isAnnotationDocumented = false;
aoqi@0 1965 LinkInfoImpl linkInfo = new LinkInfoImpl(configuration,
aoqi@0 1966 LinkInfoImpl.Kind.ANNOTATION, annotationDoc);
aoqi@0 1967 AnnotationDesc.ElementValuePair[] pairs = descList[i].elementValues();
aoqi@0 1968 // If the annotation is synthesized, do not print the container.
aoqi@0 1969 if (descList[i].isSynthesized()) {
aoqi@0 1970 for (int j = 0; j < pairs.length; j++) {
aoqi@0 1971 AnnotationValue annotationValue = pairs[j].value();
aoqi@0 1972 List<AnnotationValue> annotationTypeValues = new ArrayList<AnnotationValue>();
aoqi@0 1973 if (annotationValue.value() instanceof AnnotationValue[]) {
aoqi@0 1974 AnnotationValue[] annotationArray =
aoqi@0 1975 (AnnotationValue[]) annotationValue.value();
aoqi@0 1976 annotationTypeValues.addAll(Arrays.asList(annotationArray));
aoqi@0 1977 } else {
aoqi@0 1978 annotationTypeValues.add(annotationValue);
aoqi@0 1979 }
aoqi@0 1980 String sep = "";
aoqi@0 1981 for (AnnotationValue av : annotationTypeValues) {
aoqi@0 1982 annotation.addContent(sep);
aoqi@0 1983 annotation.addContent(annotationValueToContent(av));
aoqi@0 1984 sep = " ";
aoqi@0 1985 }
aoqi@0 1986 }
aoqi@0 1987 }
aoqi@0 1988 else if (isAnnotationArray(pairs)) {
aoqi@0 1989 // If the container has 1 or more value defined and if the
aoqi@0 1990 // repeatable type annotation is not documented, do not print
aoqi@0 1991 // the container.
aoqi@0 1992 if (pairs.length == 1 && isAnnotationDocumented) {
aoqi@0 1993 AnnotationValue[] annotationArray =
aoqi@0 1994 (AnnotationValue[]) (pairs[0].value()).value();
aoqi@0 1995 List<AnnotationValue> annotationTypeValues = new ArrayList<AnnotationValue>();
aoqi@0 1996 annotationTypeValues.addAll(Arrays.asList(annotationArray));
aoqi@0 1997 String sep = "";
aoqi@0 1998 for (AnnotationValue av : annotationTypeValues) {
aoqi@0 1999 annotation.addContent(sep);
aoqi@0 2000 annotation.addContent(annotationValueToContent(av));
aoqi@0 2001 sep = " ";
aoqi@0 2002 }
aoqi@0 2003 }
aoqi@0 2004 // If the container has 1 or more value defined and if the
aoqi@0 2005 // repeatable type annotation is not documented, print the container.
aoqi@0 2006 else {
aoqi@0 2007 addAnnotations(annotationDoc, linkInfo, annotation, pairs,
aoqi@0 2008 indent, false);
aoqi@0 2009 }
aoqi@0 2010 }
aoqi@0 2011 else {
aoqi@0 2012 addAnnotations(annotationDoc, linkInfo, annotation, pairs,
aoqi@0 2013 indent, linkBreak);
aoqi@0 2014 }
aoqi@0 2015 annotation.addContent(linkBreak ? DocletConstants.NL : "");
aoqi@0 2016 results.add(annotation);
aoqi@0 2017 }
aoqi@0 2018 return results;
aoqi@0 2019 }
aoqi@0 2020
aoqi@0 2021 /**
aoqi@0 2022 * Add annotation to the annotation string.
aoqi@0 2023 *
aoqi@0 2024 * @param annotationDoc the annotation being documented
aoqi@0 2025 * @param linkInfo the information about the link
aoqi@0 2026 * @param annotation the annotation string to which the annotation will be added
aoqi@0 2027 * @param pairs annotation type element and value pairs
aoqi@0 2028 * @param indent the number of extra spaces to indent the annotations.
aoqi@0 2029 * @param linkBreak if true, add new line between each member value
aoqi@0 2030 */
aoqi@0 2031 private void addAnnotations(AnnotationTypeDoc annotationDoc, LinkInfoImpl linkInfo,
aoqi@0 2032 ContentBuilder annotation, AnnotationDesc.ElementValuePair[] pairs,
aoqi@0 2033 int indent, boolean linkBreak) {
aoqi@0 2034 linkInfo.label = new StringContent("@" + annotationDoc.name());
aoqi@0 2035 annotation.addContent(getLink(linkInfo));
aoqi@0 2036 if (pairs.length > 0) {
aoqi@0 2037 annotation.addContent("(");
aoqi@0 2038 for (int j = 0; j < pairs.length; j++) {
aoqi@0 2039 if (j > 0) {
aoqi@0 2040 annotation.addContent(",");
aoqi@0 2041 if (linkBreak) {
aoqi@0 2042 annotation.addContent(DocletConstants.NL);
aoqi@0 2043 int spaces = annotationDoc.name().length() + 2;
aoqi@0 2044 for (int k = 0; k < (spaces + indent); k++) {
aoqi@0 2045 annotation.addContent(" ");
aoqi@0 2046 }
aoqi@0 2047 }
aoqi@0 2048 }
aoqi@0 2049 annotation.addContent(getDocLink(LinkInfoImpl.Kind.ANNOTATION,
aoqi@0 2050 pairs[j].element(), pairs[j].element().name(), false));
aoqi@0 2051 annotation.addContent("=");
aoqi@0 2052 AnnotationValue annotationValue = pairs[j].value();
aoqi@0 2053 List<AnnotationValue> annotationTypeValues = new ArrayList<AnnotationValue>();
aoqi@0 2054 if (annotationValue.value() instanceof AnnotationValue[]) {
aoqi@0 2055 AnnotationValue[] annotationArray =
aoqi@0 2056 (AnnotationValue[]) annotationValue.value();
aoqi@0 2057 annotationTypeValues.addAll(Arrays.asList(annotationArray));
aoqi@0 2058 } else {
aoqi@0 2059 annotationTypeValues.add(annotationValue);
aoqi@0 2060 }
aoqi@0 2061 annotation.addContent(annotationTypeValues.size() == 1 ? "" : "{");
aoqi@0 2062 String sep = "";
aoqi@0 2063 for (AnnotationValue av : annotationTypeValues) {
aoqi@0 2064 annotation.addContent(sep);
aoqi@0 2065 annotation.addContent(annotationValueToContent(av));
aoqi@0 2066 sep = ",";
aoqi@0 2067 }
aoqi@0 2068 annotation.addContent(annotationTypeValues.size() == 1 ? "" : "}");
aoqi@0 2069 isContainerDocumented = false;
aoqi@0 2070 }
aoqi@0 2071 annotation.addContent(")");
aoqi@0 2072 }
aoqi@0 2073 }
aoqi@0 2074
aoqi@0 2075 /**
aoqi@0 2076 * Check if the annotation contains an array of annotation as a value. This
aoqi@0 2077 * check is to verify if a repeatable type annotation is present or not.
aoqi@0 2078 *
aoqi@0 2079 * @param pairs annotation type element and value pairs
aoqi@0 2080 *
aoqi@0 2081 * @return true if the annotation contains an array of annotation as a value.
aoqi@0 2082 */
aoqi@0 2083 private boolean isAnnotationArray(AnnotationDesc.ElementValuePair[] pairs) {
aoqi@0 2084 AnnotationValue annotationValue;
aoqi@0 2085 for (int j = 0; j < pairs.length; j++) {
aoqi@0 2086 annotationValue = pairs[j].value();
aoqi@0 2087 if (annotationValue.value() instanceof AnnotationValue[]) {
aoqi@0 2088 AnnotationValue[] annotationArray =
aoqi@0 2089 (AnnotationValue[]) annotationValue.value();
aoqi@0 2090 if (annotationArray.length > 1) {
aoqi@0 2091 if (annotationArray[0].value() instanceof AnnotationDesc) {
aoqi@0 2092 AnnotationTypeDoc annotationDoc =
aoqi@0 2093 ((AnnotationDesc) annotationArray[0].value()).annotationType();
aoqi@0 2094 isContainerDocumented = true;
aoqi@0 2095 if (Util.isDocumentedAnnotation(annotationDoc)) {
aoqi@0 2096 isAnnotationDocumented = true;
aoqi@0 2097 }
aoqi@0 2098 return true;
aoqi@0 2099 }
aoqi@0 2100 }
aoqi@0 2101 }
aoqi@0 2102 }
aoqi@0 2103 return false;
aoqi@0 2104 }
aoqi@0 2105
aoqi@0 2106 private Content annotationValueToContent(AnnotationValue annotationValue) {
aoqi@0 2107 if (annotationValue.value() instanceof Type) {
aoqi@0 2108 Type type = (Type) annotationValue.value();
aoqi@0 2109 if (type.asClassDoc() != null) {
aoqi@0 2110 LinkInfoImpl linkInfo = new LinkInfoImpl(configuration,
aoqi@0 2111 LinkInfoImpl.Kind.ANNOTATION, type);
aoqi@0 2112 linkInfo.label = new StringContent((type.asClassDoc().isIncluded() ?
aoqi@0 2113 type.typeName() :
aoqi@0 2114 type.qualifiedTypeName()) + type.dimension() + ".class");
aoqi@0 2115 return getLink(linkInfo);
aoqi@0 2116 } else {
aoqi@0 2117 return new StringContent(type.typeName() + type.dimension() + ".class");
aoqi@0 2118 }
aoqi@0 2119 } else if (annotationValue.value() instanceof AnnotationDesc) {
aoqi@0 2120 List<Content> list = getAnnotations(0,
aoqi@0 2121 new AnnotationDesc[]{(AnnotationDesc) annotationValue.value()},
aoqi@0 2122 false);
aoqi@0 2123 ContentBuilder buf = new ContentBuilder();
aoqi@0 2124 for (Content c: list) {
aoqi@0 2125 buf.addContent(c);
aoqi@0 2126 }
aoqi@0 2127 return buf;
aoqi@0 2128 } else if (annotationValue.value() instanceof MemberDoc) {
aoqi@0 2129 return getDocLink(LinkInfoImpl.Kind.ANNOTATION,
aoqi@0 2130 (MemberDoc) annotationValue.value(),
aoqi@0 2131 ((MemberDoc) annotationValue.value()).name(), false);
aoqi@0 2132 } else {
aoqi@0 2133 return new StringContent(annotationValue.toString());
aoqi@0 2134 }
aoqi@0 2135 }
aoqi@0 2136
aoqi@0 2137 /**
aoqi@0 2138 * Return the configuation for this doclet.
aoqi@0 2139 *
aoqi@0 2140 * @return the configuration for this doclet.
aoqi@0 2141 */
aoqi@0 2142 public Configuration configuration() {
aoqi@0 2143 return configuration;
aoqi@0 2144 }
aoqi@0 2145 }

mercurial