Mon, 02 May 2011 02:13:02 -0700
6492694: @deprecated tag doesn't work in package-info files.
Reviewed-by: jjg
1 /*
2 * Copyright (c) 1998, 2011, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation. Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
26 package com.sun.tools.doclets.formats.html;
28 import java.io.*;
29 import java.text.SimpleDateFormat;
30 import java.util.*;
32 import com.sun.javadoc.*;
33 import com.sun.tools.doclets.formats.html.markup.*;
34 import com.sun.tools.doclets.internal.toolkit.*;
35 import com.sun.tools.doclets.internal.toolkit.util.*;
36 import com.sun.tools.doclets.internal.toolkit.taglets.*;
38 /**
39 * Class for the Html Format Code Generation specific to JavaDoc.
40 * This Class contains methods related to the Html Code Generation which
41 * are used extensively while generating the entire documentation.
42 *
43 * @since 1.2
44 * @author Atul M Dambalkar
45 * @author Robert Field
46 * @author Bhavesh Patel (Modified)
47 */
48 public class HtmlDocletWriter extends HtmlDocWriter {
50 /**
51 * Relative path from the file getting generated to the destination
52 * directory. For example, if the file getting generated is
53 * "java/lang/Object.html", then the relative path string is "../../".
54 * This string can be empty if the file getting generated is in
55 * the destination directory.
56 */
57 public String relativePath = "";
59 /**
60 * Same as relativepath, but normalized to never be empty or
61 * end with a slash.
62 */
63 public String relativepathNoSlash = "";
65 /**
66 * Platform-dependent directory path from the current or the
67 * destination directory to the file getting generated.
68 * Used when creating the file.
69 * For example, if the file getting generated is
70 * "java/lang/Object.html", then the path string is "java/lang".
71 */
72 public String path = "";
74 /**
75 * Name of the file getting generated. If the file getting generated is
76 * "java/lang/Object.html", then the filename is "Object.html".
77 */
78 public String filename = "";
80 /**
81 * The display length used for indentation while generating the class page.
82 */
83 public int displayLength = 0;
85 /**
86 * The global configuration information for this run.
87 */
88 public ConfigurationImpl configuration;
90 /**
91 * To check whether annotation heading is printed or not.
92 */
93 protected boolean printedAnnotationHeading = false;
95 /**
96 * Constructor to construct the HtmlStandardWriter object.
97 *
98 * @param filename File to be generated.
99 */
100 public HtmlDocletWriter(ConfigurationImpl configuration,
101 String filename) throws IOException {
102 super(configuration, filename);
103 this.configuration = configuration;
104 this.filename = filename;
105 }
107 /**
108 * Constructor to construct the HtmlStandardWriter object.
109 *
110 * @param path Platform-dependent {@link #path} used when
111 * creating file.
112 * @param filename Name of file to be generated.
113 * @param relativePath Value for the variable {@link #relativePath}.
114 */
115 public HtmlDocletWriter(ConfigurationImpl configuration,
116 String path, String filename,
117 String relativePath) throws IOException {
118 super(configuration, path, filename);
119 this.configuration = configuration;
120 this.path = path;
121 this.relativePath = relativePath;
122 this.relativepathNoSlash =
123 DirectoryManager.getPathNoTrailingSlash(this.relativePath);
124 this.filename = filename;
125 }
127 /**
128 * Replace {@docRoot} tag used in options that accept HTML text, such
129 * as -header, -footer, -top and -bottom, and when converting a relative
130 * HREF where commentTagsToString inserts a {@docRoot} where one was
131 * missing. (Also see DocRootTaglet for {@docRoot} tags in doc
132 * comments.)
133 * <p>
134 * Replace {@docRoot} tag in htmlstr with the relative path to the
135 * destination directory from the directory where the file is being
136 * written, looping to handle all such tags in htmlstr.
137 * <p>
138 * For example, for "-d docs" and -header containing {@docRoot}, when
139 * the HTML page for source file p/C1.java is being generated, the
140 * {@docRoot} tag would be inserted into the header as "../",
141 * the relative path from docs/p/ to docs/ (the document root).
142 * <p>
143 * Note: This doc comment was written with '&#064;' representing '@'
144 * to prevent the inline tag from being interpreted.
145 */
146 public String replaceDocRootDir(String htmlstr) {
147 // Return if no inline tags exist
148 int index = htmlstr.indexOf("{@");
149 if (index < 0) {
150 return htmlstr;
151 }
152 String lowerHtml = htmlstr.toLowerCase();
153 // Return index of first occurrence of {@docroot}
154 // Note: {@docRoot} is not case sensitive when passed in w/command line option
155 index = lowerHtml.indexOf("{@docroot}", index);
156 if (index < 0) {
157 return htmlstr;
158 }
159 StringBuilder buf = new StringBuilder();
160 int previndex = 0;
161 while (true) {
162 // Search for lowercase version of {@docRoot}
163 index = lowerHtml.indexOf("{@docroot}", previndex);
164 // If next {@docRoot} tag not found, append rest of htmlstr and exit loop
165 if (index < 0) {
166 buf.append(htmlstr.substring(previndex));
167 break;
168 }
169 // If next {@docroot} tag found, append htmlstr up to start of tag
170 buf.append(htmlstr.substring(previndex, index));
171 previndex = index + 10; // length for {@docroot} string
172 // Insert relative path where {@docRoot} was located
173 buf.append(relativepathNoSlash);
174 // Append slash if next character is not a slash
175 if (relativepathNoSlash.length() > 0 && previndex < htmlstr.length()
176 && htmlstr.charAt(previndex) != '/') {
177 buf.append(DirectoryManager.URL_FILE_SEPARATOR);
178 }
179 }
180 return buf.toString();
181 }
183 /**
184 * Print Html Hyper Link, with target frame. This
185 * link will only appear if page is not in a frame.
186 *
187 * @param link String name of the file.
188 * @param where Position in the file
189 * @param target Name of the target frame.
190 * @param label Tag for the link.
191 * @param strong Whether the label should be strong or not?
192 */
193 public void printNoFramesTargetHyperLink(String link, String where,
194 String target, String label,
195 boolean strong) {
196 script();
197 println(" <!--");
198 println(" if(window==top) {");
199 println(" document.writeln('"
200 + getHyperLinkString(link, where, label, strong, "", "", target) + "');");
201 println(" }");
202 println(" //-->");
203 scriptEnd();
204 noScript();
205 println(" " + getHyperLinkString(link, where, label, strong, "", "", target));
206 noScriptEnd();
207 println(DocletConstants.NL);
208 }
210 /**
211 * Get the script to show or hide the All classes link.
212 *
213 * @param id id of the element to show or hide
214 * @return a content tree for the script
215 */
216 public Content getAllClassesLinkScript(String id) {
217 HtmlTree script = new HtmlTree(HtmlTag.SCRIPT);
218 script.addAttr(HtmlAttr.TYPE, "text/javascript");
219 String scriptCode = "<!--" + DocletConstants.NL +
220 " allClassesLink = document.getElementById(\"" + id + "\");" + DocletConstants.NL +
221 " if(window==top) {" + DocletConstants.NL +
222 " allClassesLink.style.display = \"block\";" + DocletConstants.NL +
223 " }" + DocletConstants.NL +
224 " else {" + DocletConstants.NL +
225 " allClassesLink.style.display = \"none\";" + DocletConstants.NL +
226 " }" + DocletConstants.NL +
227 " //-->" + DocletConstants.NL;
228 Content scriptContent = new RawHtml(scriptCode);
229 script.addContent(scriptContent);
230 Content div = HtmlTree.DIV(script);
231 return div;
232 }
234 /**
235 * Add method information.
236 *
237 * @param method the method to be documented
238 * @param dl the content tree to which the method information will be added
239 */
240 private void addMethodInfo(MethodDoc method, Content dl) {
241 ClassDoc[] intfacs = method.containingClass().interfaces();
242 MethodDoc overriddenMethod = method.overriddenMethod();
243 // Check whether there is any implementation or overridden info to be
244 // printed. If no overridden or implementation info needs to be
245 // printed, do not print this section.
246 if ((intfacs.length > 0 &&
247 new ImplementedMethods(method, this.configuration).build().length > 0) ||
248 overriddenMethod != null) {
249 MethodWriterImpl.addImplementsInfo(this, method, dl);
250 if (overriddenMethod != null) {
251 MethodWriterImpl.addOverridden(this,
252 method.overriddenType(), overriddenMethod, dl);
253 }
254 }
255 }
257 /**
258 * Adds the tags information.
259 *
260 * @param doc the doc for which the tags will be generated
261 * @param htmltree the documentation tree to which the tags will be added
262 */
263 protected void addTagsInfo(Doc doc, Content htmltree) {
264 if (configuration.nocomment) {
265 return;
266 }
267 Content dl = new HtmlTree(HtmlTag.DL);
268 if (doc instanceof MethodDoc) {
269 addMethodInfo((MethodDoc) doc, dl);
270 }
271 TagletOutputImpl output = new TagletOutputImpl("");
272 TagletWriter.genTagOuput(configuration.tagletManager, doc,
273 configuration.tagletManager.getCustomTags(doc),
274 getTagletWriterInstance(false), output);
275 String outputString = output.toString().trim();
276 if (!outputString.isEmpty()) {
277 Content resultString = new RawHtml(outputString);
278 dl.addContent(resultString);
279 }
280 htmltree.addContent(dl);
281 }
283 /**
284 * Check whether there are any tags for Serialization Overview
285 * section to be printed.
286 *
287 * @param field the FieldDoc object to check for tags.
288 * @return true if there are tags to be printed else return false.
289 */
290 protected boolean hasSerializationOverviewTags(FieldDoc field) {
291 TagletOutputImpl output = new TagletOutputImpl("");
292 TagletWriter.genTagOuput(configuration.tagletManager, field,
293 configuration.tagletManager.getCustomTags(field),
294 getTagletWriterInstance(false), output);
295 return (!output.toString().trim().isEmpty());
296 }
298 /**
299 * Returns a TagletWriter that knows how to write HTML.
300 *
301 * @return a TagletWriter that knows how to write HTML.
302 */
303 public TagletWriter getTagletWriterInstance(boolean isFirstSentence) {
304 return new TagletWriterImpl(this, isFirstSentence);
305 }
307 protected void printTagsInfoHeader() {
308 dl();
309 }
311 protected void printTagsInfoFooter() {
312 dlEnd();
313 }
315 /**
316 * Get Package link, with target frame.
317 *
318 * @param pd The link will be to the "package-summary.html" page for this package
319 * @param target name of the target frame
320 * @param label tag for the link
321 * @return a content for the target package link
322 */
323 public Content getTargetPackageLink(PackageDoc pd, String target,
324 Content label) {
325 return getHyperLink(pathString(pd, "package-summary.html"), "", label, "", target);
326 }
328 /**
329 * Print the html file header. Also print Html page title and stylesheet
330 * default properties.
331 *
332 * @param title String window title to go in the <TITLE> tag
333 * @param metakeywords Array of String keywords for META tag. Each element
334 * of the array is assigned to a separate META tag.
335 * Pass in null for no array.
336 * @param includeScript boolean true if printing windowtitle script.
337 * False for files that appear in the left-hand frames.
338 */
339 public void printHtmlHeader(String title, String[] metakeywords,
340 boolean includeScript) {
341 println("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 " +
342 "Transitional//EN\" " +
343 "\"http://www.w3.org/TR/html4/loose.dtd\">");
344 println("<!--NewPage-->");
345 html();
346 head();
347 if (! configuration.notimestamp) {
348 print("<!-- Generated by javadoc (build " + ConfigurationImpl.BUILD_DATE + ") on ");
349 print(today());
350 println(" -->");
351 }
352 if (configuration.charset.length() > 0) {
353 println("<META http-equiv=\"Content-Type\" content=\"text/html; "
354 + "charset=" + configuration.charset + "\">");
355 }
356 if ( configuration.windowtitle.length() > 0 ) {
357 title += " (" + configuration.windowtitle + ")";
358 }
359 title(title);
360 println(title);
361 titleEnd();
362 println("");
363 if (! configuration.notimestamp) {
364 SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
365 println("<META NAME=\"date\" "
366 + "CONTENT=\"" + dateFormat.format(new Date()) + "\">");
367 }
368 if ( metakeywords != null ) {
369 for ( int i=0; i < metakeywords.length; i++ ) {
370 println("<META NAME=\"keywords\" "
371 + "CONTENT=\"" + metakeywords[i] + "\">");
372 }
373 }
374 println("");
375 printStyleSheetProperties();
376 println("");
377 // Don't print windowtitle script for overview-frame, allclasses-frame
378 // and package-frame
379 if (includeScript) {
380 printWinTitleScript(title);
381 }
382 println("");
383 headEnd();
384 println("");
385 body("white", includeScript);
386 }
388 /**
389 * Generates the HTML document tree and prints it out.
390 *
391 * @param metakeywords Array of String keywords for META tag. Each element
392 * of the array is assigned to a separate META tag.
393 * Pass in null for no array
394 * @param includeScript true if printing windowtitle script
395 * false for files that appear in the left-hand frames
396 * @param body the body htmltree to be included in the document
397 */
398 public void printHtmlDocument(String[] metakeywords, boolean includeScript,
399 Content body) {
400 Content htmlDocType = DocType.Transitional();
401 Content htmlComment = new Comment(configuration.getText("doclet.New_Page"));
402 Content head = new HtmlTree(HtmlTag.HEAD);
403 if (!configuration.notimestamp) {
404 Content headComment = new Comment("Generated by javadoc (version " +
405 ConfigurationImpl.BUILD_DATE + ") on " + today());
406 head.addContent(headComment);
407 }
408 if (configuration.charset.length() > 0) {
409 Content meta = HtmlTree.META("Content-Type", "text/html",
410 configuration.charset);
411 head.addContent(meta);
412 }
413 head.addContent(getTitle());
414 if (!configuration.notimestamp) {
415 SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
416 Content meta = HtmlTree.META("date", dateFormat.format(new Date()));
417 head.addContent(meta);
418 }
419 if (metakeywords != null) {
420 for (int i=0; i < metakeywords.length; i++) {
421 Content meta = HtmlTree.META("keywords", metakeywords[i]);
422 head.addContent(meta);
423 }
424 }
425 head.addContent(getStyleSheetProperties());
426 Content htmlTree = HtmlTree.HTML(configuration.getLocale().getLanguage(),
427 head, body);
428 Content htmlDocument = new HtmlDocument(htmlDocType,
429 htmlComment, htmlTree);
430 print(htmlDocument.toString());
431 }
433 /**
434 * Get the window title.
435 *
436 * @param title the title string to construct the complete window title
437 * @return the window title string
438 */
439 public String getWindowTitle(String title) {
440 if (configuration.windowtitle.length() > 0) {
441 title += " (" + configuration.windowtitle + ")";
442 }
443 return title;
444 }
446 /**
447 * Print user specified header and the footer.
448 *
449 * @param header if true print the user provided header else print the
450 * user provided footer.
451 */
452 public void printUserHeaderFooter(boolean header) {
453 em();
454 if (header) {
455 print(replaceDocRootDir(configuration.header));
456 } else {
457 if (configuration.footer.length() != 0) {
458 print(replaceDocRootDir(configuration.footer));
459 } else {
460 print(replaceDocRootDir(configuration.header));
461 }
462 }
463 emEnd();
464 }
466 /**
467 * Get user specified header and the footer.
468 *
469 * @param header if true print the user provided header else print the
470 * user provided footer.
471 */
472 public Content getUserHeaderFooter(boolean header) {
473 String content;
474 if (header) {
475 content = replaceDocRootDir(configuration.header);
476 } else {
477 if (configuration.footer.length() != 0) {
478 content = replaceDocRootDir(configuration.footer);
479 } else {
480 content = replaceDocRootDir(configuration.header);
481 }
482 }
483 Content rawContent = new RawHtml(content);
484 Content em = HtmlTree.EM(rawContent);
485 return em;
486 }
488 /**
489 * Print the user specified top.
490 */
491 public void printTop() {
492 print(replaceDocRootDir(configuration.top));
493 hr();
494 }
496 /**
497 * Adds the user specified top.
498 *
499 * @param body the content tree to which user specified top will be added
500 */
501 public void addTop(Content body) {
502 Content top = new RawHtml(replaceDocRootDir(configuration.top));
503 body.addContent(top);
504 }
506 /**
507 * Print the user specified bottom.
508 */
509 public void printBottom() {
510 hr();
511 print(replaceDocRootDir(configuration.bottom));
512 }
514 /**
515 * Adds the user specified bottom.
516 *
517 * @param body the content tree to which user specified bottom will be added
518 */
519 public void addBottom(Content body) {
520 Content bottom = new RawHtml(replaceDocRootDir(configuration.bottom));
521 Content small = HtmlTree.SMALL(bottom);
522 Content p = HtmlTree.P(HtmlStyle.legalCopy, small);
523 body.addContent(p);
524 }
526 /**
527 * Print the navigation bar for the Html page at the top and and the bottom.
528 *
529 * @param header If true print navigation bar at the top of the page else
530 * print the nevigation bar at the bottom.
531 */
532 protected void navLinks(boolean header) {
533 println("");
534 if (!configuration.nonavbar) {
535 if (header) {
536 println(DocletConstants.NL + "<!-- ========= START OF TOP NAVBAR ======= -->");
537 anchor("navbar_top");
538 println();
539 print(getHyperLinkString("", "skip-navbar_top", "", false, "",
540 configuration.getText("doclet.Skip_navigation_links"), ""));
541 } else {
542 println(DocletConstants.NL + "<!-- ======= START OF BOTTOM NAVBAR ====== -->");
543 anchor("navbar_bottom");
544 println();
545 print(getHyperLinkString("", "skip-navbar_bottom", "", false, "",
546 configuration.getText("doclet.Skip_navigation_links"), ""));
547 }
548 table(0, "100%", 1, 0);
549 tr();
550 tdColspanBgcolorStyle(2, "#EEEEFF", "NavBarCell1");
551 println("");
552 if (header) {
553 anchor("navbar_top_firstrow");
554 } else {
555 anchor("navbar_bottom_firstrow");
556 }
557 table(0, 0, 3);
558 print(" ");
559 trAlignVAlign("center", "top");
561 if (configuration.createoverview) {
562 navLinkContents();
563 }
565 if (configuration.packages.length == 1) {
566 navLinkPackage(configuration.packages[0]);
567 } else if (configuration.packages.length > 1) {
568 navLinkPackage();
569 }
571 navLinkClass();
573 if(configuration.classuse) {
574 navLinkClassUse();
575 }
576 if(configuration.createtree) {
577 navLinkTree();
578 }
579 if(!(configuration.nodeprecated ||
580 configuration.nodeprecatedlist)) {
581 navLinkDeprecated();
582 }
583 if(configuration.createindex) {
584 navLinkIndex();
585 }
586 if (!configuration.nohelp) {
587 navLinkHelp();
588 }
589 print(" ");
590 trEnd();
591 tableEnd();
592 tdEnd();
594 tdAlignVAlignRowspan("right", "top", 3);
596 printUserHeaderFooter(header);
597 tdEnd();
598 trEnd();
599 println("");
601 tr();
602 tdBgcolorStyle("white", "NavBarCell2");
603 font("-2");
604 space();
605 navLinkPrevious();
606 space();
607 println("");
608 space();
609 navLinkNext();
610 fontEnd();
611 tdEnd();
613 tdBgcolorStyle("white", "NavBarCell2");
614 font("-2");
615 print(" ");
616 navShowLists();
617 print(" ");
618 space();
619 println("");
620 space();
621 navHideLists(filename);
622 print(" ");
623 space();
624 println("");
625 space();
626 navLinkClassIndex();
627 fontEnd();
628 tdEnd();
630 trEnd();
632 printSummaryDetailLinks();
634 tableEnd();
635 if (header) {
636 aName("skip-navbar_top");
637 aEnd();
638 println(DocletConstants.NL + "<!-- ========= END OF TOP NAVBAR ========= -->");
639 } else {
640 aName("skip-navbar_bottom");
641 aEnd();
642 println(DocletConstants.NL + "<!-- ======== END OF BOTTOM NAVBAR ======= -->");
643 }
644 println("");
645 }
646 }
648 /**
649 * Adds the navigation bar for the Html page at the top and and the bottom.
650 *
651 * @param header If true print navigation bar at the top of the page else
652 * @param body the HtmlTree to which the nav links will be added
653 */
654 protected void addNavLinks(boolean header, Content body) {
655 if (!configuration.nonavbar) {
656 String allClassesId = "allclasses_";
657 HtmlTree navDiv = new HtmlTree(HtmlTag.DIV);
658 if (header) {
659 body.addContent(HtmlConstants.START_OF_TOP_NAVBAR);
660 navDiv.addStyle(HtmlStyle.topNav);
661 allClassesId += "navbar_top";
662 Content a = getMarkerAnchor("navbar_top");
663 navDiv.addContent(a);
664 Content skipLinkContent = getHyperLink("",
665 "skip-navbar_top", HtmlTree.EMPTY, configuration.getText(
666 "doclet.Skip_navigation_links"), "");
667 navDiv.addContent(skipLinkContent);
668 } else {
669 body.addContent(HtmlConstants.START_OF_BOTTOM_NAVBAR);
670 navDiv.addStyle(HtmlStyle.bottomNav);
671 allClassesId += "navbar_bottom";
672 Content a = getMarkerAnchor("navbar_bottom");
673 navDiv.addContent(a);
674 Content skipLinkContent = getHyperLink("",
675 "skip-navbar_bottom", HtmlTree.EMPTY, configuration.getText(
676 "doclet.Skip_navigation_links"), "");
677 navDiv.addContent(skipLinkContent);
678 }
679 if (header) {
680 navDiv.addContent(getMarkerAnchor("navbar_top_firstrow"));
681 } else {
682 navDiv.addContent(getMarkerAnchor("navbar_bottom_firstrow"));
683 }
684 HtmlTree navList = new HtmlTree(HtmlTag.UL);
685 navList.addStyle(HtmlStyle.navList);
686 navList.addAttr(HtmlAttr.TITLE, "Navigation");
687 if (configuration.createoverview) {
688 navList.addContent(getNavLinkContents());
689 }
690 if (configuration.packages.length == 1) {
691 navList.addContent(getNavLinkPackage(configuration.packages[0]));
692 } else if (configuration.packages.length > 1) {
693 navList.addContent(getNavLinkPackage());
694 }
695 navList.addContent(getNavLinkClass());
696 if(configuration.classuse) {
697 navList.addContent(getNavLinkClassUse());
698 }
699 if(configuration.createtree) {
700 navList.addContent(getNavLinkTree());
701 }
702 if(!(configuration.nodeprecated ||
703 configuration.nodeprecatedlist)) {
704 navList.addContent(getNavLinkDeprecated());
705 }
706 if(configuration.createindex) {
707 navList.addContent(getNavLinkIndex());
708 }
709 if (!configuration.nohelp) {
710 navList.addContent(getNavLinkHelp());
711 }
712 navDiv.addContent(navList);
713 Content aboutDiv = HtmlTree.DIV(HtmlStyle.aboutLanguage, getUserHeaderFooter(header));
714 navDiv.addContent(aboutDiv);
715 body.addContent(navDiv);
716 Content ulNav = HtmlTree.UL(HtmlStyle.navList, getNavLinkPrevious());
717 ulNav.addContent(getNavLinkNext());
718 Content subDiv = HtmlTree.DIV(HtmlStyle.subNav, ulNav);
719 Content ulFrames = HtmlTree.UL(HtmlStyle.navList, getNavShowLists());
720 ulFrames.addContent(getNavHideLists(filename));
721 subDiv.addContent(ulFrames);
722 HtmlTree ulAllClasses = HtmlTree.UL(HtmlStyle.navList, getNavLinkClassIndex());
723 ulAllClasses.addAttr(HtmlAttr.ID, allClassesId.toString());
724 subDiv.addContent(ulAllClasses);
725 subDiv.addContent(getAllClassesLinkScript(allClassesId.toString()));
726 addSummaryDetailLinks(subDiv);
727 if (header) {
728 subDiv.addContent(getMarkerAnchor("skip-navbar_top"));
729 body.addContent(subDiv);
730 body.addContent(HtmlConstants.END_OF_TOP_NAVBAR);
731 } else {
732 subDiv.addContent(getMarkerAnchor("skip-navbar_bottom"));
733 body.addContent(subDiv);
734 body.addContent(HtmlConstants.END_OF_BOTTOM_NAVBAR);
735 }
736 }
737 }
739 /**
740 * Print the word "NEXT" to indicate that no link is available. Override
741 * this method to customize next link.
742 */
743 protected void navLinkNext() {
744 navLinkNext(null);
745 }
747 /**
748 * Get the word "NEXT" to indicate that no link is available. Override
749 * this method to customize next link.
750 *
751 * @return a content tree for the link
752 */
753 protected Content getNavLinkNext() {
754 return getNavLinkNext(null);
755 }
757 /**
758 * Print the word "PREV" to indicate that no link is available. Override
759 * this method to customize prev link.
760 */
761 protected void navLinkPrevious() {
762 navLinkPrevious(null);
763 }
765 /**
766 * Get the word "PREV" to indicate that no link is available. Override
767 * this method to customize prev link.
768 *
769 * @return a content tree for the link
770 */
771 protected Content getNavLinkPrevious() {
772 return getNavLinkPrevious(null);
773 }
775 /**
776 * Do nothing. This is the default method.
777 */
778 protected void printSummaryDetailLinks() {
779 }
781 /**
782 * Do nothing. This is the default method.
783 */
784 protected void addSummaryDetailLinks(Content navDiv) {
785 }
787 /**
788 * Print link to the "overview-summary.html" page.
789 */
790 protected void navLinkContents() {
791 navCellStart();
792 printHyperLink(relativePath + "overview-summary.html", "",
793 configuration.getText("doclet.Overview"), true, "NavBarFont1");
794 navCellEnd();
795 }
797 /**
798 * Get link to the "overview-summary.html" page.
799 *
800 * @return a content tree for the link
801 */
802 protected Content getNavLinkContents() {
803 Content linkContent = getHyperLink(relativePath +
804 "overview-summary.html", "", overviewLabel, "", "");
805 Content li = HtmlTree.LI(linkContent);
806 return li;
807 }
809 /**
810 * Description for a cell in the navigation bar.
811 */
812 protected void navCellStart() {
813 print(" ");
814 tdBgcolorStyle("#EEEEFF", "NavBarCell1");
815 print(" ");
816 }
818 /**
819 * Description for a cell in the navigation bar, but with reverse
820 * high-light effect.
821 */
822 protected void navCellRevStart() {
823 print(" ");
824 tdBgcolorStyle("#FFFFFF", "NavBarCell1Rev");
825 print(" ");
826 space();
827 }
829 /**
830 * Closing tag for navigation bar cell.
831 */
832 protected void navCellEnd() {
833 space();
834 tdEnd();
835 }
837 /**
838 * Print link to the "package-summary.html" page for the package passed.
839 *
840 * @param pkg Package to which link will be generated.
841 */
842 protected void navLinkPackage(PackageDoc pkg) {
843 navCellStart();
844 printPackageLink(pkg, configuration.getText("doclet.Package"), true,
845 "NavBarFont1");
846 navCellEnd();
847 }
849 /**
850 * Get link to the "package-summary.html" page for the package passed.
851 *
852 * @param pkg Package to which link will be generated
853 * @return a content tree for the link
854 */
855 protected Content getNavLinkPackage(PackageDoc pkg) {
856 Content linkContent = getPackageLink(pkg,
857 packageLabel);
858 Content li = HtmlTree.LI(linkContent);
859 return li;
860 }
862 /**
863 * Print the word "Package" in the navigation bar cell, to indicate that
864 * link is not available here.
865 */
866 protected void navLinkPackage() {
867 navCellStart();
868 fontStyle("NavBarFont1");
869 printText("doclet.Package");
870 fontEnd();
871 navCellEnd();
872 }
874 /**
875 * Get the word "Package" , to indicate that link is not available here.
876 *
877 * @return a content tree for the link
878 */
879 protected Content getNavLinkPackage() {
880 Content li = HtmlTree.LI(packageLabel);
881 return li;
882 }
884 /**
885 * Print the word "Use" in the navigation bar cell, to indicate that link
886 * is not available.
887 */
888 protected void navLinkClassUse() {
889 navCellStart();
890 fontStyle("NavBarFont1");
891 printText("doclet.navClassUse");
892 fontEnd();
893 navCellEnd();
894 }
896 /**
897 * Get the word "Use", to indicate that link is not available.
898 *
899 * @return a content tree for the link
900 */
901 protected Content getNavLinkClassUse() {
902 Content li = HtmlTree.LI(useLabel);
903 return li;
904 }
906 /**
907 * Print link for previous file.
908 *
909 * @param prev File name for the prev link.
910 */
911 public void navLinkPrevious(String prev) {
912 String tag = configuration.getText("doclet.Prev");
913 if (prev != null) {
914 printHyperLink(prev, "", tag, true) ;
915 } else {
916 print(tag);
917 }
918 }
920 /**
921 * Get link for previous file.
922 *
923 * @param prev File name for the prev link
924 * @return a content tree for the link
925 */
926 public Content getNavLinkPrevious(String prev) {
927 Content li;
928 if (prev != null) {
929 li = HtmlTree.LI(getHyperLink(prev, "", prevLabel, "", ""));
930 }
931 else
932 li = HtmlTree.LI(prevLabel);
933 return li;
934 }
936 /**
937 * Print link for next file. If next is null, just print the label
938 * without linking it anywhere.
939 *
940 * @param next File name for the next link.
941 */
942 public void navLinkNext(String next) {
943 String tag = configuration.getText("doclet.Next");
944 if (next != null) {
945 printHyperLink(next, "", tag, true);
946 } else {
947 print(tag);
948 }
949 }
951 /**
952 * Get link for next file. If next is null, just print the label
953 * without linking it anywhere.
954 *
955 * @param next File name for the next link
956 * @return a content tree for the link
957 */
958 public Content getNavLinkNext(String next) {
959 Content li;
960 if (next != null) {
961 li = HtmlTree.LI(getHyperLink(next, "", nextLabel, "", ""));
962 }
963 else
964 li = HtmlTree.LI(nextLabel);
965 return li;
966 }
968 /**
969 * Print "FRAMES" link, to switch to the frame version of the output.
970 *
971 * @param link File to be linked, "index.html".
972 */
973 protected void navShowLists(String link) {
974 print(getHyperLinkString(link + "?" + path + filename, "",
975 configuration.getText("doclet.FRAMES"), true, "", "", "_top"));
976 }
978 /**
979 * Get "FRAMES" link, to switch to the frame version of the output.
980 *
981 * @param link File to be linked, "index.html"
982 * @return a content tree for the link
983 */
984 protected Content getNavShowLists(String link) {
985 Content framesContent = getHyperLink(link + "?" + path +
986 filename, "", framesLabel, "", "_top");
987 Content li = HtmlTree.LI(framesContent);
988 return li;
989 }
991 /**
992 * Print "FRAMES" link, to switch to the frame version of the output.
993 */
994 protected void navShowLists() {
995 navShowLists(relativePath + "index.html");
996 }
998 /**
999 * Get "FRAMES" link, to switch to the frame version of the output.
1000 *
1001 * @return a content tree for the link
1002 */
1003 protected Content getNavShowLists() {
1004 return getNavShowLists(relativePath + "index.html");
1005 }
1007 /**
1008 * Print "NO FRAMES" link, to switch to the non-frame version of the output.
1009 *
1010 * @param link File to be linked.
1011 */
1012 protected void navHideLists(String link) {
1013 print(getHyperLinkString(link, "", configuration.getText("doclet.NO_FRAMES"),
1014 true, "", "", "_top"));
1015 }
1017 /**
1018 * Get "NO FRAMES" link, to switch to the non-frame version of the output.
1019 *
1020 * @param link File to be linked
1021 * @return a content tree for the link
1022 */
1023 protected Content getNavHideLists(String link) {
1024 Content noFramesContent = getHyperLink(link, "", noframesLabel, "", "_top");
1025 Content li = HtmlTree.LI(noFramesContent);
1026 return li;
1027 }
1029 /**
1030 * Print "Tree" link in the navigation bar. If there is only one package
1031 * specified on the command line, then the "Tree" link will be to the
1032 * only "package-tree.html" file otherwise it will be to the
1033 * "overview-tree.html" file.
1034 */
1035 protected void navLinkTree() {
1036 navCellStart();
1037 PackageDoc[] packages = configuration.root.specifiedPackages();
1038 if (packages.length == 1 && configuration.root.specifiedClasses().length == 0) {
1039 printHyperLink(pathString(packages[0], "package-tree.html"), "",
1040 configuration.getText("doclet.Tree"), true, "NavBarFont1");
1041 } else {
1042 printHyperLink(relativePath + "overview-tree.html", "",
1043 configuration.getText("doclet.Tree"), true, "NavBarFont1");
1044 }
1045 navCellEnd();
1046 }
1048 /**
1049 * Get "Tree" link in the navigation bar. If there is only one package
1050 * specified on the command line, then the "Tree" link will be to the
1051 * only "package-tree.html" file otherwise it will be to the
1052 * "overview-tree.html" file.
1053 *
1054 * @return a content tree for the link
1055 */
1056 protected Content getNavLinkTree() {
1057 Content treeLinkContent;
1058 PackageDoc[] packages = configuration.root.specifiedPackages();
1059 if (packages.length == 1 && configuration.root.specifiedClasses().length == 0) {
1060 treeLinkContent = getHyperLink(pathString(packages[0],
1061 "package-tree.html"), "", treeLabel,
1062 "", "");
1063 } else {
1064 treeLinkContent = getHyperLink(relativePath + "overview-tree.html",
1065 "", treeLabel, "", "");
1066 }
1067 Content li = HtmlTree.LI(treeLinkContent);
1068 return li;
1069 }
1071 /**
1072 * Get the overview tree link for the main tree.
1073 *
1074 * @param label the label for the link
1075 * @return a content tree for the link
1076 */
1077 protected Content getNavLinkMainTree(String label) {
1078 Content mainTreeContent = getHyperLink(relativePath + "overview-tree.html",
1079 new StringContent(label));
1080 Content li = HtmlTree.LI(mainTreeContent);
1081 return li;
1082 }
1084 /**
1085 * Print the word "Class" in the navigation bar cell, to indicate that
1086 * class link is not available.
1087 */
1088 protected void navLinkClass() {
1089 navCellStart();
1090 fontStyle("NavBarFont1");
1091 printText("doclet.Class");
1092 fontEnd();
1093 navCellEnd();
1094 }
1096 /**
1097 * Get the word "Class", to indicate that class link is not available.
1098 *
1099 * @return a content tree for the link
1100 */
1101 protected Content getNavLinkClass() {
1102 Content li = HtmlTree.LI(classLabel);
1103 return li;
1104 }
1106 /**
1107 * Print "Deprecated" API link in the navigation bar.
1108 */
1109 protected void navLinkDeprecated() {
1110 navCellStart();
1111 printHyperLink(relativePath + "deprecated-list.html", "",
1112 configuration.getText("doclet.navDeprecated"), true, "NavBarFont1");
1113 navCellEnd();
1114 }
1116 /**
1117 * Get "Deprecated" API link in the navigation bar.
1118 *
1119 * @return a content tree for the link
1120 */
1121 protected Content getNavLinkDeprecated() {
1122 Content linkContent = getHyperLink(relativePath +
1123 "deprecated-list.html", "", deprecatedLabel, "", "");
1124 Content li = HtmlTree.LI(linkContent);
1125 return li;
1126 }
1128 /**
1129 * Print link for generated index. If the user has used "-splitindex"
1130 * command line option, then link to file "index-files/index-1.html" is
1131 * generated otherwise link to file "index-all.html" is generated.
1132 */
1133 protected void navLinkClassIndex() {
1134 printNoFramesTargetHyperLink(relativePath +
1135 AllClassesFrameWriter.OUTPUT_FILE_NAME_NOFRAMES,
1136 "", "", configuration.getText("doclet.All_Classes"), true);
1137 }
1139 /**
1140 * Get link for generated index. If the user has used "-splitindex"
1141 * command line option, then link to file "index-files/index-1.html" is
1142 * generated otherwise link to file "index-all.html" is generated.
1143 *
1144 * @return a content tree for the link
1145 */
1146 protected Content getNavLinkClassIndex() {
1147 Content allClassesContent = getHyperLink(relativePath +
1148 AllClassesFrameWriter.OUTPUT_FILE_NAME_NOFRAMES, "",
1149 allclassesLabel, "", "");
1150 Content li = HtmlTree.LI(allClassesContent);
1151 return li;
1152 }
1153 /**
1154 * Print link for generated class index.
1155 */
1156 protected void navLinkIndex() {
1157 navCellStart();
1158 printHyperLink(relativePath +
1159 (configuration.splitindex?
1160 DirectoryManager.getPath("index-files") +
1161 fileseparator: "") +
1162 (configuration.splitindex?
1163 "index-1.html" : "index-all.html"), "",
1164 configuration.getText("doclet.Index"), true, "NavBarFont1");
1165 navCellEnd();
1166 }
1168 /**
1169 * Get link for generated class index.
1170 *
1171 * @return a content tree for the link
1172 */
1173 protected Content getNavLinkIndex() {
1174 Content linkContent = getHyperLink(relativePath +(configuration.splitindex?
1175 DirectoryManager.getPath("index-files") + fileseparator: "") +
1176 (configuration.splitindex?"index-1.html" : "index-all.html"), "",
1177 indexLabel, "", "");
1178 Content li = HtmlTree.LI(linkContent);
1179 return li;
1180 }
1182 /**
1183 * Print help file link. If user has provided a help file, then generate a
1184 * link to the user given file, which is already copied to current or
1185 * destination directory.
1186 */
1187 protected void navLinkHelp() {
1188 String helpfilenm = configuration.helpfile;
1189 if (helpfilenm.equals("")) {
1190 helpfilenm = "help-doc.html";
1191 } else {
1192 int lastsep;
1193 if ((lastsep = helpfilenm.lastIndexOf(File.separatorChar)) != -1) {
1194 helpfilenm = helpfilenm.substring(lastsep + 1);
1195 }
1196 }
1197 navCellStart();
1198 printHyperLink(relativePath + helpfilenm, "",
1199 configuration.getText("doclet.Help"), true, "NavBarFont1");
1200 navCellEnd();
1201 }
1203 /**
1204 * Get help file link. If user has provided a help file, then generate a
1205 * link to the user given file, which is already copied to current or
1206 * destination directory.
1207 *
1208 * @return a content tree for the link
1209 */
1210 protected Content getNavLinkHelp() {
1211 String helpfilenm = configuration.helpfile;
1212 if (helpfilenm.equals("")) {
1213 helpfilenm = "help-doc.html";
1214 } else {
1215 int lastsep;
1216 if ((lastsep = helpfilenm.lastIndexOf(File.separatorChar)) != -1) {
1217 helpfilenm = helpfilenm.substring(lastsep + 1);
1218 }
1219 }
1220 Content linkContent = getHyperLink(relativePath + helpfilenm, "",
1221 helpLabel, "", "");
1222 Content li = HtmlTree.LI(linkContent);
1223 return li;
1224 }
1226 /**
1227 * Print the word "Detail" in the navigation bar. No link is available.
1228 */
1229 protected void navDetail() {
1230 printText("doclet.Detail");
1231 }
1233 /**
1234 * Print the word "Summary" in the navigation bar. No link is available.
1235 */
1236 protected void navSummary() {
1237 printText("doclet.Summary");
1238 }
1240 /**
1241 * Print the Html table tag for the index summary tables. The table tag
1242 * printed is
1243 * <TABLE BORDER="1" CELLPADDING="3" CELLSPACING="0" WIDTH="100%">
1244 */
1245 public void tableIndexSummary() {
1246 table(1, "100%", 3, 0);
1247 }
1249 /**
1250 * Print the Html table tag for the index summary tables.
1251 *
1252 * @param summary the summary for the table tag summary attribute.
1253 */
1254 public void tableIndexSummary(String summary) {
1255 table(1, "100%", 3, 0, summary);
1256 }
1258 /**
1259 * Same as {@link #tableIndexSummary()}.
1260 */
1261 public void tableIndexDetail() {
1262 table(1, "100%", 3, 0);
1263 }
1265 /**
1266 * Print Html tag for table elements. The tag printed is
1267 * <TD ALIGN="right" VALIGN="top" WIDTH="1%">.
1268 */
1269 public void tdIndex() {
1270 print("<TD ALIGN=\"right\" VALIGN=\"top\" WIDTH=\"1%\">");
1271 }
1273 /**
1274 * Print table caption.
1275 */
1276 public void tableCaptionStart() {
1277 captionStyle("TableCaption");
1278 }
1280 /**
1281 * Print table sub-caption.
1282 */
1283 public void tableSubCaptionStart() {
1284 captionStyle("TableSubCaption");
1285 }
1287 /**
1288 * Print table caption end tags.
1289 */
1290 public void tableCaptionEnd() {
1291 captionEnd();
1292 }
1294 /**
1295 * Print summary table header.
1296 */
1297 public void summaryTableHeader(String[] header, String scope) {
1298 tr();
1299 for ( int i=0; i < header.length; i++ ) {
1300 thScopeNoWrap("TableHeader", scope);
1301 print(header[i]);
1302 thEnd();
1303 }
1304 trEnd();
1305 }
1307 /**
1308 * Get summary table header.
1309 *
1310 * @param header the header for the table
1311 * @param scope the scope of the headers
1312 * @return a content tree for the header
1313 */
1314 public Content getSummaryTableHeader(String[] header, String scope) {
1315 Content tr = new HtmlTree(HtmlTag.TR);
1316 int size = header.length;
1317 Content tableHeader;
1318 if (size == 1) {
1319 tableHeader = new StringContent(header[0]);
1320 tr.addContent(HtmlTree.TH(HtmlStyle.colOne, scope, tableHeader));
1321 return tr;
1322 }
1323 for (int i = 0; i < size; i++) {
1324 tableHeader = new StringContent(header[i]);
1325 if(i == 0)
1326 tr.addContent(HtmlTree.TH(HtmlStyle.colFirst, scope, tableHeader));
1327 else if(i == (size - 1))
1328 tr.addContent(HtmlTree.TH(HtmlStyle.colLast, scope, tableHeader));
1329 else
1330 tr.addContent(HtmlTree.TH(scope, tableHeader));
1331 }
1332 return tr;
1333 }
1335 /**
1336 * Get table caption.
1337 *
1338 * @param rawText the caption for the table which could be raw Html
1339 * @return a content tree for the caption
1340 */
1341 public Content getTableCaption(String rawText) {
1342 Content title = new RawHtml(rawText);
1343 Content captionSpan = HtmlTree.SPAN(title);
1344 Content space = getSpace();
1345 Content tabSpan = HtmlTree.SPAN(HtmlStyle.tabEnd, space);
1346 Content caption = HtmlTree.CAPTION(captionSpan);
1347 caption.addContent(tabSpan);
1348 return caption;
1349 }
1351 /**
1352 * Get the marker anchor which will be added to the documentation tree.
1353 *
1354 * @param anchorName the anchor name attribute
1355 * @return a content tree for the marker anchor
1356 */
1357 public Content getMarkerAnchor(String anchorName) {
1358 return getMarkerAnchor(anchorName, null);
1359 }
1361 /**
1362 * Get the marker anchor which will be added to the documentation tree.
1363 *
1364 * @param anchorName the anchor name attribute
1365 * @param anchorContent the content that should be added to the anchor
1366 * @return a content tree for the marker anchor
1367 */
1368 public Content getMarkerAnchor(String anchorName, Content anchorContent) {
1369 if (anchorContent == null)
1370 anchorContent = new Comment(" ");
1371 Content markerAnchor = HtmlTree.A_NAME(anchorName, anchorContent);
1372 return markerAnchor;
1373 }
1375 /**
1376 * Returns a packagename content.
1377 *
1378 * @param packageDoc the package to check
1379 * @return package name content
1380 */
1381 public Content getPackageName(PackageDoc packageDoc) {
1382 return packageDoc == null || packageDoc.name().length() == 0 ?
1383 defaultPackageLabel :
1384 getPackageLabel(packageDoc.name());
1385 }
1387 /**
1388 * Returns a package name label.
1389 *
1390 * @param parsedName the package name
1391 * @return the package name content
1392 */
1393 public Content getPackageLabel(String packageName) {
1394 return new StringContent(packageName);
1395 }
1397 /**
1398 * Add package deprecation information to the documentation tree
1399 *
1400 * @param deprPkgs list of deprecated packages
1401 * @param headingKey the caption for the deprecated package table
1402 * @param tableSummary the summary for the deprecated package table
1403 * @param tableHeader table headers for the deprecated package table
1404 * @param contentTree the content tree to which the deprecated package table will be added
1405 */
1406 protected void addPackageDeprecatedAPI(List<Doc> deprPkgs, String headingKey,
1407 String tableSummary, String[] tableHeader, Content contentTree) {
1408 if (deprPkgs.size() > 0) {
1409 Content table = HtmlTree.TABLE(0, 3, 0, tableSummary,
1410 getTableCaption(configuration().getText(headingKey)));
1411 table.addContent(getSummaryTableHeader(tableHeader, "col"));
1412 Content tbody = new HtmlTree(HtmlTag.TBODY);
1413 for (int i = 0; i < deprPkgs.size(); i++) {
1414 PackageDoc pkg = (PackageDoc) deprPkgs.get(i);
1415 HtmlTree td = HtmlTree.TD(HtmlStyle.colOne,
1416 getPackageLink(pkg, getPackageName(pkg)));
1417 if (pkg.tags("deprecated").length > 0) {
1418 addInlineDeprecatedComment(pkg, pkg.tags("deprecated")[0], td);
1419 }
1420 HtmlTree tr = HtmlTree.TR(td);
1421 if (i % 2 == 0) {
1422 tr.addStyle(HtmlStyle.altColor);
1423 } else {
1424 tr.addStyle(HtmlStyle.rowColor);
1425 }
1426 tbody.addContent(tr);
1427 }
1428 table.addContent(tbody);
1429 Content li = HtmlTree.LI(HtmlStyle.blockList, table);
1430 Content ul = HtmlTree.UL(HtmlStyle.blockList, li);
1431 contentTree.addContent(ul);
1432 }
1433 }
1435 /**
1436 * Prine table header information about color, column span and the font.
1437 *
1438 * @param color Background color.
1439 * @param span Column span.
1440 */
1441 public void tableHeaderStart(String color, int span) {
1442 trBgcolorStyle(color, "TableHeadingColor");
1443 thAlignColspan("left", span);
1444 font("+2");
1445 }
1447 /**
1448 * Print table header for the inherited members summary tables. Print the
1449 * background color information.
1450 *
1451 * @param color Background color.
1452 */
1453 public void tableInheritedHeaderStart(String color) {
1454 trBgcolorStyle(color, "TableSubHeadingColor");
1455 thAlign("left");
1456 }
1458 /**
1459 * Print "Use" table header. Print the background color and the column span.
1460 *
1461 * @param color Background color.
1462 */
1463 public void tableUseInfoHeaderStart(String color) {
1464 trBgcolorStyle(color, "TableSubHeadingColor");
1465 thAlignColspan("left", 2);
1466 }
1468 /**
1469 * Print table header with the background color with default column span 2.
1470 *
1471 * @param color Background color.
1472 */
1473 public void tableHeaderStart(String color) {
1474 tableHeaderStart(color, 2);
1475 }
1477 /**
1478 * Print table header with the column span, with the default color #CCCCFF.
1479 *
1480 * @param span Column span.
1481 */
1482 public void tableHeaderStart(int span) {
1483 tableHeaderStart("#CCCCFF", span);
1484 }
1486 /**
1487 * Print table header with default column span 2 and default color #CCCCFF.
1488 */
1489 public void tableHeaderStart() {
1490 tableHeaderStart(2);
1491 }
1493 /**
1494 * Print table header end tags for font, column and row.
1495 */
1496 public void tableHeaderEnd() {
1497 fontEnd();
1498 thEnd();
1499 trEnd();
1500 }
1502 /**
1503 * Print table header end tags in inherited tables for column and row.
1504 */
1505 public void tableInheritedHeaderEnd() {
1506 thEnd();
1507 trEnd();
1508 }
1510 /**
1511 * Print the summary table row cell attribute width.
1512 *
1513 * @param width Width of the table cell.
1514 */
1515 public void summaryRow(int width) {
1516 if (width != 0) {
1517 tdWidth(width + "%");
1518 } else {
1519 td();
1520 }
1521 }
1523 /**
1524 * Print the summary table row cell end tag.
1525 */
1526 public void summaryRowEnd() {
1527 tdEnd();
1528 }
1530 /**
1531 * Print the heading in Html <H2> format.
1532 *
1533 * @param str The Header string.
1534 */
1535 public void printIndexHeading(String str) {
1536 h2();
1537 print(str);
1538 h2End();
1539 }
1541 /**
1542 * Print Html tag <FRAMESET=arg>.
1543 *
1544 * @param arg Argument for the tag.
1545 */
1546 public void frameSet(String arg) {
1547 println("<FRAMESET " + arg + ">");
1548 }
1550 /**
1551 * Print Html closing tag </FRAMESET>.
1552 */
1553 public void frameSetEnd() {
1554 println("</FRAMESET>");
1555 }
1557 /**
1558 * Print Html tag <FRAME=arg>.
1559 *
1560 * @param arg Argument for the tag.
1561 */
1562 public void frame(String arg) {
1563 println("<FRAME " + arg + ">");
1564 }
1566 /**
1567 * Print Html closing tag </FRAME>.
1568 */
1569 public void frameEnd() {
1570 println("</FRAME>");
1571 }
1573 /**
1574 * Return path to the class page for a classdoc. For example, the class
1575 * name is "java.lang.Object" and if the current file getting generated is
1576 * "java/io/File.html", then the path string to the class, returned is
1577 * "../../java/lang.Object.html".
1578 *
1579 * @param cd Class to which the path is requested.
1580 */
1581 protected String pathToClass(ClassDoc cd) {
1582 return pathString(cd.containingPackage(), cd.name() + ".html");
1583 }
1585 /**
1586 * Return the path to the class page for a classdoc. Works same as
1587 * {@link #pathToClass(ClassDoc)}.
1588 *
1589 * @param cd Class to which the path is requested.
1590 * @param name Name of the file(doesn't include path).
1591 */
1592 protected String pathString(ClassDoc cd, String name) {
1593 return pathString(cd.containingPackage(), name);
1594 }
1596 /**
1597 * Return path to the given file name in the given package. So if the name
1598 * passed is "Object.html" and the name of the package is "java.lang", and
1599 * if the relative path is "../.." then returned string will be
1600 * "../../java/lang/Object.html"
1601 *
1602 * @param pd Package in which the file name is assumed to be.
1603 * @param name File name, to which path string is.
1604 */
1605 protected String pathString(PackageDoc pd, String name) {
1606 StringBuffer buf = new StringBuffer(relativePath);
1607 buf.append(DirectoryManager.getPathToPackage(pd, name));
1608 return buf.toString();
1609 }
1611 /**
1612 * Print the link to the given package.
1613 *
1614 * @param pkg the package to link to.
1615 * @param label the label for the link.
1616 * @param isStrong true if the label should be strong.
1617 */
1618 public void printPackageLink(PackageDoc pkg, String label, boolean isStrong) {
1619 print(getPackageLinkString(pkg, label, isStrong));
1620 }
1622 /**
1623 * Print the link to the given package.
1624 *
1625 * @param pkg the package to link to.
1626 * @param label the label for the link.
1627 * @param isStrong true if the label should be strong.
1628 * @param style the font of the package link label.
1629 */
1630 public void printPackageLink(PackageDoc pkg, String label, boolean isStrong,
1631 String style) {
1632 print(getPackageLinkString(pkg, label, isStrong, style));
1633 }
1635 /**
1636 * Return the link to the given package.
1637 *
1638 * @param pkg the package to link to.
1639 * @param label the label for the link.
1640 * @param isStrong true if the label should be strong.
1641 * @return the link to the given package.
1642 */
1643 public String getPackageLinkString(PackageDoc pkg, String label,
1644 boolean isStrong) {
1645 return getPackageLinkString(pkg, label, isStrong, "");
1646 }
1648 /**
1649 * Return the link to the given package.
1650 *
1651 * @param pkg the package to link to.
1652 * @param label the label for the link.
1653 * @param isStrong true if the label should be strong.
1654 * @param style the font of the package link label.
1655 * @return the link to the given package.
1656 */
1657 public String getPackageLinkString(PackageDoc pkg, String label, boolean isStrong,
1658 String style) {
1659 boolean included = pkg != null && pkg.isIncluded();
1660 if (! included) {
1661 PackageDoc[] packages = configuration.packages;
1662 for (int i = 0; i < packages.length; i++) {
1663 if (packages[i].equals(pkg)) {
1664 included = true;
1665 break;
1666 }
1667 }
1668 }
1669 if (included || pkg == null) {
1670 return getHyperLinkString(pathString(pkg, "package-summary.html"),
1671 "", label, isStrong, style);
1672 } else {
1673 String crossPkgLink = getCrossPackageLink(Util.getPackageName(pkg));
1674 if (crossPkgLink != null) {
1675 return getHyperLinkString(crossPkgLink, "", label, isStrong, style);
1676 } else {
1677 return label;
1678 }
1679 }
1680 }
1682 /**
1683 * Return the link to the given package.
1684 *
1685 * @param pkg the package to link to.
1686 * @param label the label for the link.
1687 * @return a content tree for the package link.
1688 */
1689 public Content getPackageLink(PackageDoc pkg, Content label) {
1690 boolean included = pkg != null && pkg.isIncluded();
1691 if (! included) {
1692 PackageDoc[] packages = configuration.packages;
1693 for (int i = 0; i < packages.length; i++) {
1694 if (packages[i].equals(pkg)) {
1695 included = true;
1696 break;
1697 }
1698 }
1699 }
1700 if (included || pkg == null) {
1701 return getHyperLink(pathString(pkg, "package-summary.html"),
1702 "", label);
1703 } else {
1704 String crossPkgLink = getCrossPackageLink(Util.getPackageName(pkg));
1705 if (crossPkgLink != null) {
1706 return getHyperLink(crossPkgLink, "", label);
1707 } else {
1708 return label;
1709 }
1710 }
1711 }
1713 public String italicsClassName(ClassDoc cd, boolean qual) {
1714 String name = (qual)? cd.qualifiedName(): cd.name();
1715 return (cd.isInterface())? italicsText(name): name;
1716 }
1718 public void printSrcLink(ProgramElementDoc d, String label) {
1719 if (d == null) {
1720 return;
1721 }
1722 ClassDoc cd = d.containingClass();
1723 if (cd == null) {
1724 //d must be a class doc since in has no containing class.
1725 cd = (ClassDoc) d;
1726 }
1727 String href = relativePath + DocletConstants.SOURCE_OUTPUT_DIR_NAME
1728 + DirectoryManager.getDirectoryPath(cd.containingPackage())
1729 + cd.name() + ".html#" + SourceToHTMLConverter.getAnchorName(d);
1730 printHyperLink(href, "", label, true);
1731 }
1733 /**
1734 * Add the link to the content tree.
1735 *
1736 * @param doc program element doc for which the link will be added
1737 * @param label label for the link
1738 * @param htmltree the content tree to which the link will be added
1739 */
1740 public void addSrcLink(ProgramElementDoc doc, Content label, Content htmltree) {
1741 if (doc == null) {
1742 return;
1743 }
1744 ClassDoc cd = doc.containingClass();
1745 if (cd == null) {
1746 //d must be a class doc since in has no containing class.
1747 cd = (ClassDoc) doc;
1748 }
1749 String href = relativePath + DocletConstants.SOURCE_OUTPUT_DIR_NAME
1750 + DirectoryManager.getDirectoryPath(cd.containingPackage())
1751 + cd.name() + ".html#" + SourceToHTMLConverter.getAnchorName(doc);
1752 Content linkContent = getHyperLink(href, "", label, "", "");
1753 htmltree.addContent(linkContent);
1754 }
1756 /**
1757 * Return the link to the given class.
1758 *
1759 * @param linkInfo the information about the link.
1760 *
1761 * @return the link for the given class.
1762 */
1763 public String getLink(LinkInfoImpl linkInfo) {
1764 LinkFactoryImpl factory = new LinkFactoryImpl(this);
1765 String link = ((LinkOutputImpl) factory.getLinkOutput(linkInfo)).toString();
1766 displayLength += linkInfo.displayLength;
1767 return link;
1768 }
1770 /**
1771 * Return the type parameters for the given class.
1772 *
1773 * @param linkInfo the information about the link.
1774 * @return the type for the given class.
1775 */
1776 public String getTypeParameterLinks(LinkInfoImpl linkInfo) {
1777 LinkFactoryImpl factory = new LinkFactoryImpl(this);
1778 return ((LinkOutputImpl)
1779 factory.getTypeParameterLinks(linkInfo, false)).toString();
1780 }
1782 /**
1783 * Print the link to the given class.
1784 */
1785 public void printLink(LinkInfoImpl linkInfo) {
1786 print(getLink(linkInfo));
1787 }
1789 /*************************************************************
1790 * Return a class cross link to external class documentation.
1791 * The name must be fully qualified to determine which package
1792 * the class is in. The -link option does not allow users to
1793 * link to external classes in the "default" package.
1794 *
1795 * @param qualifiedClassName the qualified name of the external class.
1796 * @param refMemName the name of the member being referenced. This should
1797 * be null or empty string if no member is being referenced.
1798 * @param label the label for the external link.
1799 * @param strong true if the link should be strong.
1800 * @param style the style of the link.
1801 * @param code true if the label should be code font.
1802 */
1803 public String getCrossClassLink(String qualifiedClassName, String refMemName,
1804 String label, boolean strong, String style,
1805 boolean code) {
1806 String className = "",
1807 packageName = qualifiedClassName == null ? "" : qualifiedClassName;
1808 int periodIndex;
1809 while((periodIndex = packageName.lastIndexOf('.')) != -1) {
1810 className = packageName.substring(periodIndex + 1, packageName.length()) +
1811 (className.length() > 0 ? "." + className : "");
1812 String defaultLabel = code ? getCode() + className + getCodeEnd() : className;
1813 packageName = packageName.substring(0, periodIndex);
1814 if (getCrossPackageLink(packageName) != null) {
1815 //The package exists in external documentation, so link to the external
1816 //class (assuming that it exists). This is definitely a limitation of
1817 //the -link option. There are ways to determine if an external package
1818 //exists, but no way to determine if the external class exists. We just
1819 //have to assume that it does.
1820 return getHyperLinkString(
1821 configuration.extern.getExternalLink(packageName, relativePath,
1822 className + ".html?is-external=true"),
1823 refMemName == null ? "" : refMemName,
1824 label == null || label.length() == 0 ? defaultLabel : label,
1825 strong, style,
1826 configuration.getText("doclet.Href_Class_Or_Interface_Title", packageName),
1827 "");
1828 }
1829 }
1830 return null;
1831 }
1833 public boolean isClassLinkable(ClassDoc cd) {
1834 if (cd.isIncluded()) {
1835 return configuration.isGeneratedDoc(cd);
1836 }
1837 return configuration.extern.isExternal(cd);
1838 }
1840 public String getCrossPackageLink(String pkgName) {
1841 return configuration.extern.getExternalLink(pkgName, relativePath,
1842 "package-summary.html?is-external=true");
1843 }
1845 /**
1846 * Get the class link.
1847 *
1848 * @param context the id of the context where the link will be added
1849 * @param cd the class doc to link to
1850 * @return a content tree for the link
1851 */
1852 public Content getQualifiedClassLink(int context, ClassDoc cd) {
1853 return new RawHtml(getLink(new LinkInfoImpl(context, cd,
1854 configuration.getClassName(cd), "")));
1855 }
1857 /**
1858 * Add the class link.
1859 *
1860 * @param context the id of the context where the link will be added
1861 * @param cd the class doc to link to
1862 * @param contentTree the content tree to which the link will be added
1863 */
1864 public void addPreQualifiedClassLink(int context, ClassDoc cd, Content contentTree) {
1865 addPreQualifiedClassLink(context, cd, false, contentTree);
1866 }
1868 /**
1869 * Retrieve the class link with the package portion of the label in
1870 * plain text. If the qualifier is excluded, it willnot be included in the
1871 * link label.
1872 *
1873 * @param cd the class to link to.
1874 * @param isStrong true if the link should be strong.
1875 * @return the link with the package portion of the label in plain text.
1876 */
1877 public String getPreQualifiedClassLink(int context,
1878 ClassDoc cd, boolean isStrong) {
1879 String classlink = "";
1880 PackageDoc pd = cd.containingPackage();
1881 if(pd != null && ! configuration.shouldExcludeQualifier(pd.name())) {
1882 classlink = getPkgName(cd);
1883 }
1884 classlink += getLink(new LinkInfoImpl(context, cd, cd.name(), isStrong));
1885 return classlink;
1886 }
1888 /**
1889 * Add the class link with the package portion of the label in
1890 * plain text. If the qualifier is excluded, it will not be included in the
1891 * link label.
1892 *
1893 * @param context the id of the context where the link will be added
1894 * @param cd the class to link to
1895 * @param isStrong true if the link should be strong
1896 * @param contentTree the content tree to which the link with be added
1897 */
1898 public void addPreQualifiedClassLink(int context,
1899 ClassDoc cd, boolean isStrong, Content contentTree) {
1900 PackageDoc pd = cd.containingPackage();
1901 if(pd != null && ! configuration.shouldExcludeQualifier(pd.name())) {
1902 contentTree.addContent(getPkgName(cd));
1903 }
1904 contentTree.addContent(new RawHtml(getLink(new LinkInfoImpl(
1905 context, cd, cd.name(), isStrong))));
1906 }
1908 /**
1909 * Add the class link, with only class name as the strong link and prefixing
1910 * plain package name.
1911 *
1912 * @param context the id of the context where the link will be added
1913 * @param cd the class to link to
1914 * @param contentTree the content tree to which the link with be added
1915 */
1916 public void addPreQualifiedStrongClassLink(int context, ClassDoc cd, Content contentTree) {
1917 addPreQualifiedClassLink(context, cd, true, contentTree);
1918 }
1920 public void printText(String key) {
1921 print(configuration.getText(key));
1922 }
1924 public void printText(String key, String a1) {
1925 print(configuration.getText(key, a1));
1926 }
1928 public void printText(String key, String a1, String a2) {
1929 print(configuration.getText(key, a1, a2));
1930 }
1932 public void strongText(String key) {
1933 strong(configuration.getText(key));
1934 }
1936 public void strongText(String key, String a1) {
1937 strong(configuration.getText(key, a1));
1938 }
1940 public void strongText(String key, String a1, String a2) {
1941 strong(configuration.getText(key, a1, a2));
1942 }
1944 /**
1945 * Get the link for the given member.
1946 *
1947 * @param context the id of the context where the link will be added
1948 * @param doc the member being linked to
1949 * @param label the label for the link
1950 * @return a content tree for the doc link
1951 */
1952 public Content getDocLink(int context, MemberDoc doc, String label) {
1953 return getDocLink(context, doc.containingClass(), doc, label);
1954 }
1956 /**
1957 * Print the link for the given member.
1958 *
1959 * @param context the id of the context where the link will be printed.
1960 * @param classDoc the classDoc that we should link to. This is not
1961 * necessarily equal to doc.containingClass(). We may be
1962 * inheriting comments.
1963 * @param doc the member being linked to.
1964 * @param label the label for the link.
1965 * @param strong true if the link should be strong.
1966 */
1967 public void printDocLink(int context, ClassDoc classDoc, MemberDoc doc,
1968 String label, boolean strong) {
1969 print(getDocLink(context, classDoc, doc, label, strong));
1970 }
1972 /**
1973 * Return the link for the given member.
1974 *
1975 * @param context the id of the context where the link will be printed.
1976 * @param doc the member being linked to.
1977 * @param label the label for the link.
1978 * @param strong true if the link should be strong.
1979 * @return the link for the given member.
1980 */
1981 public String getDocLink(int context, MemberDoc doc, String label,
1982 boolean strong) {
1983 return getDocLink(context, doc.containingClass(), doc, label, strong);
1984 }
1986 /**
1987 * Return the link for the given member.
1988 *
1989 * @param context the id of the context where the link will be printed.
1990 * @param classDoc the classDoc that we should link to. This is not
1991 * necessarily equal to doc.containingClass(). We may be
1992 * inheriting comments.
1993 * @param doc the member being linked to.
1994 * @param label the label for the link.
1995 * @param strong true if the link should be strong.
1996 * @return the link for the given member.
1997 */
1998 public String getDocLink(int context, ClassDoc classDoc, MemberDoc doc,
1999 String label, boolean strong) {
2000 if (! (doc.isIncluded() ||
2001 Util.isLinkable(classDoc, configuration()))) {
2002 return label;
2003 } else if (doc instanceof ExecutableMemberDoc) {
2004 ExecutableMemberDoc emd = (ExecutableMemberDoc)doc;
2005 return getLink(new LinkInfoImpl(context, classDoc,
2006 getAnchor(emd), label, strong));
2007 } else if (doc instanceof MemberDoc) {
2008 return getLink(new LinkInfoImpl(context, classDoc,
2009 doc.name(), label, strong));
2010 } else {
2011 return label;
2012 }
2013 }
2015 /**
2016 * Return the link for the given member.
2017 *
2018 * @param context the id of the context where the link will be added
2019 * @param classDoc the classDoc that we should link to. This is not
2020 * necessarily equal to doc.containingClass(). We may be
2021 * inheriting comments
2022 * @param doc the member being linked to
2023 * @param label the label for the link
2024 * @return the link for the given member
2025 */
2026 public Content getDocLink(int context, ClassDoc classDoc, MemberDoc doc,
2027 String label) {
2028 if (! (doc.isIncluded() ||
2029 Util.isLinkable(classDoc, configuration()))) {
2030 return new StringContent(label);
2031 } else if (doc instanceof ExecutableMemberDoc) {
2032 ExecutableMemberDoc emd = (ExecutableMemberDoc)doc;
2033 return new RawHtml(getLink(new LinkInfoImpl(context, classDoc,
2034 getAnchor(emd), label, false)));
2035 } else if (doc instanceof MemberDoc) {
2036 return new RawHtml(getLink(new LinkInfoImpl(context, classDoc,
2037 doc.name(), label, false)));
2038 } else {
2039 return new StringContent(label);
2040 }
2041 }
2043 public void anchor(ExecutableMemberDoc emd) {
2044 anchor(getAnchor(emd));
2045 }
2047 public String getAnchor(ExecutableMemberDoc emd) {
2048 StringBuilder signature = new StringBuilder(emd.signature());
2049 StringBuilder signatureParsed = new StringBuilder();
2050 int counter = 0;
2051 for (int i = 0; i < signature.length(); i++) {
2052 char c = signature.charAt(i);
2053 if (c == '<') {
2054 counter++;
2055 } else if (c == '>') {
2056 counter--;
2057 } else if (counter == 0) {
2058 signatureParsed.append(c);
2059 }
2060 }
2061 return emd.name() + signatureParsed.toString();
2062 }
2064 public String seeTagToString(SeeTag see) {
2065 String tagName = see.name();
2066 if (! (tagName.startsWith("@link") || tagName.equals("@see"))) {
2067 return "";
2068 }
2069 StringBuffer result = new StringBuffer();
2070 boolean isplaintext = tagName.toLowerCase().equals("@linkplain");
2071 String label = see.label();
2072 label = (label.length() > 0)?
2073 ((isplaintext) ? label :
2074 getCode() + label + getCodeEnd()):"";
2075 String seetext = replaceDocRootDir(see.text());
2077 //Check if @see is an href or "string"
2078 if (seetext.startsWith("<") || seetext.startsWith("\"")) {
2079 result.append(seetext);
2080 return result.toString();
2081 }
2083 //The text from the @see tag. We will output this text when a label is not specified.
2084 String text = (isplaintext) ? seetext : getCode() + seetext + getCodeEnd();
2086 ClassDoc refClass = see.referencedClass();
2087 String refClassName = see.referencedClassName();
2088 MemberDoc refMem = see.referencedMember();
2089 String refMemName = see.referencedMemberName();
2090 if (refClass == null) {
2091 //@see is not referencing an included class
2092 PackageDoc refPackage = see.referencedPackage();
2093 if (refPackage != null && refPackage.isIncluded()) {
2094 //@see is referencing an included package
2095 String packageName = isplaintext ? refPackage.name() :
2096 getCode() + refPackage.name() + getCodeEnd();
2097 result.append(getPackageLinkString(refPackage,
2098 label.length() == 0 ? packageName : label, false));
2099 } else {
2100 //@see is not referencing an included class or package. Check for cross links.
2101 String classCrossLink, packageCrossLink = getCrossPackageLink(refClassName);
2102 if (packageCrossLink != null) {
2103 //Package cross link found
2104 result.append(getHyperLinkString(packageCrossLink, "",
2105 (label.length() == 0)? text : label, false));
2106 } else if ((classCrossLink = getCrossClassLink(refClassName,
2107 refMemName, label, false, "", ! isplaintext)) != null) {
2108 //Class cross link found (possiblly to a member in the class)
2109 result.append(classCrossLink);
2110 } else {
2111 //No cross link found so print warning
2112 configuration.getDocletSpecificMsg().warning(see.position(), "doclet.see.class_or_package_not_found",
2113 tagName, seetext);
2114 result.append((label.length() == 0)? text: label);
2115 }
2116 }
2117 } else if (refMemName == null) {
2118 // Must be a class reference since refClass is not null and refMemName is null.
2119 if (label.length() == 0) {
2120 label = (isplaintext) ? refClass.name() : getCode() + refClass.name() + getCodeEnd();
2121 result.append(getLink(new LinkInfoImpl(refClass, label)));
2122 } else {
2123 result.append(getLink(new LinkInfoImpl(refClass, label)));
2124 }
2125 } else if (refMem == null) {
2126 // Must be a member reference since refClass is not null and refMemName is not null.
2127 // However, refMem is null, so this referenced member does not exist.
2128 result.append((label.length() == 0)? text: label);
2129 } else {
2130 // Must be a member reference since refClass is not null and refMemName is not null.
2131 // refMem is not null, so this @see tag must be referencing a valid member.
2132 ClassDoc containing = refMem.containingClass();
2133 if (see.text().trim().startsWith("#") &&
2134 ! (containing.isPublic() ||
2135 Util.isLinkable(containing, configuration()))) {
2136 // Since the link is relative and the holder is not even being
2137 // documented, this must be an inherited link. Redirect it.
2138 // The current class either overrides the referenced member or
2139 // inherits it automatically.
2140 if (this instanceof ClassWriterImpl) {
2141 containing = ((ClassWriterImpl) this).getClassDoc();
2142 } else if (!containing.isPublic()){
2143 configuration.getDocletSpecificMsg().warning(
2144 see.position(), "doclet.see.class_or_package_not_accessible",
2145 tagName, containing.qualifiedName());
2146 } else {
2147 configuration.getDocletSpecificMsg().warning(
2148 see.position(), "doclet.see.class_or_package_not_found",
2149 tagName, seetext);
2150 }
2151 }
2152 if (configuration.currentcd != containing) {
2153 refMemName = containing.name() + "." + refMemName;
2154 }
2155 if (refMem instanceof ExecutableMemberDoc) {
2156 if (refMemName.indexOf('(') < 0) {
2157 refMemName += ((ExecutableMemberDoc)refMem).signature();
2158 }
2159 }
2160 text = (isplaintext) ?
2161 refMemName : getCode() + Util.escapeHtmlChars(refMemName) + getCodeEnd();
2163 result.append(getDocLink(LinkInfoImpl.CONTEXT_SEE_TAG, containing,
2164 refMem, (label.length() == 0)? text: label, false));
2165 }
2166 return result.toString();
2167 }
2169 public void printInlineComment(Doc doc, Tag tag) {
2170 printCommentTags(doc, tag.inlineTags(), false, false);
2171 }
2173 /**
2174 * Add the inline comment.
2175 *
2176 * @param doc the doc for which the inline comment will be added
2177 * @param tag the inline tag to be added
2178 * @param htmltree the content tree to which the comment will be added
2179 */
2180 public void addInlineComment(Doc doc, Tag tag, Content htmltree) {
2181 addCommentTags(doc, tag.inlineTags(), false, false, htmltree);
2182 }
2184 public void printInlineDeprecatedComment(Doc doc, Tag tag) {
2185 printCommentTags(doc, tag.inlineTags(), true, false);
2186 }
2188 /**
2189 * Add the inline deprecated comment.
2190 *
2191 * @param doc the doc for which the inline deprecated comment will be added
2192 * @param tag the inline tag to be added
2193 * @param htmltree the content tree to which the comment will be added
2194 */
2195 public void addInlineDeprecatedComment(Doc doc, Tag tag, Content htmltree) {
2196 addCommentTags(doc, tag.inlineTags(), true, false, htmltree);
2197 }
2199 public void printSummaryComment(Doc doc) {
2200 printSummaryComment(doc, doc.firstSentenceTags());
2201 }
2203 /**
2204 * Adds the summary content.
2205 *
2206 * @param doc the doc for which the summary will be generated
2207 * @param htmltree the documentation tree to which the summary will be added
2208 */
2209 public void addSummaryComment(Doc doc, Content htmltree) {
2210 addSummaryComment(doc, doc.firstSentenceTags(), htmltree);
2211 }
2213 public void printSummaryComment(Doc doc, Tag[] firstSentenceTags) {
2214 printCommentTags(doc, firstSentenceTags, false, true);
2215 }
2217 /**
2218 * Adds the summary content.
2219 *
2220 * @param doc the doc for which the summary will be generated
2221 * @param firstSentenceTags the first sentence tags for the doc
2222 * @param htmltree the documentation tree to which the summary will be added
2223 */
2224 public void addSummaryComment(Doc doc, Tag[] firstSentenceTags, Content htmltree) {
2225 addCommentTags(doc, firstSentenceTags, false, true, htmltree);
2226 }
2228 public void printSummaryDeprecatedComment(Doc doc) {
2229 printCommentTags(doc, doc.firstSentenceTags(), true, true);
2230 }
2232 public void printSummaryDeprecatedComment(Doc doc, Tag tag) {
2233 printCommentTags(doc, tag.firstSentenceTags(), true, true);
2234 }
2236 public void addSummaryDeprecatedComment(Doc doc, Tag tag, Content htmltree) {
2237 addCommentTags(doc, tag.firstSentenceTags(), true, true, htmltree);
2238 }
2240 public void printInlineComment(Doc doc) {
2241 printCommentTags(doc, doc.inlineTags(), false, false);
2242 p();
2243 }
2245 /**
2246 * Adds the inline comment.
2247 *
2248 * @param doc the doc for which the inline comments will be generated
2249 * @param htmltree the documentation tree to which the inline comments will be added
2250 */
2251 public void addInlineComment(Doc doc, Content htmltree) {
2252 addCommentTags(doc, doc.inlineTags(), false, false, htmltree);
2253 }
2255 public void printInlineDeprecatedComment(Doc doc) {
2256 printCommentTags(doc, doc.inlineTags(), true, false);
2257 }
2259 private void printCommentTags(Doc doc, Tag[] tags, boolean depr, boolean first) {
2260 if(configuration.nocomment){
2261 return;
2262 }
2263 if (depr) {
2264 italic();
2265 }
2266 String result = commentTagsToString(null, doc, tags, first);
2267 print(result);
2268 if (depr) {
2269 italicEnd();
2270 }
2271 if (tags.length == 0) {
2272 space();
2273 }
2274 }
2276 /**
2277 * Adds the comment tags.
2278 *
2279 * @param doc the doc for which the comment tags will be generated
2280 * @param tags the first sentence tags for the doc
2281 * @param depr true if it is deprecated
2282 * @param first true if the first sentenge tags should be added
2283 * @param htmltree the documentation tree to which the comment tags will be added
2284 */
2285 private void addCommentTags(Doc doc, Tag[] tags, boolean depr,
2286 boolean first, Content htmltree) {
2287 if(configuration.nocomment){
2288 return;
2289 }
2290 Content div;
2291 Content result = new RawHtml(commentTagsToString(null, doc, tags, first));
2292 if (depr) {
2293 Content italic = HtmlTree.I(result);
2294 div = HtmlTree.DIV(HtmlStyle.block, italic);
2295 htmltree.addContent(div);
2296 }
2297 else {
2298 div = HtmlTree.DIV(HtmlStyle.block, result);
2299 htmltree.addContent(div);
2300 }
2301 if (tags.length == 0) {
2302 htmltree.addContent(getSpace());
2303 }
2304 }
2306 /**
2307 * Converts inline tags and text to text strings, expanding the
2308 * inline tags along the way. Called wherever text can contain
2309 * an inline tag, such as in comments or in free-form text arguments
2310 * to non-inline tags.
2311 *
2312 * @param holderTag specific tag where comment resides
2313 * @param doc specific doc where comment resides
2314 * @param tags array of text tags and inline tags (often alternating)
2315 * present in the text of interest for this doc
2316 * @param isFirstSentence true if text is first sentence
2317 */
2318 public String commentTagsToString(Tag holderTag, Doc doc, Tag[] tags,
2319 boolean isFirstSentence) {
2320 StringBuilder result = new StringBuilder();
2321 // Array of all possible inline tags for this javadoc run
2322 configuration.tagletManager.checkTags(doc, tags, true);
2323 for (int i = 0; i < tags.length; i++) {
2324 Tag tagelem = tags[i];
2325 String tagName = tagelem.name();
2326 if (tagelem instanceof SeeTag) {
2327 result.append(seeTagToString((SeeTag)tagelem));
2328 } else if (! tagName.equals("Text")) {
2329 int originalLength = result.length();
2330 TagletOutput output = TagletWriter.getInlineTagOuput(
2331 configuration.tagletManager, holderTag,
2332 tagelem, getTagletWriterInstance(isFirstSentence));
2333 result.append(output == null ? "" : output.toString());
2334 if (originalLength == 0 && isFirstSentence && tagelem.name().equals("@inheritDoc") && result.length() > 0) {
2335 break;
2336 } else {
2337 continue;
2338 }
2339 } else {
2340 //This is just a regular text tag. The text may contain html links (<a>)
2341 //or inline tag {@docRoot}, which will be handled as special cases.
2342 String text = redirectRelativeLinks(tagelem.holder(), tagelem.text());
2344 // Replace @docRoot only if not represented by an instance of DocRootTaglet,
2345 // that is, only if it was not present in a source file doc comment.
2346 // This happens when inserted by the doclet (a few lines
2347 // above in this method). [It might also happen when passed in on the command
2348 // line as a text argument to an option (like -header).]
2349 text = replaceDocRootDir(text);
2350 if (isFirstSentence) {
2351 text = removeNonInlineHtmlTags(text);
2352 }
2353 StringTokenizer lines = new StringTokenizer(text, "\r\n", true);
2354 StringBuffer textBuff = new StringBuffer();
2355 while (lines.hasMoreTokens()) {
2356 StringBuilder line = new StringBuilder(lines.nextToken());
2357 Util.replaceTabs(configuration.sourcetab, line);
2358 textBuff.append(line.toString());
2359 }
2360 result.append(textBuff);
2361 }
2362 }
2363 return result.toString();
2364 }
2366 /**
2367 * Return true if relative links should not be redirected.
2368 *
2369 * @return Return true if a relative link should not be redirected.
2370 */
2371 private boolean shouldNotRedirectRelativeLinks() {
2372 return this instanceof AnnotationTypeWriter ||
2373 this instanceof ClassWriter ||
2374 this instanceof PackageSummaryWriter;
2375 }
2377 /**
2378 * Suppose a piece of documentation has a relative link. When you copy
2379 * that documetation to another place such as the index or class-use page,
2380 * that relative link will no longer work. We should redirect those links
2381 * so that they will work again.
2382 * <p>
2383 * Here is the algorithm used to fix the link:
2384 * <p>
2385 * <relative link> => docRoot + <relative path to file> + <relative link>
2386 * <p>
2387 * For example, suppose com.sun.javadoc.RootDoc has this link:
2388 * <a href="package-summary.html">The package Page</a>
2389 * <p>
2390 * If this link appeared in the index, we would redirect
2391 * the link like this:
2392 *
2393 * <a href="./com/sun/javadoc/package-summary.html">The package Page</a>
2394 *
2395 * @param doc the Doc object whose documentation is being written.
2396 * @param text the text being written.
2397 *
2398 * @return the text, with all the relative links redirected to work.
2399 */
2400 private String redirectRelativeLinks(Doc doc, String text) {
2401 if (doc == null || shouldNotRedirectRelativeLinks()) {
2402 return text;
2403 }
2405 String redirectPathFromRoot;
2406 if (doc instanceof ClassDoc) {
2407 redirectPathFromRoot = DirectoryManager.getDirectoryPath(((ClassDoc) doc).containingPackage());
2408 } else if (doc instanceof MemberDoc) {
2409 redirectPathFromRoot = DirectoryManager.getDirectoryPath(((MemberDoc) doc).containingPackage());
2410 } else if (doc instanceof PackageDoc) {
2411 redirectPathFromRoot = DirectoryManager.getDirectoryPath((PackageDoc) doc);
2412 } else {
2413 return text;
2414 }
2416 if (! redirectPathFromRoot.endsWith(DirectoryManager.URL_FILE_SEPARATOR)) {
2417 redirectPathFromRoot += DirectoryManager.URL_FILE_SEPARATOR;
2418 }
2420 //Redirect all relative links.
2421 int end, begin = text.toLowerCase().indexOf("<a");
2422 if(begin >= 0){
2423 StringBuffer textBuff = new StringBuffer(text);
2425 while(begin >=0){
2426 if (textBuff.length() > begin + 2 && ! Character.isWhitespace(textBuff.charAt(begin+2))) {
2427 begin = textBuff.toString().toLowerCase().indexOf("<a", begin + 1);
2428 continue;
2429 }
2431 begin = textBuff.indexOf("=", begin) + 1;
2432 end = textBuff.indexOf(">", begin +1);
2433 if(begin == 0){
2434 //Link has no equal symbol.
2435 configuration.root.printWarning(
2436 doc.position(),
2437 configuration.getText("doclet.malformed_html_link_tag", text));
2438 break;
2439 }
2440 if (end == -1) {
2441 //Break without warning. This <a> tag is not necessarily malformed. The text
2442 //might be missing '>' character because the href has an inline tag.
2443 break;
2444 }
2445 if(textBuff.substring(begin, end).indexOf("\"") != -1){
2446 begin = textBuff.indexOf("\"", begin) + 1;
2447 end = textBuff.indexOf("\"", begin +1);
2448 if(begin == 0 || end == -1){
2449 //Link is missing a quote.
2450 break;
2451 }
2452 }
2453 String relativeLink = textBuff.substring(begin, end);
2454 if(!(relativeLink.toLowerCase().startsWith("mailto:") ||
2455 relativeLink.toLowerCase().startsWith("http:") ||
2456 relativeLink.toLowerCase().startsWith("https:") ||
2457 relativeLink.toLowerCase().startsWith("file:"))){
2458 relativeLink = "{@"+(new DocRootTaglet()).getName() + "}"
2459 + redirectPathFromRoot
2460 + relativeLink;
2461 textBuff.replace(begin, end, relativeLink);
2462 }
2463 begin = textBuff.toString().toLowerCase().indexOf("<a", begin + 1);
2464 }
2465 return textBuff.toString();
2466 }
2467 return text;
2468 }
2470 public String removeNonInlineHtmlTags(String text) {
2471 if (text.indexOf('<') < 0) {
2472 return text;
2473 }
2474 String noninlinetags[] = { "<ul>", "</ul>", "<ol>", "</ol>",
2475 "<dl>", "</dl>", "<table>", "</table>",
2476 "<tr>", "</tr>", "<td>", "</td>",
2477 "<th>", "</th>", "<p>", "</p>",
2478 "<li>", "</li>", "<dd>", "</dd>",
2479 "<dir>", "</dir>", "<dt>", "</dt>",
2480 "<h1>", "</h1>", "<h2>", "</h2>",
2481 "<h3>", "</h3>", "<h4>", "</h4>",
2482 "<h5>", "</h5>", "<h6>", "</h6>",
2483 "<pre>", "</pre>", "<menu>", "</menu>",
2484 "<listing>", "</listing>", "<hr>",
2485 "<blockquote>", "</blockquote>",
2486 "<center>", "</center>",
2487 "<UL>", "</UL>", "<OL>", "</OL>",
2488 "<DL>", "</DL>", "<TABLE>", "</TABLE>",
2489 "<TR>", "</TR>", "<TD>", "</TD>",
2490 "<TH>", "</TH>", "<P>", "</P>",
2491 "<LI>", "</LI>", "<DD>", "</DD>",
2492 "<DIR>", "</DIR>", "<DT>", "</DT>",
2493 "<H1>", "</H1>", "<H2>", "</H2>",
2494 "<H3>", "</H3>", "<H4>", "</H4>",
2495 "<H5>", "</H5>", "<H6>", "</H6>",
2496 "<PRE>", "</PRE>", "<MENU>", "</MENU>",
2497 "<LISTING>", "</LISTING>", "<HR>",
2498 "<BLOCKQUOTE>", "</BLOCKQUOTE>",
2499 "<CENTER>", "</CENTER>"
2500 };
2501 for (int i = 0; i < noninlinetags.length; i++) {
2502 text = replace(text, noninlinetags[i], "");
2503 }
2504 return text;
2505 }
2507 public String replace(String text, String tobe, String by) {
2508 while (true) {
2509 int startindex = text.indexOf(tobe);
2510 if (startindex < 0) {
2511 return text;
2512 }
2513 int endindex = startindex + tobe.length();
2514 StringBuilder replaced = new StringBuilder();
2515 if (startindex > 0) {
2516 replaced.append(text.substring(0, startindex));
2517 }
2518 replaced.append(by);
2519 if (text.length() > endindex) {
2520 replaced.append(text.substring(endindex));
2521 }
2522 text = replaced.toString();
2523 }
2524 }
2526 public void printStyleSheetProperties() {
2527 String filename = configuration.stylesheetfile;
2528 if (filename.length() > 0) {
2529 File stylefile = new File(filename);
2530 String parent = stylefile.getParent();
2531 filename = (parent == null)?
2532 filename:
2533 filename.substring(parent.length() + 1);
2534 } else {
2535 filename = "stylesheet.css";
2536 }
2537 filename = relativePath + filename;
2538 link("REL =\"stylesheet\" TYPE=\"text/css\" HREF=\"" +
2539 filename + "\" " + "TITLE=\"Style\"");
2540 }
2542 /**
2543 * Returns a link to the stylesheet file.
2544 *
2545 * @return an HtmlTree for the lINK tag which provides the stylesheet location
2546 */
2547 public HtmlTree getStyleSheetProperties() {
2548 String filename = configuration.stylesheetfile;
2549 if (filename.length() > 0) {
2550 File stylefile = new File(filename);
2551 String parent = stylefile.getParent();
2552 filename = (parent == null)?
2553 filename:
2554 filename.substring(parent.length() + 1);
2555 } else {
2556 filename = "stylesheet.css";
2557 }
2558 filename = relativePath + filename;
2559 HtmlTree link = HtmlTree.LINK("stylesheet", "text/css", filename, "Style");
2560 return link;
2561 }
2563 /**
2564 * According to
2565 * <cite>The Java™ Language Specification</cite>,
2566 * all the outer classes and static nested classes are core classes.
2567 */
2568 public boolean isCoreClass(ClassDoc cd) {
2569 return cd.containingClass() == null || cd.isStatic();
2570 }
2572 /**
2573 * Write the annotatation types for the given packageDoc.
2574 *
2575 * @param packageDoc the package to write annotations for.
2576 */
2577 public void writeAnnotationInfo(PackageDoc packageDoc) {
2578 writeAnnotationInfo(packageDoc, packageDoc.annotations());
2579 }
2581 /**
2582 * Adds the annotatation types for the given packageDoc.
2583 *
2584 * @param packageDoc the package to write annotations for.
2585 * @param htmltree the documentation tree to which the annotation info will be
2586 * added
2587 */
2588 public void addAnnotationInfo(PackageDoc packageDoc, Content htmltree) {
2589 addAnnotationInfo(packageDoc, packageDoc.annotations(), htmltree);
2590 }
2592 /**
2593 * Write the annotatation types for the given doc.
2594 *
2595 * @param doc the doc to write annotations for.
2596 */
2597 public void writeAnnotationInfo(ProgramElementDoc doc) {
2598 writeAnnotationInfo(doc, doc.annotations());
2599 }
2601 /**
2602 * Adds the annotatation types for the given doc.
2603 *
2604 * @param packageDoc the package to write annotations for
2605 * @param htmltree the content tree to which the annotation types will be added
2606 */
2607 public void addAnnotationInfo(ProgramElementDoc doc, Content htmltree) {
2608 addAnnotationInfo(doc, doc.annotations(), htmltree);
2609 }
2611 /**
2612 * Write the annotatation types for the given doc and parameter.
2613 *
2614 * @param indent the number of spaced to indent the parameters.
2615 * @param doc the doc to write annotations for.
2616 * @param param the parameter to write annotations for.
2617 */
2618 public boolean writeAnnotationInfo(int indent, Doc doc, Parameter param) {
2619 return writeAnnotationInfo(indent, doc, param.annotations(), false);
2620 }
2622 /**
2623 * Add the annotatation types for the given doc and parameter.
2624 *
2625 * @param indent the number of spaces to indent the parameters.
2626 * @param doc the doc to write annotations for.
2627 * @param param the parameter to write annotations for.
2628 * @param tree the content tree to which the annotation types will be added
2629 */
2630 public boolean addAnnotationInfo(int indent, Doc doc, Parameter param,
2631 Content tree) {
2632 return addAnnotationInfo(indent, doc, param.annotations(), false, tree);
2633 }
2635 /**
2636 * Write the annotatation types for the given doc.
2637 *
2638 * @param doc the doc to write annotations for.
2639 * @param descList the array of {@link AnnotationDesc}.
2640 */
2641 private void writeAnnotationInfo(Doc doc, AnnotationDesc[] descList) {
2642 writeAnnotationInfo(0, doc, descList, true);
2643 }
2645 /**
2646 * Adds the annotatation types for the given doc.
2647 *
2648 * @param doc the doc to write annotations for.
2649 * @param descList the array of {@link AnnotationDesc}.
2650 * @param htmltree the documentation tree to which the annotation info will be
2651 * added
2652 */
2653 private void addAnnotationInfo(Doc doc, AnnotationDesc[] descList,
2654 Content htmltree) {
2655 addAnnotationInfo(0, doc, descList, true, htmltree);
2656 }
2658 /**
2659 * Write the annotatation types for the given doc.
2660 *
2661 * @param indent the number of extra spaces to indent the annotations.
2662 * @param doc the doc to write annotations for.
2663 * @param descList the array of {@link AnnotationDesc}.
2664 */
2665 private boolean writeAnnotationInfo(int indent, Doc doc, AnnotationDesc[] descList, boolean lineBreak) {
2666 List<String> annotations = getAnnotations(indent, descList, lineBreak);
2667 if (annotations.size() == 0) {
2668 return false;
2669 }
2670 fontNoNewLine("-1");
2671 for (Iterator<String> iter = annotations.iterator(); iter.hasNext();) {
2672 print(iter.next());
2673 }
2674 fontEnd();
2675 return true;
2676 }
2678 /**
2679 * Adds the annotatation types for the given doc.
2680 *
2681 * @param indent the number of extra spaces to indent the annotations.
2682 * @param doc the doc to write annotations for.
2683 * @param descList the array of {@link AnnotationDesc}.
2684 * @param htmltree the documentation tree to which the annotation info will be
2685 * added
2686 */
2687 private boolean addAnnotationInfo(int indent, Doc doc,
2688 AnnotationDesc[] descList, boolean lineBreak, Content htmltree) {
2689 List<String> annotations = getAnnotations(indent, descList, lineBreak);
2690 if (annotations.size() == 0) {
2691 return false;
2692 }
2693 Content annotationContent;
2694 for (Iterator<String> iter = annotations.iterator(); iter.hasNext();) {
2695 annotationContent = new RawHtml(iter.next());
2696 htmltree.addContent(annotationContent);
2697 }
2698 return true;
2699 }
2701 /**
2702 * Return the string representations of the annotation types for
2703 * the given doc.
2704 *
2705 * @param indent the number of extra spaces to indent the annotations.
2706 * @param descList the array of {@link AnnotationDesc}.
2707 * @param linkBreak if true, add new line between each member value.
2708 * @return an array of strings representing the annotations being
2709 * documented.
2710 */
2711 private List<String> getAnnotations(int indent, AnnotationDesc[] descList, boolean linkBreak) {
2712 List<String> results = new ArrayList<String>();
2713 StringBuffer annotation;
2714 for (int i = 0; i < descList.length; i++) {
2715 AnnotationTypeDoc annotationDoc = descList[i].annotationType();
2716 if (! Util.isDocumentedAnnotation(annotationDoc)){
2717 continue;
2718 }
2719 annotation = new StringBuffer();
2720 LinkInfoImpl linkInfo = new LinkInfoImpl(
2721 LinkInfoImpl.CONTEXT_ANNOTATION, annotationDoc);
2722 linkInfo.label = "@" + annotationDoc.name();
2723 annotation.append(getLink(linkInfo));
2724 AnnotationDesc.ElementValuePair[] pairs = descList[i].elementValues();
2725 if (pairs.length > 0) {
2726 annotation.append('(');
2727 for (int j = 0; j < pairs.length; j++) {
2728 if (j > 0) {
2729 annotation.append(",");
2730 if (linkBreak) {
2731 annotation.append(DocletConstants.NL);
2732 int spaces = annotationDoc.name().length() + 2;
2733 for (int k = 0; k < (spaces + indent); k++) {
2734 annotation.append(' ');
2735 }
2736 }
2737 }
2738 annotation.append(getDocLink(LinkInfoImpl.CONTEXT_ANNOTATION,
2739 pairs[j].element(), pairs[j].element().name(), false));
2740 annotation.append('=');
2741 AnnotationValue annotationValue = pairs[j].value();
2742 List<AnnotationValue> annotationTypeValues = new ArrayList<AnnotationValue>();
2743 if (annotationValue.value() instanceof AnnotationValue[]) {
2744 AnnotationValue[] annotationArray =
2745 (AnnotationValue[]) annotationValue.value();
2746 for (int k = 0; k < annotationArray.length; k++) {
2747 annotationTypeValues.add(annotationArray[k]);
2748 }
2749 } else {
2750 annotationTypeValues.add(annotationValue);
2751 }
2752 annotation.append(annotationTypeValues.size() == 1 ? "" : "{");
2753 for (Iterator<AnnotationValue> iter = annotationTypeValues.iterator(); iter.hasNext(); ) {
2754 annotation.append(annotationValueToString(iter.next()));
2755 annotation.append(iter.hasNext() ? "," : "");
2756 }
2757 annotation.append(annotationTypeValues.size() == 1 ? "" : "}");
2758 }
2759 annotation.append(")");
2760 }
2761 annotation.append(linkBreak ? DocletConstants.NL : "");
2762 results.add(annotation.toString());
2763 }
2764 return results;
2765 }
2767 private String annotationValueToString(AnnotationValue annotationValue) {
2768 if (annotationValue.value() instanceof Type) {
2769 Type type = (Type) annotationValue.value();
2770 if (type.asClassDoc() != null) {
2771 LinkInfoImpl linkInfo = new LinkInfoImpl(
2772 LinkInfoImpl.CONTEXT_ANNOTATION, type);
2773 linkInfo.label = (type.asClassDoc().isIncluded() ?
2774 type.typeName() :
2775 type.qualifiedTypeName()) + type.dimension() + ".class";
2776 return getLink(linkInfo);
2777 } else {
2778 return type.typeName() + type.dimension() + ".class";
2779 }
2780 } else if (annotationValue.value() instanceof AnnotationDesc) {
2781 List<String> list = getAnnotations(0,
2782 new AnnotationDesc[]{(AnnotationDesc) annotationValue.value()},
2783 false);
2784 StringBuffer buf = new StringBuffer();
2785 for (Iterator<String> iter = list.iterator(); iter.hasNext(); ) {
2786 buf.append(iter.next());
2787 }
2788 return buf.toString();
2789 } else if (annotationValue.value() instanceof MemberDoc) {
2790 return getDocLink(LinkInfoImpl.CONTEXT_ANNOTATION,
2791 (MemberDoc) annotationValue.value(),
2792 ((MemberDoc) annotationValue.value()).name(), false);
2793 } else {
2794 return annotationValue.toString();
2795 }
2796 }
2798 /**
2799 * Return the configuation for this doclet.
2800 *
2801 * @return the configuration for this doclet.
2802 */
2803 public Configuration configuration() {
2804 return configuration;
2805 }
2806 }