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