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