Thu, 02 Oct 2008 19:58:40 -0700
6754988: Update copyright year
Summary: Update for files that have been modified starting July 2008
Reviewed-by: ohair, tbell
1 /*
2 * Copyright 1998-2008 Sun Microsystems, Inc. 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. Sun designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
22 * CA 95054 USA or visit www.sun.com if you need additional information or
23 * have any questions.
24 */
26 package com.sun.tools.doclets.formats.html;
27 import com.sun.tools.doclets.formats.html.markup.*;
29 import com.sun.tools.doclets.internal.toolkit.*;
30 import com.sun.tools.doclets.internal.toolkit.util.*;
31 import com.sun.tools.doclets.internal.toolkit.taglets.*;
33 import com.sun.javadoc.*;
34 import java.io.*;
35 import java.text.SimpleDateFormat;
36 import java.util.*;
39 /**
40 * Class for the Html Format Code Generation specific to JavaDoc.
41 * This Class contains methods related to the Html Code Generation which
42 * are used extensively while generating the entire documentation.
43 *
44 * @since 1.2
45 * @author Atul M Dambalkar
46 * @author Robert Field
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 * Constructor to construct the HtmlStandardWriter object.
92 *
93 * @param filename File to be generated.
94 */
95 public HtmlDocletWriter(ConfigurationImpl configuration,
96 String filename) throws IOException {
97 super(configuration, filename);
98 this.configuration = configuration;
99 this.filename = filename;
100 }
102 /**
103 * Constructor to construct the HtmlStandardWriter object.
104 *
105 * @param path Platform-dependent {@link #path} used when
106 * creating file.
107 * @param filename Name of file to be generated.
108 * @param relativePath Value for the variable {@link #relativePath}.
109 */
110 public HtmlDocletWriter(ConfigurationImpl configuration,
111 String path, String filename,
112 String relativePath) throws IOException {
113 super(configuration, path, filename);
114 this.configuration = configuration;
115 this.path = path;
116 this.relativePath = relativePath;
117 this.relativepathNoSlash =
118 DirectoryManager.getPathNoTrailingSlash(this.relativePath);
119 this.filename = filename;
120 }
122 /**
123 * Replace {@docRoot} tag used in options that accept HTML text, such
124 * as -header, -footer, -top and -bottom, and when converting a relative
125 * HREF where commentTagsToString inserts a {@docRoot} where one was
126 * missing. (Also see DocRootTaglet for {@docRoot} tags in doc
127 * comments.)
128 * <p>
129 * Replace {@docRoot} tag in htmlstr with the relative path to the
130 * destination directory from the directory where the file is being
131 * written, looping to handle all such tags in htmlstr.
132 * <p>
133 * For example, for "-d docs" and -header containing {@docRoot}, when
134 * the HTML page for source file p/C1.java is being generated, the
135 * {@docRoot} tag would be inserted into the header as "../",
136 * the relative path from docs/p/ to docs/ (the document root).
137 * <p>
138 * Note: This doc comment was written with '&#064;' representing '@'
139 * to prevent the inline tag from being interpreted.
140 */
141 public String replaceDocRootDir(String htmlstr) {
142 // Return if no inline tags exist
143 int index = htmlstr.indexOf("{@");
144 if (index < 0) {
145 return htmlstr;
146 }
147 String lowerHtml = htmlstr.toLowerCase();
148 // Return index of first occurrence of {@docroot}
149 // Note: {@docRoot} is not case sensitive when passed in w/command line option
150 index = lowerHtml.indexOf("{@docroot}", index);
151 if (index < 0) {
152 return htmlstr;
153 }
154 StringBuffer buf = new StringBuffer();
155 int previndex = 0;
156 while (true) {
157 // Search for lowercase version of {@docRoot}
158 index = lowerHtml.indexOf("{@docroot}", previndex);
159 // If next {@docRoot} tag not found, append rest of htmlstr and exit loop
160 if (index < 0) {
161 buf.append(htmlstr.substring(previndex));
162 break;
163 }
164 // If next {@docroot} tag found, append htmlstr up to start of tag
165 buf.append(htmlstr.substring(previndex, index));
166 previndex = index + 10; // length for {@docroot} string
167 // Insert relative path where {@docRoot} was located
168 buf.append(relativepathNoSlash);
169 // Append slash if next character is not a slash
170 if (relativepathNoSlash.length() > 0 && previndex < htmlstr.length()
171 && htmlstr.charAt(previndex) != '/') {
172 buf.append(DirectoryManager.URL_FILE_SEPERATOR);
173 }
174 }
175 return buf.toString();
176 }
178 /**
179 * Print Html Hyper Link, with target frame. This
180 * link will only appear if page is not in a frame.
181 *
182 * @param link String name of the file.
183 * @param where Position in the file
184 * @param target Name of the target frame.
185 * @param label Tag for the link.
186 * @param bold Whether the label should be bold or not?
187 */
188 public void printNoFramesTargetHyperLink(String link, String where,
189 String target, String label,
190 boolean bold) {
191 script();
192 println(" <!--");
193 println(" if(window==top) {");
194 println(" document.writeln('"
195 + getHyperLink(link, where, label, bold, "", "", target) + "');");
196 println(" }");
197 println(" //-->");
198 scriptEnd();
199 noScript();
200 println(" " + getHyperLink(link, where, label, bold, "", "", target));
201 noScriptEnd();
202 println(DocletConstants.NL);
203 }
205 private void printMethodInfo(MethodDoc method) {
206 ClassDoc[] intfacs = method.containingClass().interfaces();
207 MethodDoc overriddenMethod = method.overriddenMethod();
208 if (intfacs.length > 0 || overriddenMethod != null) {
209 dd();
210 printTagsInfoHeader();
211 MethodWriterImpl.printImplementsInfo(this, method);
212 if (overriddenMethod != null) {
213 MethodWriterImpl.printOverridden(this,
214 method.overriddenType(), overriddenMethod);
215 }
216 printTagsInfoFooter();
217 ddEnd();
218 }
219 dd();
220 }
222 protected void printTags(Doc doc) {
223 if(configuration.nocomment){
224 return;
225 }
226 if (doc instanceof MethodDoc) {
227 printMethodInfo((MethodDoc) doc);
228 }
229 TagletOutputImpl output = new TagletOutputImpl("");
230 TagletWriter.genTagOuput(configuration.tagletManager, doc,
231 configuration.tagletManager.getCustomTags(doc),
232 getTagletWriterInstance(false), output);
233 if (output.toString().trim().length() > 0) {
234 printTagsInfoHeader();
235 print(output.toString());
236 printTagsInfoFooter();
237 } else if (! (doc instanceof ConstructorDoc ||
238 doc instanceof RootDoc || doc instanceof ClassDoc)) {
239 //To be consistent with 1.4.2 output.
240 //I hate to do this but we have to pass the diff test to prove
241 //nothing has broken.
242 printTagsInfoHeader();
243 printTagsInfoFooter();
244 }
245 }
247 /**
248 * Returns a TagletWriter that knows how to write HTML.
249 *
250 * @return a TagletWriter that knows how to write HTML.
251 */
252 public TagletWriter getTagletWriterInstance(boolean isFirstSentence) {
253 return new TagletWriterImpl(this, isFirstSentence);
254 }
256 protected void printTagsInfoHeader() {
257 dl();
258 }
260 protected void printTagsInfoFooter() {
261 dlEnd();
262 }
264 /**
265 * Print Package link, with target frame.
266 *
267 * @param pd The link will be to the "package-summary.html" page for this
268 * package.
269 * @param target Name of the target frame.
270 * @param label Tag for the link.
271 */
272 public void printTargetPackageLink(PackageDoc pd, String target,
273 String label) {
274 print(getHyperLink(pathString(pd, "package-summary.html"), "", label,
275 false, "", "", target));
276 }
278 /**
279 * Print the html file header. Also print Html page title and stylesheet
280 * default properties.
281 *
282 * @param title String window title to go in the <TITLE> tag
283 * @param metakeywords Array of String keywords for META tag. Each element
284 * of the array is assigned to a separate META tag.
285 * Pass in null for no array.
286 * @param includeScript boolean true if printing windowtitle script.
287 * False for files that appear in the left-hand frames.
288 */
289 public void printHtmlHeader(String title, String[] metakeywords,
290 boolean includeScript) {
291 println("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 " +
292 "Transitional//EN\" " +
293 "\"http://www.w3.org/TR/html4/loose.dtd\">");
294 println("<!--NewPage-->");
295 html();
296 head();
297 if (! configuration.notimestamp) {
298 print("<!-- Generated by javadoc (build " + ConfigurationImpl.BUILD_DATE + ") on ");
299 print(today());
300 println(" -->");
301 }
302 if (configuration.charset.length() > 0) {
303 println("<META http-equiv=\"Content-Type\" content=\"text/html; "
304 + "charset=" + configuration.charset + "\">");
305 }
306 if ( configuration.windowtitle.length() > 0 ) {
307 title += " (" + configuration.windowtitle + ")";
308 }
309 title(title);
310 println(title);
311 titleEnd();
312 println("");
313 if (! configuration.notimestamp) {
314 SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
315 println("<META NAME=\"date\" "
316 + "CONTENT=\"" + dateFormat.format(new Date()) + "\">");
317 }
318 if ( metakeywords != null ) {
319 for ( int i=0; i < metakeywords.length; i++ ) {
320 println("<META NAME=\"keywords\" "
321 + "CONTENT=\"" + metakeywords[i] + "\">");
322 }
323 }
324 println("");
325 printStyleSheetProperties();
326 println("");
327 // Don't print windowtitle script for overview-frame, allclasses-frame
328 // and package-frame
329 if (includeScript) {
330 printWinTitleScript(title);
331 }
332 println("");
333 headEnd();
334 println("");
335 body("white", includeScript);
336 }
338 /**
339 * Print user specified header and the footer.
340 *
341 * @param header if true print the user provided header else print the
342 * user provided footer.
343 */
344 public void printUserHeaderFooter(boolean header) {
345 em();
346 if (header) {
347 print(replaceDocRootDir(configuration.header));
348 } else {
349 if (configuration.footer.length() != 0) {
350 print(replaceDocRootDir(configuration.footer));
351 } else {
352 print(replaceDocRootDir(configuration.header));
353 }
354 }
355 emEnd();
356 }
358 /**
359 * Print the user specified top.
360 */
361 public void printTop() {
362 print(replaceDocRootDir(configuration.top));
363 hr();
364 }
366 /**
367 * Print the user specified bottom.
368 */
369 public void printBottom() {
370 hr();
371 print(replaceDocRootDir(configuration.bottom));
372 }
374 /**
375 * Print the navigation bar for the Html page at the top and and the bottom.
376 *
377 * @param header If true print navigation bar at the top of the page else
378 * print the nevigation bar at the bottom.
379 */
380 protected void navLinks(boolean header) {
381 println("");
382 if (!configuration.nonavbar) {
383 if (header) {
384 println(DocletConstants.NL + "<!-- ========= START OF TOP NAVBAR ======= -->");
385 anchor("navbar_top");
386 println();
387 print(getHyperLink("", "skip-navbar_top", "", false, "",
388 configuration.getText("doclet.Skip_navigation_links"), ""));
389 } else {
390 println(DocletConstants.NL + "<!-- ======= START OF BOTTOM NAVBAR ====== -->");
391 anchor("navbar_bottom");
392 println();
393 print(getHyperLink("", "skip-navbar_bottom", "", false, "",
394 configuration.getText("doclet.Skip_navigation_links"), ""));
395 }
396 table(0, "100%", 1, 0);
397 tr();
398 tdColspanBgcolorStyle(2, "#EEEEFF", "NavBarCell1");
399 println("");
400 if (header) {
401 anchor("navbar_top_firstrow");
402 } else {
403 anchor("navbar_bottom_firstrow");
404 }
405 table(0, 0, 3);
406 print(" ");
407 trAlignVAlign("center", "top");
409 if (configuration.createoverview) {
410 navLinkContents();
411 }
413 if (configuration.packages.length == 1) {
414 navLinkPackage(configuration.packages[0]);
415 } else if (configuration.packages.length > 1) {
416 navLinkPackage();
417 }
419 navLinkClass();
421 if(configuration.classuse) {
422 navLinkClassUse();
423 }
424 if(configuration.createtree) {
425 navLinkTree();
426 }
427 if(!(configuration.nodeprecated ||
428 configuration.nodeprecatedlist)) {
429 navLinkDeprecated();
430 }
431 if(configuration.createindex) {
432 navLinkIndex();
433 }
434 if (!configuration.nohelp) {
435 navLinkHelp();
436 }
437 print(" ");
438 trEnd();
439 tableEnd();
440 tdEnd();
442 tdAlignVAlignRowspan("right", "top", 3);
444 printUserHeaderFooter(header);
445 tdEnd();
446 trEnd();
447 println("");
449 tr();
450 tdBgcolorStyle("white", "NavBarCell2");
451 font("-2");
452 space();
453 navLinkPrevious();
454 space();
455 println("");
456 space();
457 navLinkNext();
458 fontEnd();
459 tdEnd();
461 tdBgcolorStyle("white", "NavBarCell2");
462 font("-2");
463 print(" ");
464 navShowLists();
465 print(" ");
466 space();
467 println("");
468 space();
469 navHideLists(filename);
470 print(" ");
471 space();
472 println("");
473 space();
474 navLinkClassIndex();
475 fontEnd();
476 tdEnd();
478 trEnd();
480 printSummaryDetailLinks();
482 tableEnd();
483 if (header) {
484 aName("skip-navbar_top");
485 aEnd();
486 println(DocletConstants.NL + "<!-- ========= END OF TOP NAVBAR ========= -->");
487 } else {
488 aName("skip-navbar_bottom");
489 aEnd();
490 println(DocletConstants.NL + "<!-- ======== END OF BOTTOM NAVBAR ======= -->");
491 }
492 println("");
493 }
494 }
496 /**
497 * Print the word "NEXT" to indicate that no link is available. Override
498 * this method to customize next link.
499 */
500 protected void navLinkNext() {
501 navLinkNext(null);
502 }
504 /**
505 * Print the word "PREV" to indicate that no link is available. Override
506 * this method to customize prev link.
507 */
508 protected void navLinkPrevious() {
509 navLinkPrevious(null);
510 }
512 /**
513 * Do nothing. This is the default method.
514 */
515 protected void printSummaryDetailLinks() {
516 }
518 /**
519 * Print link to the "overview-summary.html" page.
520 */
521 protected void navLinkContents() {
522 navCellStart();
523 printHyperLink(relativePath + "overview-summary.html", "",
524 configuration.getText("doclet.Overview"), true, "NavBarFont1");
525 navCellEnd();
526 }
528 /**
529 * Description for a cell in the navigation bar.
530 */
531 protected void navCellStart() {
532 print(" ");
533 tdBgcolorStyle("#EEEEFF", "NavBarCell1");
534 print(" ");
535 }
537 /**
538 * Description for a cell in the navigation bar, but with reverse
539 * high-light effect.
540 */
541 protected void navCellRevStart() {
542 print(" ");
543 tdBgcolorStyle("#FFFFFF", "NavBarCell1Rev");
544 print(" ");
545 space();
546 }
548 /**
549 * Closing tag for navigation bar cell.
550 */
551 protected void navCellEnd() {
552 space();
553 tdEnd();
554 }
556 /**
557 * Print link to the "package-summary.html" page for the package passed.
558 *
559 * @param pkg Package to which link will be generated.
560 */
561 protected void navLinkPackage(PackageDoc pkg) {
562 navCellStart();
563 printPackageLink(pkg, configuration.getText("doclet.Package"), true,
564 "NavBarFont1");
565 navCellEnd();
566 }
568 /**
569 * Print the word "Package" in the navigation bar cell, to indicate that
570 * link is not available here.
571 */
572 protected void navLinkPackage() {
573 navCellStart();
574 fontStyle("NavBarFont1");
575 printText("doclet.Package");
576 fontEnd();
577 navCellEnd();
578 }
580 /**
581 * Print the word "Use" in the navigation bar cell, to indicate that link
582 * is not available.
583 */
584 protected void navLinkClassUse() {
585 navCellStart();
586 fontStyle("NavBarFont1");
587 printText("doclet.navClassUse");
588 fontEnd();
589 navCellEnd();
590 }
592 /**
593 * Print link for previous file.
594 *
595 * @param prev File name for the prev link.
596 */
597 public void navLinkPrevious(String prev) {
598 String tag = configuration.getText("doclet.Prev");
599 if (prev != null) {
600 printHyperLink(prev, "", tag, true) ;
601 } else {
602 print(tag);
603 }
604 }
606 /**
607 * Print link for next file. If next is null, just print the label
608 * without linking it anywhere.
609 *
610 * @param next File name for the next link.
611 */
612 public void navLinkNext(String next) {
613 String tag = configuration.getText("doclet.Next");
614 if (next != null) {
615 printHyperLink(next, "", tag, true);
616 } else {
617 print(tag);
618 }
619 }
621 /**
622 * Print "FRAMES" link, to switch to the frame version of the output.
623 *
624 * @param link File to be linked, "index.html".
625 */
626 protected void navShowLists(String link) {
627 print(getHyperLink(link + "?" + path + filename, "",
628 configuration.getText("doclet.FRAMES"), true, "", "", "_top"));
629 }
631 /**
632 * Print "FRAMES" link, to switch to the frame version of the output.
633 */
634 protected void navShowLists() {
635 navShowLists(relativePath + "index.html");
636 }
638 /**
639 * Print "NO FRAMES" link, to switch to the non-frame version of the output.
640 *
641 * @param link File to be linked.
642 */
643 protected void navHideLists(String link) {
644 print(getHyperLink(link, "", configuration.getText("doclet.NO_FRAMES"),
645 true, "", "", "_top"));
646 }
648 /**
649 * Print "Tree" link in the navigation bar. If there is only one package
650 * specified on the command line, then the "Tree" link will be to the
651 * only "package-tree.html" file otherwise it will be to the
652 * "overview-tree.html" file.
653 */
654 protected void navLinkTree() {
655 navCellStart();
656 PackageDoc[] packages = configuration.root.specifiedPackages();
657 if (packages.length == 1 && configuration.root.specifiedClasses().length == 0) {
658 printHyperLink(pathString(packages[0], "package-tree.html"), "",
659 configuration.getText("doclet.Tree"), true, "NavBarFont1");
660 } else {
661 printHyperLink(relativePath + "overview-tree.html", "",
662 configuration.getText("doclet.Tree"), true, "NavBarFont1");
663 }
664 navCellEnd();
665 }
667 /**
668 * Print "Tree" link to the "overview-tree.html" file.
669 */
670 protected void navLinkMainTree(String label) {
671 printHyperLink(relativePath + "overview-tree.html", label);
672 }
674 /**
675 * Print the word "Class" in the navigation bar cell, to indicate that
676 * class link is not available.
677 */
678 protected void navLinkClass() {
679 navCellStart();
680 fontStyle("NavBarFont1");
681 printText("doclet.Class");
682 fontEnd();
683 navCellEnd();
684 }
686 /**
687 * Print "Deprecated" API link in the navigation bar.
688 */
689 protected void navLinkDeprecated() {
690 navCellStart();
691 printHyperLink(relativePath + "deprecated-list.html", "",
692 configuration.getText("doclet.navDeprecated"), true, "NavBarFont1");
693 navCellEnd();
694 }
696 /**
697 * Print link for generated index. If the user has used "-splitindex"
698 * command line option, then link to file "index-files/index-1.html" is
699 * generated otherwise link to file "index-all.html" is generated.
700 */
701 protected void navLinkClassIndex() {
702 printNoFramesTargetHyperLink(relativePath +
703 AllClassesFrameWriter.OUTPUT_FILE_NAME_NOFRAMES,
704 "", "", configuration.getText("doclet.All_Classes"), true);
705 }
706 /**
707 * Print link for generated class index.
708 */
709 protected void navLinkIndex() {
710 navCellStart();
711 printHyperLink(relativePath +
712 (configuration.splitindex?
713 DirectoryManager.getPath("index-files") +
714 fileseparator: "") +
715 (configuration.splitindex?
716 "index-1.html" : "index-all.html"), "",
717 configuration.getText("doclet.Index"), true, "NavBarFont1");
718 navCellEnd();
719 }
721 /**
722 * Print help file link. If user has provided a help file, then generate a
723 * link to the user given file, which is already copied to current or
724 * destination directory.
725 */
726 protected void navLinkHelp() {
727 String helpfilenm = configuration.helpfile;
728 if (helpfilenm.equals("")) {
729 helpfilenm = "help-doc.html";
730 } else {
731 int lastsep;
732 if ((lastsep = helpfilenm.lastIndexOf(File.separatorChar)) != -1) {
733 helpfilenm = helpfilenm.substring(lastsep + 1);
734 }
735 }
736 navCellStart();
737 printHyperLink(relativePath + helpfilenm, "",
738 configuration.getText("doclet.Help"), true, "NavBarFont1");
739 navCellEnd();
740 }
742 /**
743 * Print the word "Detail" in the navigation bar. No link is available.
744 */
745 protected void navDetail() {
746 printText("doclet.Detail");
747 }
749 /**
750 * Print the word "Summary" in the navigation bar. No link is available.
751 */
752 protected void navSummary() {
753 printText("doclet.Summary");
754 }
756 /**
757 * Print the Html table tag for the index summary tables. The table tag
758 * printed is
759 * <TABLE BORDER="1" CELLPADDING="3" CELLSPACING="0" WIDTH="100%">
760 */
761 public void tableIndexSummary() {
762 table(1, "100%", 3, 0);
763 }
765 /**
766 * Same as {@link #tableIndexSummary()}.
767 */
768 public void tableIndexDetail() {
769 table(1, "100%", 3, 0);
770 }
772 /**
773 * Print Html tag for table elements. The tag printed is
774 * <TD ALIGN="right" VALIGN="top" WIDTH="1%">.
775 */
776 public void tdIndex() {
777 print("<TD ALIGN=\"right\" VALIGN=\"top\" WIDTH=\"1%\">");
778 }
780 /**
781 * Prine table header information about color, column span and the font.
782 *
783 * @param color Background color.
784 * @param span Column span.
785 */
786 public void tableHeaderStart(String color, int span) {
787 trBgcolorStyle(color, "TableHeadingColor");
788 thAlignColspan("left", span);
789 font("+2");
790 }
792 /**
793 * Print table header for the inherited members summary tables. Print the
794 * background color information.
795 *
796 * @param color Background color.
797 */
798 public void tableInheritedHeaderStart(String color) {
799 trBgcolorStyle(color, "TableSubHeadingColor");
800 thAlign("left");
801 }
803 /**
804 * Print "Use" table header. Print the background color and the column span.
805 *
806 * @param color Background color.
807 */
808 public void tableUseInfoHeaderStart(String color) {
809 trBgcolorStyle(color, "TableSubHeadingColor");
810 thAlignColspan("left", 2);
811 }
813 /**
814 * Print table header with the background color with default column span 2.
815 *
816 * @param color Background color.
817 */
818 public void tableHeaderStart(String color) {
819 tableHeaderStart(color, 2);
820 }
822 /**
823 * Print table header with the column span, with the default color #CCCCFF.
824 *
825 * @param span Column span.
826 */
827 public void tableHeaderStart(int span) {
828 tableHeaderStart("#CCCCFF", span);
829 }
831 /**
832 * Print table header with default column span 2 and default color #CCCCFF.
833 */
834 public void tableHeaderStart() {
835 tableHeaderStart(2);
836 }
838 /**
839 * Print table header end tags for font, column and row.
840 */
841 public void tableHeaderEnd() {
842 fontEnd();
843 thEnd();
844 trEnd();
845 }
847 /**
848 * Print table header end tags in inherited tables for column and row.
849 */
850 public void tableInheritedHeaderEnd() {
851 thEnd();
852 trEnd();
853 }
855 /**
856 * Print the summary table row cell attribute width.
857 *
858 * @param width Width of the table cell.
859 */
860 public void summaryRow(int width) {
861 if (width != 0) {
862 tdWidth(width + "%");
863 } else {
864 td();
865 }
866 }
868 /**
869 * Print the summary table row cell end tag.
870 */
871 public void summaryRowEnd() {
872 tdEnd();
873 }
875 /**
876 * Print the heading in Html <H2> format.
877 *
878 * @param str The Header string.
879 */
880 public void printIndexHeading(String str) {
881 h2();
882 print(str);
883 h2End();
884 }
886 /**
887 * Print Html tag <FRAMESET=arg>.
888 *
889 * @param arg Argument for the tag.
890 */
891 public void frameSet(String arg) {
892 println("<FRAMESET " + arg + ">");
893 }
895 /**
896 * Print Html closing tag </FRAMESET>.
897 */
898 public void frameSetEnd() {
899 println("</FRAMESET>");
900 }
902 /**
903 * Print Html tag <FRAME=arg>.
904 *
905 * @param arg Argument for the tag.
906 */
907 public void frame(String arg) {
908 println("<FRAME " + arg + ">");
909 }
911 /**
912 * Print Html closing tag </FRAME>.
913 */
914 public void frameEnd() {
915 println("</FRAME>");
916 }
918 /**
919 * Return path to the class page for a classdoc. For example, the class
920 * name is "java.lang.Object" and if the current file getting generated is
921 * "java/io/File.html", then the path string to the class, returned is
922 * "../../java/lang.Object.html".
923 *
924 * @param cd Class to which the path is requested.
925 */
926 protected String pathToClass(ClassDoc cd) {
927 return pathString(cd.containingPackage(), cd.name() + ".html");
928 }
930 /**
931 * Return the path to the class page for a classdoc. Works same as
932 * {@link #pathToClass(ClassDoc)}.
933 *
934 * @param cd Class to which the path is requested.
935 * @param name Name of the file(doesn't include path).
936 */
937 protected String pathString(ClassDoc cd, String name) {
938 return pathString(cd.containingPackage(), name);
939 }
941 /**
942 * Return path to the given file name in the given package. So if the name
943 * passed is "Object.html" and the name of the package is "java.lang", and
944 * if the relative path is "../.." then returned string will be
945 * "../../java/lang/Object.html"
946 *
947 * @param pd Package in which the file name is assumed to be.
948 * @param name File name, to which path string is.
949 */
950 protected String pathString(PackageDoc pd, String name) {
951 StringBuffer buf = new StringBuffer(relativePath);
952 buf.append(DirectoryManager.getPathToPackage(pd, name));
953 return buf.toString();
954 }
956 /**
957 * Print the link to the given package.
958 *
959 * @param pkg the package to link to.
960 * @param label the label for the link.
961 * @param isBold true if the label should be bold.
962 */
963 public void printPackageLink(PackageDoc pkg, String label, boolean isBold) {
964 print(getPackageLink(pkg, label, isBold));
965 }
967 /**
968 * Print the link to the given package.
969 *
970 * @param pkg the package to link to.
971 * @param label the label for the link.
972 * @param isBold true if the label should be bold.
973 * @param style the font of the package link label.
974 */
975 public void printPackageLink(PackageDoc pkg, String label, boolean isBold,
976 String style) {
977 print(getPackageLink(pkg, label, isBold, style));
978 }
980 /**
981 * Return the link to the given package.
982 *
983 * @param pkg the package to link to.
984 * @param label the label for the link.
985 * @param isBold true if the label should be bold.
986 * @return the link to the given package.
987 */
988 public String getPackageLink(PackageDoc pkg, String label,
989 boolean isBold) {
990 return getPackageLink(pkg, label, isBold, "");
991 }
993 /**
994 * Return the link to the given package.
995 *
996 * @param pkg the package to link to.
997 * @param label the label for the link.
998 * @param isBold true if the label should be bold.
999 * @param style the font of the package link label.
1000 * @return the link to the given package.
1001 */
1002 public String getPackageLink(PackageDoc pkg, String label, boolean isBold,
1003 String style) {
1004 boolean included = pkg != null && pkg.isIncluded();
1005 if (! included) {
1006 PackageDoc[] packages = configuration.packages;
1007 for (int i = 0; i < packages.length; i++) {
1008 if (packages[i].equals(pkg)) {
1009 included = true;
1010 break;
1011 }
1012 }
1013 }
1014 if (included || pkg == null) {
1015 return getHyperLink(pathString(pkg, "package-summary.html"),
1016 "", label, isBold, style);
1017 } else {
1018 String crossPkgLink = getCrossPackageLink(Util.getPackageName(pkg));
1019 if (crossPkgLink != null) {
1020 return getHyperLink(crossPkgLink, "", label, isBold, style);
1021 } else {
1022 return label;
1023 }
1024 }
1025 }
1027 public String italicsClassName(ClassDoc cd, boolean qual) {
1028 String name = (qual)? cd.qualifiedName(): cd.name();
1029 return (cd.isInterface())? italicsText(name): name;
1030 }
1032 public void printSrcLink(ProgramElementDoc d, String label) {
1033 if (d == null) {
1034 return;
1035 }
1036 ClassDoc cd = d.containingClass();
1037 if (cd == null) {
1038 //d must be a class doc since in has no containing class.
1039 cd = (ClassDoc) d;
1040 }
1041 String href = relativePath + DocletConstants.SOURCE_OUTPUT_DIR_NAME
1042 + DirectoryManager.getDirectoryPath(cd.containingPackage())
1043 + cd.name() + ".html#" + SourceToHTMLConverter.getAnchorName(d);
1044 printHyperLink(href, "", label, true);
1045 }
1047 /**
1048 * Return the link to the given class.
1049 *
1050 * @param linkInfo the information about the link.
1051 *
1052 * @return the link for the given class.
1053 */
1054 public String getLink(LinkInfoImpl linkInfo) {
1055 LinkFactoryImpl factory = new LinkFactoryImpl(this);
1056 String link = ((LinkOutputImpl) factory.getLinkOutput(linkInfo)).toString();
1057 displayLength += linkInfo.displayLength;
1058 return link;
1059 }
1061 /**
1062 * Return the type parameters for the given class.
1063 *
1064 * @param linkInfo the information about the link.
1065 * @return the type for the given class.
1066 */
1067 public String getTypeParameterLinks(LinkInfoImpl linkInfo) {
1068 LinkFactoryImpl factory = new LinkFactoryImpl(this);
1069 return ((LinkOutputImpl)
1070 factory.getTypeParameterLinks(linkInfo, false)).toString();
1071 }
1073 /**
1074 * Print the link to the given class.
1075 */
1076 public void printLink(LinkInfoImpl linkInfo) {
1077 print(getLink(linkInfo));
1078 }
1080 /*************************************************************
1081 * Return a class cross link to external class documentation.
1082 * The name must be fully qualified to determine which package
1083 * the class is in. The -link option does not allow users to
1084 * link to external classes in the "default" package.
1085 *
1086 * @param qualifiedClassName the qualified name of the external class.
1087 * @param refMemName the name of the member being referenced. This should
1088 * be null or empty string if no member is being referenced.
1089 * @param label the label for the external link.
1090 * @param bold true if the link should be bold.
1091 * @param style the style of the link.
1092 * @param code true if the label should be code font.
1093 */
1094 public String getCrossClassLink(String qualifiedClassName, String refMemName,
1095 String label, boolean bold, String style,
1096 boolean code) {
1097 String className = "",
1098 packageName = qualifiedClassName == null ? "" : qualifiedClassName;
1099 int periodIndex;
1100 while((periodIndex = packageName.lastIndexOf('.')) != -1) {
1101 className = packageName.substring(periodIndex + 1, packageName.length()) +
1102 (className.length() > 0 ? "." + className : "");
1103 String defaultLabel = code ? getCode() + className + getCodeEnd() : className;
1104 packageName = packageName.substring(0, periodIndex);
1105 if (getCrossPackageLink(packageName) != null) {
1106 //The package exists in external documentation, so link to the external
1107 //class (assuming that it exists). This is definitely a limitation of
1108 //the -link option. There are ways to determine if an external package
1109 //exists, but no way to determine if the external class exists. We just
1110 //have to assume that it does.
1111 return getHyperLink(
1112 configuration.extern.getExternalLink(packageName, relativePath,
1113 className + ".html?is-external=true"),
1114 refMemName == null ? "" : refMemName,
1115 label == null || label.length() == 0 ? defaultLabel : label,
1116 bold, style,
1117 configuration.getText("doclet.Href_Class_Or_Interface_Title", packageName),
1118 "");
1119 }
1120 }
1121 return null;
1122 }
1124 public boolean isClassLinkable(ClassDoc cd) {
1125 if (cd.isIncluded()) {
1126 return configuration.isGeneratedDoc(cd);
1127 }
1128 return configuration.extern.isExternal(cd);
1129 }
1131 public String getCrossPackageLink(String pkgName) {
1132 return configuration.extern.getExternalLink(pkgName, relativePath,
1133 "package-summary.html?is-external=true");
1134 }
1136 public void printQualifiedClassLink(int context, ClassDoc cd) {
1137 printLink(new LinkInfoImpl(context, cd,
1138 configuration.getClassName(cd), ""));
1139 }
1141 /**
1142 * Print Class link, with only class name as the link and prefixing
1143 * plain package name.
1144 */
1145 public void printPreQualifiedClassLink(int context, ClassDoc cd) {
1146 print(getPreQualifiedClassLink(context, cd, false));
1147 }
1149 /**
1150 * Retrieve the class link with the package portion of the label in
1151 * plain text. If the qualifier is excluded, it willnot be included in the
1152 * link label.
1153 *
1154 * @param cd the class to link to.
1155 * @param isBold true if the link should be bold.
1156 * @return the link with the package portion of the label in plain text.
1157 */
1158 public String getPreQualifiedClassLink(int context,
1159 ClassDoc cd, boolean isBold) {
1160 String classlink = "";
1161 PackageDoc pd = cd.containingPackage();
1162 if(pd != null && ! configuration.shouldExcludeQualifier(pd.name())) {
1163 classlink = getPkgName(cd);
1164 }
1165 classlink += getLink(new LinkInfoImpl(context, cd, cd.name(), isBold));
1166 return classlink;
1167 }
1170 /**
1171 * Print Class link, with only class name as the bold link and prefixing
1172 * plain package name.
1173 */
1174 public void printPreQualifiedBoldClassLink(int context, ClassDoc cd) {
1175 print(getPreQualifiedClassLink(context, cd, true));
1176 }
1178 public void printText(String key) {
1179 print(configuration.getText(key));
1180 }
1182 public void printText(String key, String a1) {
1183 print(configuration.getText(key, a1));
1184 }
1186 public void printText(String key, String a1, String a2) {
1187 print(configuration.getText(key, a1, a2));
1188 }
1190 public void boldText(String key) {
1191 bold(configuration.getText(key));
1192 }
1194 public void boldText(String key, String a1) {
1195 bold(configuration.getText(key, a1));
1196 }
1198 public void boldText(String key, String a1, String a2) {
1199 bold(configuration.getText(key, a1, a2));
1200 }
1202 /**
1203 * Print the link for the given member.
1204 *
1205 * @param context the id of the context where the link will be printed.
1206 * @param doc the member being linked to.
1207 * @param label the label for the link.
1208 * @param bold true if the link should be bold.
1209 */
1210 public void printDocLink(int context, MemberDoc doc, String label,
1211 boolean bold) {
1212 print(getDocLink(context, doc, label, bold));
1213 }
1215 /**
1216 * Print the link for the given member.
1217 *
1218 * @param context the id of the context where the link will be printed.
1219 * @param classDoc the classDoc that we should link to. This is not
1220 * necessarily equal to doc.containingClass(). We may be
1221 * inheriting comments.
1222 * @param doc the member being linked to.
1223 * @param label the label for the link.
1224 * @param bold true if the link should be bold.
1225 */
1226 public void printDocLink(int context, ClassDoc classDoc, MemberDoc doc,
1227 String label, boolean bold) {
1228 print(getDocLink(context, classDoc, doc, label, bold));
1229 }
1231 /**
1232 * Return the link for the given member.
1233 *
1234 * @param context the id of the context where the link will be printed.
1235 * @param doc the member being linked to.
1236 * @param label the label for the link.
1237 * @param bold true if the link should be bold.
1238 * @return the link for the given member.
1239 */
1240 public String getDocLink(int context, MemberDoc doc, String label,
1241 boolean bold) {
1242 return getDocLink(context, doc.containingClass(), doc, label, bold);
1243 }
1245 /**
1246 * Return the link for the given member.
1247 *
1248 * @param context the id of the context where the link will be printed.
1249 * @param classDoc the classDoc that we should link to. This is not
1250 * necessarily equal to doc.containingClass(). We may be
1251 * inheriting comments.
1252 * @param doc the member being linked to.
1253 * @param label the label for the link.
1254 * @param bold true if the link should be bold.
1255 * @return the link for the given member.
1256 */
1257 public String getDocLink(int context, ClassDoc classDoc, MemberDoc doc,
1258 String label, boolean bold) {
1259 if (! (doc.isIncluded() ||
1260 Util.isLinkable(classDoc, configuration()))) {
1261 return label;
1262 } else if (doc instanceof ExecutableMemberDoc) {
1263 ExecutableMemberDoc emd = (ExecutableMemberDoc)doc;
1264 return getLink(new LinkInfoImpl(context, classDoc,
1265 getAnchor(emd), label, bold));
1266 } else if (doc instanceof MemberDoc) {
1267 return getLink(new LinkInfoImpl(context, classDoc,
1268 doc.name(), label, bold));
1269 } else {
1270 return label;
1271 }
1272 }
1274 public void anchor(ExecutableMemberDoc emd) {
1275 anchor(getAnchor(emd));
1276 }
1278 public String getAnchor(ExecutableMemberDoc emd) {
1279 StringBuilder signature = new StringBuilder(emd.signature());
1280 StringBuilder signatureParsed = new StringBuilder();
1281 int counter = 0;
1282 for (int i = 0; i < signature.length(); i++) {
1283 char c = signature.charAt(i);
1284 if (c == '<') {
1285 counter++;
1286 } else if (c == '>') {
1287 counter--;
1288 } else if (counter == 0) {
1289 signatureParsed.append(c);
1290 }
1291 }
1292 return emd.name() + signatureParsed.toString();
1293 }
1295 public String seeTagToString(SeeTag see) {
1296 String tagName = see.name();
1297 if (! (tagName.startsWith("@link") || tagName.equals("@see"))) {
1298 return "";
1299 }
1300 StringBuffer result = new StringBuffer();
1301 boolean isplaintext = tagName.toLowerCase().equals("@linkplain");
1302 String label = see.label();
1303 label = (label.length() > 0)?
1304 ((isplaintext) ? label :
1305 getCode() + label + getCodeEnd()):"";
1306 String seetext = replaceDocRootDir(see.text());
1308 //Check if @see is an href or "string"
1309 if (seetext.startsWith("<") || seetext.startsWith("\"")) {
1310 result.append(seetext);
1311 return result.toString();
1312 }
1314 //The text from the @see tag. We will output this text when a label is not specified.
1315 String text = (isplaintext) ? seetext : getCode() + seetext + getCodeEnd();
1317 ClassDoc refClass = see.referencedClass();
1318 String refClassName = see.referencedClassName();
1319 MemberDoc refMem = see.referencedMember();
1320 String refMemName = see.referencedMemberName();
1321 if (refClass == null) {
1322 //@see is not referencing an included class
1323 PackageDoc refPackage = see.referencedPackage();
1324 if (refPackage != null && refPackage.isIncluded()) {
1325 //@see is referencing an included package
1326 String packageName = isplaintext ? refPackage.name() :
1327 getCode() + refPackage.name() + getCodeEnd();
1328 result.append(getPackageLink(refPackage,
1329 label.length() == 0 ? packageName : label, false));
1330 } else {
1331 //@see is not referencing an included class or package. Check for cross links.
1332 String classCrossLink, packageCrossLink = getCrossPackageLink(refClassName);
1333 if (packageCrossLink != null) {
1334 //Package cross link found
1335 result.append(getHyperLink(packageCrossLink, "",
1336 (label.length() == 0)? text : label, false));
1337 } else if ((classCrossLink = getCrossClassLink(refClassName,
1338 refMemName, label, false, "", ! isplaintext)) != null) {
1339 //Class cross link found (possiblly to a member in the class)
1340 result.append(classCrossLink);
1341 } else {
1342 //No cross link found so print warning
1343 configuration.getDocletSpecificMsg().warning(see.position(), "doclet.see.class_or_package_not_found",
1344 tagName, seetext);
1345 result.append((label.length() == 0)? text: label);
1346 }
1347 }
1348 } else if (refMemName == null) {
1349 // Must be a class reference since refClass is not null and refMemName is null.
1350 if (label.length() == 0) {
1351 label = (isplaintext) ? refClass.name() : getCode() + refClass.name() + getCodeEnd();
1352 result.append(getLink(new LinkInfoImpl(refClass, label)));
1353 } else {
1354 result.append(getLink(new LinkInfoImpl(refClass, label)));
1355 }
1356 } else if (refMem == null) {
1357 // Must be a member reference since refClass is not null and refMemName is not null.
1358 // However, refMem is null, so this referenced member does not exist.
1359 result.append((label.length() == 0)? text: label);
1360 } else {
1361 // Must be a member reference since refClass is not null and refMemName is not null.
1362 // refMem is not null, so this @see tag must be referencing a valid member.
1363 ClassDoc containing = refMem.containingClass();
1364 if (see.text().trim().startsWith("#") &&
1365 ! (containing.isPublic() ||
1366 Util.isLinkable(containing, configuration()))) {
1367 // Since the link is relative and the holder is not even being
1368 // documented, this must be an inherited link. Redirect it.
1369 // The current class either overrides the referenced member or
1370 // inherits it automatically.
1371 containing = ((ClassWriterImpl) this).getClassDoc();
1372 }
1373 if (configuration.currentcd != containing) {
1374 refMemName = containing.name() + "." + refMemName;
1375 }
1376 if (refMem instanceof ExecutableMemberDoc) {
1377 if (refMemName.indexOf('(') < 0) {
1378 refMemName += ((ExecutableMemberDoc)refMem).signature();
1379 }
1380 }
1381 text = (isplaintext) ?
1382 refMemName : getCode() + refMemName + getCodeEnd();
1384 result.append(getDocLink(LinkInfoImpl.CONTEXT_SEE_TAG, containing,
1385 refMem, (label.length() == 0)? text: label, false));
1386 }
1387 return result.toString();
1388 }
1390 public void printInlineComment(Doc doc, Tag tag) {
1391 printCommentTags(doc, tag.inlineTags(), false, false);
1392 }
1394 public void printInlineDeprecatedComment(Doc doc, Tag tag) {
1395 printCommentTags(doc, tag.inlineTags(), true, false);
1396 }
1398 public void printSummaryComment(Doc doc) {
1399 printSummaryComment(doc, doc.firstSentenceTags());
1400 }
1402 public void printSummaryComment(Doc doc, Tag[] firstSentenceTags) {
1403 printCommentTags(doc, firstSentenceTags, false, true);
1404 }
1406 public void printSummaryDeprecatedComment(Doc doc) {
1407 printCommentTags(doc, doc.firstSentenceTags(), true, true);
1408 }
1410 public void printSummaryDeprecatedComment(Doc doc, Tag tag) {
1411 printCommentTags(doc, tag.firstSentenceTags(), true, true);
1412 }
1414 public void printInlineComment(Doc doc) {
1415 printCommentTags(doc, doc.inlineTags(), false, false);
1416 p();
1417 }
1419 public void printInlineDeprecatedComment(Doc doc) {
1420 printCommentTags(doc, doc.inlineTags(), true, false);
1421 }
1423 private void printCommentTags(Doc doc, Tag[] tags, boolean depr, boolean first) {
1424 if(configuration.nocomment){
1425 return;
1426 }
1427 if (depr) {
1428 italic();
1429 }
1430 String result = commentTagsToString(null, doc, tags, first);
1431 print(result);
1432 if (depr) {
1433 italicEnd();
1434 }
1435 if (tags.length == 0) {
1436 space();
1437 }
1438 }
1440 /**
1441 * Converts inline tags and text to text strings, expanding the
1442 * inline tags along the way. Called wherever text can contain
1443 * an inline tag, such as in comments or in free-form text arguments
1444 * to non-inline tags.
1445 *
1446 * @param holderTag specific tag where comment resides
1447 * @param doc specific doc where comment resides
1448 * @param tags array of text tags and inline tags (often alternating)
1449 * present in the text of interest for this doc
1450 * @param isFirstSentence true if text is first sentence
1451 */
1452 public String commentTagsToString(Tag holderTag, Doc doc, Tag[] tags,
1453 boolean isFirstSentence) {
1454 StringBuffer result = new StringBuffer();
1455 // Array of all possible inline tags for this javadoc run
1456 configuration.tagletManager.checkTags(doc, tags, true);
1457 for (int i = 0; i < tags.length; i++) {
1458 Tag tagelem = tags[i];
1459 String tagName = tagelem.name();
1460 if (tagelem instanceof SeeTag) {
1461 result.append(seeTagToString((SeeTag)tagelem));
1462 } else if (! tagName.equals("Text")) {
1463 int originalLength = result.length();
1464 TagletOutput output = TagletWriter.getInlineTagOuput(
1465 configuration.tagletManager, holderTag,
1466 tagelem, getTagletWriterInstance(isFirstSentence));
1467 result.append(output == null ? "" : output.toString());
1468 if (originalLength == 0 && isFirstSentence && tagelem.name().equals("@inheritDoc") && result.length() > 0) {
1469 break;
1470 } else {
1471 continue;
1472 }
1473 } else {
1474 //This is just a regular text tag. The text may contain html links (<a>)
1475 //or inline tag {@docRoot}, which will be handled as special cases.
1476 String text = redirectRelativeLinks(tagelem.holder(), tagelem.text());
1478 // Replace @docRoot only if not represented by an instance of DocRootTaglet,
1479 // that is, only if it was not present in a source file doc comment.
1480 // This happens when inserted by the doclet (a few lines
1481 // above in this method). [It might also happen when passed in on the command
1482 // line as a text argument to an option (like -header).]
1483 text = replaceDocRootDir(text);
1484 if (isFirstSentence) {
1485 text = removeNonInlineHtmlTags(text);
1486 }
1487 StringTokenizer lines = new StringTokenizer(text, "\r\n", true);
1488 StringBuffer textBuff = new StringBuffer();
1489 while (lines.hasMoreTokens()) {
1490 StringBuffer line = new StringBuffer(lines.nextToken());
1491 Util.replaceTabs(configuration.sourcetab, line);
1492 textBuff.append(line.toString());
1493 }
1494 result.append(textBuff);
1495 }
1496 }
1497 return result.toString();
1498 }
1500 /**
1501 * Return true if relative links should not be redirected.
1502 *
1503 * @return Return true if a relative link should not be redirected.
1504 */
1505 private boolean shouldNotRedirectRelativeLinks() {
1506 return this instanceof AnnotationTypeWriter ||
1507 this instanceof ClassWriter ||
1508 this instanceof PackageSummaryWriter;
1509 }
1511 /**
1512 * Suppose a piece of documentation has a relative link. When you copy
1513 * that documetation to another place such as the index or class-use page,
1514 * that relative link will no longer work. We should redirect those links
1515 * so that they will work again.
1516 * <p>
1517 * Here is the algorithm used to fix the link:
1518 * <p>
1519 * <relative link> => docRoot + <relative path to file> + <relative link>
1520 * <p>
1521 * For example, suppose com.sun.javadoc.RootDoc has this link:
1522 * <a href="package-summary.html">The package Page</a>
1523 * <p>
1524 * If this link appeared in the index, we would redirect
1525 * the link like this:
1526 *
1527 * <a href="./com/sun/javadoc/package-summary.html">The package Page</a>
1528 *
1529 * @param doc the Doc object whose documentation is being written.
1530 * @param text the text being written.
1531 *
1532 * @return the text, with all the relative links redirected to work.
1533 */
1534 private String redirectRelativeLinks(Doc doc, String text) {
1535 if (doc == null || shouldNotRedirectRelativeLinks()) {
1536 return text;
1537 }
1539 String redirectPathFromRoot;
1540 if (doc instanceof ClassDoc) {
1541 redirectPathFromRoot = DirectoryManager.getDirectoryPath(((ClassDoc) doc).containingPackage());
1542 } else if (doc instanceof MemberDoc) {
1543 redirectPathFromRoot = DirectoryManager.getDirectoryPath(((MemberDoc) doc).containingPackage());
1544 } else if (doc instanceof PackageDoc) {
1545 redirectPathFromRoot = DirectoryManager.getDirectoryPath((PackageDoc) doc);
1546 } else {
1547 return text;
1548 }
1550 if (! redirectPathFromRoot.endsWith(DirectoryManager.URL_FILE_SEPERATOR)) {
1551 redirectPathFromRoot += DirectoryManager.URL_FILE_SEPERATOR;
1552 }
1554 //Redirect all relative links.
1555 int end, begin = text.toLowerCase().indexOf("<a");
1556 if(begin >= 0){
1557 StringBuffer textBuff = new StringBuffer(text);
1559 while(begin >=0){
1560 if (textBuff.length() > begin + 2 && ! Character.isWhitespace(textBuff.charAt(begin+2))) {
1561 begin = textBuff.toString().toLowerCase().indexOf("<a", begin + 1);
1562 continue;
1563 }
1565 begin = textBuff.indexOf("=", begin) + 1;
1566 end = textBuff.indexOf(">", begin +1);
1567 if(begin == 0){
1568 //Link has no equal symbol.
1569 configuration.root.printWarning(
1570 doc.position(),
1571 configuration.getText("doclet.malformed_html_link_tag", text));
1572 break;
1573 }
1574 if (end == -1) {
1575 //Break without warning. This <a> tag is not necessarily malformed. The text
1576 //might be missing '>' character because the href has an inline tag.
1577 break;
1578 }
1579 if(textBuff.substring(begin, end).indexOf("\"") != -1){
1580 begin = textBuff.indexOf("\"", begin) + 1;
1581 end = textBuff.indexOf("\"", begin +1);
1582 if(begin == 0 || end == -1){
1583 //Link is missing a quote.
1584 break;
1585 }
1586 }
1587 String relativeLink = textBuff.substring(begin, end);
1588 if(!(relativeLink.toLowerCase().startsWith("mailto:") ||
1589 relativeLink.toLowerCase().startsWith("http:") ||
1590 relativeLink.toLowerCase().startsWith("https:") ||
1591 relativeLink.toLowerCase().startsWith("file:"))){
1592 relativeLink = "{@"+(new DocRootTaglet()).getName() + "}"
1593 + redirectPathFromRoot
1594 + relativeLink;
1595 textBuff.replace(begin, end, relativeLink);
1596 }
1597 begin = textBuff.toString().toLowerCase().indexOf("<a", begin + 1);
1598 }
1599 return textBuff.toString();
1600 }
1601 return text;
1602 }
1604 public String removeNonInlineHtmlTags(String text) {
1605 if (text.indexOf('<') < 0) {
1606 return text;
1607 }
1608 String noninlinetags[] = { "<ul>", "</ul>", "<ol>", "</ol>",
1609 "<dl>", "</dl>", "<table>", "</table>",
1610 "<tr>", "</tr>", "<td>", "</td>",
1611 "<th>", "</th>", "<p>", "</p>",
1612 "<li>", "</li>", "<dd>", "</dd>",
1613 "<dir>", "</dir>", "<dt>", "</dt>",
1614 "<h1>", "</h1>", "<h2>", "</h2>",
1615 "<h3>", "</h3>", "<h4>", "</h4>",
1616 "<h5>", "</h5>", "<h6>", "</h6>",
1617 "<pre>", "</pre>", "<menu>", "</menu>",
1618 "<listing>", "</listing>", "<hr>",
1619 "<blockquote>", "</blockquote>",
1620 "<center>", "</center>",
1621 "<UL>", "</UL>", "<OL>", "</OL>",
1622 "<DL>", "</DL>", "<TABLE>", "</TABLE>",
1623 "<TR>", "</TR>", "<TD>", "</TD>",
1624 "<TH>", "</TH>", "<P>", "</P>",
1625 "<LI>", "</LI>", "<DD>", "</DD>",
1626 "<DIR>", "</DIR>", "<DT>", "</DT>",
1627 "<H1>", "</H1>", "<H2>", "</H2>",
1628 "<H3>", "</H3>", "<H4>", "</H4>",
1629 "<H5>", "</H5>", "<H6>", "</H6>",
1630 "<PRE>", "</PRE>", "<MENU>", "</MENU>",
1631 "<LISTING>", "</LISTING>", "<HR>",
1632 "<BLOCKQUOTE>", "</BLOCKQUOTE>",
1633 "<CENTER>", "</CENTER>"
1634 };
1635 for (int i = 0; i < noninlinetags.length; i++) {
1636 text = replace(text, noninlinetags[i], "");
1637 }
1638 return text;
1639 }
1641 public String replace(String text, String tobe, String by) {
1642 while (true) {
1643 int startindex = text.indexOf(tobe);
1644 if (startindex < 0) {
1645 return text;
1646 }
1647 int endindex = startindex + tobe.length();
1648 StringBuffer replaced = new StringBuffer();
1649 if (startindex > 0) {
1650 replaced.append(text.substring(0, startindex));
1651 }
1652 replaced.append(by);
1653 if (text.length() > endindex) {
1654 replaced.append(text.substring(endindex));
1655 }
1656 text = replaced.toString();
1657 }
1658 }
1660 public void printStyleSheetProperties() {
1661 String filename = configuration.stylesheetfile;
1662 if (filename.length() > 0) {
1663 File stylefile = new File(filename);
1664 String parent = stylefile.getParent();
1665 filename = (parent == null)?
1666 filename:
1667 filename.substring(parent.length() + 1);
1668 } else {
1669 filename = "stylesheet.css";
1670 }
1671 filename = relativePath + filename;
1672 link("REL =\"stylesheet\" TYPE=\"text/css\" HREF=\"" +
1673 filename + "\" " + "TITLE=\"Style\"");
1674 }
1676 /**
1677 * According to the Java Language Specifications, all the outer classes
1678 * and static nested classes are core classes.
1679 */
1680 public boolean isCoreClass(ClassDoc cd) {
1681 return cd.containingClass() == null || cd.isStatic();
1682 }
1684 /**
1685 * Write the annotatation types for the given packageDoc.
1686 *
1687 * @param packageDoc the package to write annotations for.
1688 */
1689 public void writeAnnotationInfo(PackageDoc packageDoc) {
1690 writeAnnotationInfo(packageDoc, packageDoc.annotations());
1691 }
1693 /**
1694 * Write the annotatation types for the given doc.
1695 *
1696 * @param doc the doc to write annotations for.
1697 */
1698 public void writeAnnotationInfo(ProgramElementDoc doc) {
1699 writeAnnotationInfo(doc, doc.annotations());
1700 }
1702 /**
1703 * Write the annotatation types for the given doc and parameter.
1704 *
1705 * @param indent the number of spaced to indent the parameters.
1706 * @param doc the doc to write annotations for.
1707 * @param param the parameter to write annotations for.
1708 */
1709 public boolean writeAnnotationInfo(int indent, Doc doc, Parameter param) {
1710 return writeAnnotationInfo(indent, doc, param.annotations(), false);
1711 }
1713 /**
1714 * Write the annotatation types for the given doc.
1715 *
1716 * @param doc the doc to write annotations for.
1717 * @param descList the array of {@link AnnotationDesc}.
1718 */
1719 private void writeAnnotationInfo(Doc doc, AnnotationDesc[] descList) {
1720 writeAnnotationInfo(0, doc, descList, true);
1721 }
1723 /**
1724 * Write the annotatation types for the given doc.
1725 *
1726 * @param indent the number of extra spaces to indent the annotations.
1727 * @param doc the doc to write annotations for.
1728 * @param descList the array of {@link AnnotationDesc}.
1729 */
1730 private boolean writeAnnotationInfo(int indent, Doc doc, AnnotationDesc[] descList, boolean lineBreak) {
1731 List annotations = getAnnotations(indent, descList, lineBreak);
1732 if (annotations.size() == 0) {
1733 return false;
1734 }
1735 fontNoNewLine("-1");
1736 for (Iterator iter = annotations.iterator(); iter.hasNext();) {
1737 print((String) iter.next());
1738 }
1739 fontEnd();
1740 return true;
1741 }
1743 /**
1744 * Return the string representations of the annotation types for
1745 * the given doc.
1746 *
1747 * @param indent the number of extra spaces to indent the annotations.
1748 * @param descList the array of {@link AnnotationDesc}.
1749 * @param linkBreak if true, add new line between each member value.
1750 * @return an array of strings representing the annotations being
1751 * documented.
1752 */
1753 private List<String> getAnnotations(int indent, AnnotationDesc[] descList, boolean linkBreak) {
1754 List<String> results = new ArrayList<String>();
1755 StringBuffer annotation;
1756 for (int i = 0; i < descList.length; i++) {
1757 AnnotationTypeDoc annotationDoc = descList[i].annotationType();
1758 if (! Util.isDocumentedAnnotation(annotationDoc)){
1759 continue;
1760 }
1761 annotation = new StringBuffer();
1762 LinkInfoImpl linkInfo = new LinkInfoImpl(
1763 LinkInfoImpl.CONTEXT_ANNOTATION, annotationDoc);
1764 linkInfo.label = "@" + annotationDoc.name();
1765 annotation.append(getLink(linkInfo));
1766 AnnotationDesc.ElementValuePair[] pairs = descList[i].elementValues();
1767 if (pairs.length > 0) {
1768 annotation.append('(');
1769 for (int j = 0; j < pairs.length; j++) {
1770 if (j > 0) {
1771 annotation.append(",");
1772 if (linkBreak) {
1773 annotation.append(DocletConstants.NL);
1774 int spaces = annotationDoc.name().length() + 2;
1775 for (int k = 0; k < (spaces + indent); k++) {
1776 annotation.append(' ');
1777 }
1778 }
1779 }
1780 annotation.append(getDocLink(LinkInfoImpl.CONTEXT_ANNOTATION,
1781 pairs[j].element(), pairs[j].element().name(), false));
1782 annotation.append('=');
1783 AnnotationValue annotationValue = pairs[j].value();
1784 List<AnnotationValue> annotationTypeValues = new ArrayList<AnnotationValue>();
1785 if (annotationValue.value() instanceof AnnotationValue[]) {
1786 AnnotationValue[] annotationArray =
1787 (AnnotationValue[]) annotationValue.value();
1788 for (int k = 0; k < annotationArray.length; k++) {
1789 annotationTypeValues.add(annotationArray[k]);
1790 }
1791 } else {
1792 annotationTypeValues.add(annotationValue);
1793 }
1794 annotation.append(annotationTypeValues.size() == 1 ? "" : "{");
1795 for (Iterator iter = annotationTypeValues.iterator(); iter.hasNext(); ) {
1796 annotation.append(annotationValueToString((AnnotationValue) iter.next()));
1797 annotation.append(iter.hasNext() ? "," : "");
1798 }
1799 annotation.append(annotationTypeValues.size() == 1 ? "" : "}");
1800 }
1801 annotation.append(")");
1802 }
1803 annotation.append(linkBreak ? DocletConstants.NL : "");
1804 results.add(annotation.toString());
1805 }
1806 return results;
1807 }
1809 private String annotationValueToString(AnnotationValue annotationValue) {
1810 if (annotationValue.value() instanceof Type) {
1811 Type type = (Type) annotationValue.value();
1812 if (type.asClassDoc() != null) {
1813 LinkInfoImpl linkInfo = new LinkInfoImpl(
1814 LinkInfoImpl.CONTEXT_ANNOTATION, type);
1815 linkInfo.label = (type.asClassDoc().isIncluded() ?
1816 type.typeName() :
1817 type.qualifiedTypeName()) + type.dimension() + ".class";
1818 return getLink(linkInfo);
1819 } else {
1820 return type.typeName() + type.dimension() + ".class";
1821 }
1822 } else if (annotationValue.value() instanceof AnnotationDesc) {
1823 List list = getAnnotations(0,
1824 new AnnotationDesc[]{(AnnotationDesc) annotationValue.value()},
1825 false);
1826 StringBuffer buf = new StringBuffer();
1827 for (Iterator iter = list.iterator(); iter.hasNext(); ) {
1828 buf.append(iter.next());
1829 }
1830 return buf.toString();
1831 } else if (annotationValue.value() instanceof MemberDoc) {
1832 return getDocLink(LinkInfoImpl.CONTEXT_ANNOTATION,
1833 (MemberDoc) annotationValue.value(),
1834 ((MemberDoc) annotationValue.value()).name(), false);
1835 } else {
1836 return annotationValue.toString();
1837 }
1838 }
1840 /**
1841 * Return the configuation for this doclet.
1842 *
1843 * @return the configuration for this doclet.
1844 */
1845 public Configuration configuration() {
1846 return configuration;
1847 }
1848 }