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