60 import com.sun.source.doctree.IndexTree;
61 import com.sun.source.doctree.InheritDocTree;
62 import com.sun.source.doctree.LinkTree;
63 import com.sun.source.doctree.LiteralTree;
64 import com.sun.source.doctree.SeeTree;
65 import com.sun.source.doctree.StartElementTree;
66 import com.sun.source.doctree.SummaryTree;
67 import com.sun.source.doctree.TextTree;
68 import com.sun.source.util.SimpleDocTreeVisitor;
69
70 import jdk.javadoc.internal.doclets.formats.html.markup.Comment;
71 import jdk.javadoc.internal.doclets.formats.html.markup.ContentBuilder;
72 import jdk.javadoc.internal.doclets.formats.html.markup.DocType;
73 import jdk.javadoc.internal.doclets.formats.html.markup.HtmlAttr;
74 import jdk.javadoc.internal.doclets.formats.html.markup.HtmlConstants;
75 import jdk.javadoc.internal.doclets.formats.html.markup.HtmlDocWriter;
76 import jdk.javadoc.internal.doclets.formats.html.markup.HtmlDocument;
77 import jdk.javadoc.internal.doclets.formats.html.markup.HtmlStyle;
78 import jdk.javadoc.internal.doclets.formats.html.markup.HtmlTag;
79 import jdk.javadoc.internal.doclets.formats.html.markup.HtmlTree;
80 import jdk.javadoc.internal.doclets.formats.html.markup.RawHtml;
81 import jdk.javadoc.internal.doclets.formats.html.markup.Script;
82 import jdk.javadoc.internal.doclets.formats.html.markup.StringContent;
83 import jdk.javadoc.internal.doclets.toolkit.AnnotationTypeWriter;
84 import jdk.javadoc.internal.doclets.toolkit.ClassWriter;
85 import jdk.javadoc.internal.doclets.toolkit.Content;
86 import jdk.javadoc.internal.doclets.toolkit.Messages;
87 import jdk.javadoc.internal.doclets.toolkit.PackageSummaryWriter;
88 import jdk.javadoc.internal.doclets.toolkit.Resources;
89 import jdk.javadoc.internal.doclets.toolkit.taglets.DocRootTaglet;
90 import jdk.javadoc.internal.doclets.toolkit.taglets.TagletWriter;
91 import jdk.javadoc.internal.doclets.toolkit.util.CommentHelper;
92 import jdk.javadoc.internal.doclets.toolkit.util.DocFile;
93 import jdk.javadoc.internal.doclets.toolkit.util.DocFileIOException;
94 import jdk.javadoc.internal.doclets.toolkit.util.DocLink;
95 import jdk.javadoc.internal.doclets.toolkit.util.DocPath;
96 import jdk.javadoc.internal.doclets.toolkit.util.DocPaths;
97 import jdk.javadoc.internal.doclets.toolkit.util.DocletConstants;
98 import jdk.javadoc.internal.doclets.toolkit.util.ImplementedMethods;
99 import jdk.javadoc.internal.doclets.toolkit.util.Utils;
137
138 /**
139 * Name of the file getting generated. If the file getting generated is
140 * "java/lang/Object.html", then the filename is "Object.html".
141 */
142 public final DocPath filename;
143
144 /**
145 * The global configuration information for this run.
146 */
147 public final HtmlConfiguration configuration;
148
149 protected final Utils utils;
150
151 protected final Contents contents;
152
153 protected final Messages messages;
154
155 protected final Resources resources;
156
157 /**
158 * To check whether annotation heading is printed or not.
159 */
160 protected boolean printedAnnotationHeading = false;
161
162 /**
163 * To check whether annotation field heading is printed or not.
164 */
165 protected boolean printedAnnotationFieldHeading = false;
166
167 /**
168 * To check whether the repeated annotations is documented or not.
169 */
170 private boolean isAnnotationDocumented = false;
171
172 /**
173 * To check whether the container annotations is documented or not.
174 */
175 private boolean isContainerDocumented = false;
176
179 final static Pattern IMPROPER_HTML_CHARS = Pattern.compile(".*[&<>].*");
180
181 /**
182 * The window title of this file.
183 */
184 protected String winTitle;
185
186 protected Script mainBodyScript;
187
188 /**
189 * Constructor to construct the HtmlStandardWriter object.
190 *
191 * @param path File to be generated.
192 */
193 public HtmlDocletWriter(HtmlConfiguration configuration, DocPath path) {
194 super(configuration, path);
195 this.configuration = configuration;
196 this.contents = configuration.contents;
197 this.messages = configuration.messages;
198 this.resources = configuration.resources;
199 this.utils = configuration.utils;
200 this.path = path;
201 this.pathToRoot = path.parent().invert();
202 this.filename = path.basename();
203 }
204
205 /**
206 * Replace {@docRoot} tag used in options that accept HTML text, such
207 * as -header, -footer, -top and -bottom, and when converting a relative
208 * HREF where commentTagsToString inserts a {@docRoot} where one was
209 * missing. (Also see DocRootTaglet for {@docRoot} tags in doc
210 * comments.)
211 * <p>
212 * Replace {@docRoot} tag in htmlstr with the relative path to the
213 * destination directory from the directory where the file is being
214 * written, looping to handle all such tags in htmlstr.
215 * <p>
216 * For example, for "-d docs" and -header containing {@docRoot}, when
217 * the HTML page for source file p/C1.java is being generated, the
218 * {@docRoot} tag would be inserted into the header as "../",
349
350 /**
351 * Returns a TagletWriter that knows how to write HTML.
352 *
353 * @return a TagletWriter that knows how to write HTML.
354 */
355 public TagletWriter getTagletWriterInstance(boolean isFirstSentence) {
356 return new TagletWriterImpl(this, isFirstSentence);
357 }
358
359 /**
360 * Get Package link, with target frame.
361 *
362 * @param pkg The link will be to the "package-summary.html" page for this package
363 * @param target name of the target frame
364 * @param label tag for the link
365 * @return a content for the target package link
366 */
367 public Content getTargetPackageLink(PackageElement pkg, String target,
368 Content label) {
369 return getHyperLink(pathString(pkg, DocPaths.PACKAGE_SUMMARY), label, "", target);
370 }
371
372 /**
373 * Get Module Package link, with target frame.
374 *
375 * @param pkg the PackageElement
376 * @param target name of the target frame
377 * @param label tag for the link
378 * @param mdle the module being documented
379 * @return a content for the target module packages link
380 */
381 public Content getTargetModulePackageLink(PackageElement pkg, String target,
382 Content label, ModuleElement mdle) {
383 return getHyperLink(pathString(pkg, DocPaths.PACKAGE_SUMMARY),
384 label, "", target);
385 }
386
387 /**
388 * Get Module link, with target frame.
389 *
390 * @param target name of the target frame
391 * @param label tag for the link
392 * @param mdle the module being documented
393 * @return a content for the target module link
394 */
395 public Content getTargetModuleLink(String target, Content label, ModuleElement mdle) {
396 return getHyperLink(pathToRoot.resolve(
397 DocPaths.moduleSummary(mdle)), label, "", target);
398 }
399
400 /**
401 * Generates the HTML document tree and prints it out.
402 *
403 * @param metakeywords Array of String keywords for META tag. Each element
404 * of the array is assigned to a separate META tag.
405 * Pass in null for no array
406 * @param includeScript true if printing windowtitle script
407 * false for files that appear in the left-hand frames
408 * @param body the body htmltree to be included in the document
409 * @throws DocFileIOException if there is a problem writing the file
410 */
411 public void printHtmlDocument(List<String> metakeywords, boolean includeScript,
412 Content body) throws DocFileIOException {
413 DocType htmlDocType = DocType.forVersion(configuration.htmlVersion);
414 Content htmlComment = contents.newPage;
415 Head head = new Head(path, configuration.htmlVersion, configuration.docletVersion)
416 .setTimestamp(!configuration.notimestamp)
483
484 /**
485 * Adds the navigation bar for the Html page at the top and and the bottom.
486 *
487 * @param header If true print navigation bar at the top of the page else
488 * @param htmlTree the HtmlTree to which the nav links will be added
489 */
490 protected void addNavLinks(boolean header, Content htmlTree) {
491 if (!configuration.nonavbar) {
492 Content tree = (configuration.allowTag(HtmlTag.NAV))
493 ? HtmlTree.NAV()
494 : htmlTree;
495 String allClassesId = "allclasses_";
496 HtmlTree navDiv = new HtmlTree(HtmlTag.DIV);
497 fixedNavDiv.setStyle(HtmlStyle.fixedNav);
498 Content skipNavLinks = configuration.getContent("doclet.Skip_navigation_links");
499 if (header) {
500 fixedNavDiv.addContent(HtmlConstants.START_OF_TOP_NAVBAR);
501 navDiv.setStyle(HtmlStyle.topNav);
502 allClassesId += "navbar_top";
503 Content a = getMarkerAnchor(SectionName.NAVBAR_TOP);
504 //WCAG - Hyperlinks should contain text or an image with alt text - for AT tools
505 navDiv.addContent(a);
506 Content skipLinkContent = HtmlTree.DIV(HtmlStyle.skipNav, getHyperLink(
507 getDocLink(SectionName.SKIP_NAVBAR_TOP), skipNavLinks,
508 skipNavLinks.toString(), ""));
509 navDiv.addContent(skipLinkContent);
510 } else {
511 tree.addContent(HtmlConstants.START_OF_BOTTOM_NAVBAR);
512 navDiv.setStyle(HtmlStyle.bottomNav);
513 allClassesId += "navbar_bottom";
514 Content a = getMarkerAnchor(SectionName.NAVBAR_BOTTOM);
515 navDiv.addContent(a);
516 Content skipLinkContent = HtmlTree.DIV(HtmlStyle.skipNav, getHyperLink(
517 getDocLink(SectionName.SKIP_NAVBAR_BOTTOM), skipNavLinks,
518 skipNavLinks.toString(), ""));
519 navDiv.addContent(skipLinkContent);
520 }
521 if (header) {
522 navDiv.addContent(getMarkerAnchor(SectionName.NAVBAR_TOP_FIRSTROW));
523 } else {
524 navDiv.addContent(getMarkerAnchor(SectionName.NAVBAR_BOTTOM_FIRSTROW));
525 }
526 HtmlTree navList = new HtmlTree(HtmlTag.UL);
527 navList.setStyle(HtmlStyle.navList);
528 navList.addAttr(HtmlAttr.TITLE,
529 configuration.getText("doclet.Navigation"));
530 if (configuration.createoverview) {
531 navList.addContent(getNavLinkContents());
532 }
533 if (configuration.showModules) {
534 if (configuration.modules.size() == 1) {
535 navList.addContent(getNavLinkModule(configuration.modules.first()));
536 } else if (!configuration.modules.isEmpty()) {
537 navList.addContent(getNavLinkModule());
538 }
539 }
540 if (configuration.packages.size() == 1) {
541 navList.addContent(getNavLinkPackage(configuration.packages.first()));
542 } else if (!configuration.packages.isEmpty()) {
543 navList.addContent(getNavLinkPackage());
544 }
575 subDiv.addContent(ulFrames);
576 }
577 HtmlTree ulAllClasses = HtmlTree.UL(HtmlStyle.navList, getNavLinkClassIndex());
578 ulAllClasses.addAttr(HtmlAttr.ID, allClassesId);
579 subDiv.addContent(ulAllClasses);
580 if (header && configuration.createindex) {
581 String searchValueId = "search";
582 String reset = "reset";
583 HtmlTree inputText = HtmlTree.INPUT("text", searchValueId, searchValueId);
584 HtmlTree inputReset = HtmlTree.INPUT(reset, reset, reset);
585 Content searchTxt = configuration.getContent("doclet.search");
586 HtmlTree liInput = HtmlTree.LI(HtmlTree.LABEL(searchValueId, searchTxt));
587 liInput.addContent(inputText);
588 liInput.addContent(inputReset);
589 HtmlTree ulSearch = HtmlTree.UL(HtmlStyle.navListSearch, liInput);
590 subDiv.addContent(ulSearch);
591 }
592 subDiv.addContent(getAllClassesLinkScript(allClassesId));
593 addSummaryDetailLinks(subDiv);
594 if (header) {
595 subDiv.addContent(getMarkerAnchor(SectionName.SKIP_NAVBAR_TOP));
596 fixedNavDiv.addContent(subDiv);
597 fixedNavDiv.addContent(HtmlConstants.END_OF_TOP_NAVBAR);
598 tree.addContent(fixedNavDiv);
599 HtmlTree paddingDiv = HtmlTree.DIV(HtmlStyle.navPadding, Contents.SPACE);
600 tree.addContent(paddingDiv);
601 Script script = new Script(
602 "<!--\n"
603 + "$('.navPadding').css('padding-top', $('.fixedNav').css(\"height\"));\n"
604 + "//-->\n");
605 tree.addContent(script.asContent());
606 } else {
607 subDiv.addContent(getMarkerAnchor(SectionName.SKIP_NAVBAR_BOTTOM));
608 tree.addContent(subDiv);
609 tree.addContent(HtmlConstants.END_OF_BOTTOM_NAVBAR);
610 }
611 if (configuration.allowTag(HtmlTag.NAV)) {
612 htmlTree.addContent(tree);
613 }
614 }
615 }
616
617 /**
618 * Get the word "NEXT" to indicate that no link is available. Override
619 * this method to customize next link.
620 *
621 * @return a content tree for the link
622 */
623 protected Content getNavLinkNext() {
624 return getNavLinkNext(null);
625 }
626
627 /**
629 * this method to customize prev link.
630 *
631 * @return a content tree for the link
632 */
633 protected Content getNavLinkPrevious() {
634 return getNavLinkPrevious(null);
635 }
636
637 /**
638 * Do nothing. This is the default method.
639 */
640 protected void addSummaryDetailLinks(Content navDiv) {
641 }
642
643 /**
644 * Get link to the "overview-summary.html" page.
645 *
646 * @return a content tree for the link
647 */
648 protected Content getNavLinkContents() {
649 Content linkContent = getHyperLink(pathToRoot.resolve(DocPaths.overviewSummary(configuration.frames)),
650 contents.overviewLabel, "", "");
651 Content li = HtmlTree.LI(linkContent);
652 return li;
653 }
654
655 /**
656 * Get link to the module summary page for the module passed.
657 *
658 * @param mdle Module to which link will be generated
659 * @return a content tree for the link
660 */
661 protected Content getNavLinkModule(ModuleElement mdle) {
662 Content linkContent = getModuleLink(mdle, contents.moduleLabel);
663 Content li = HtmlTree.LI(linkContent);
664 return li;
665 }
666
667 /**
668 * Get the word "Module", to indicate that link is not available here.
669 *
698
699 /**
700 * Get the word "Use", to indicate that link is not available.
701 *
702 * @return a content tree for the link
703 */
704 protected Content getNavLinkClassUse() {
705 Content li = HtmlTree.LI(contents.useLabel);
706 return li;
707 }
708
709 /**
710 * Get link for previous file.
711 *
712 * @param prev File name for the prev link
713 * @return a content tree for the link
714 */
715 public Content getNavLinkPrevious(DocPath prev) {
716 Content li;
717 if (prev != null) {
718 li = HtmlTree.LI(getHyperLink(prev, contents.prevLabel, "", ""));
719 }
720 else
721 li = HtmlTree.LI(contents.prevLabel);
722 return li;
723 }
724
725 /**
726 * Get link for next file. If next is null, just print the label
727 * without linking it anywhere.
728 *
729 * @param next File name for the next link
730 * @return a content tree for the link
731 */
732 public Content getNavLinkNext(DocPath next) {
733 Content li;
734 if (next != null) {
735 li = HtmlTree.LI(getHyperLink(next, contents.nextLabel, "", ""));
736 }
737 else
738 li = HtmlTree.LI(contents.nextLabel);
739 return li;
740 }
741
742 /**
743 * Get "FRAMES" link, to switch to the frame version of the output.
744 *
745 * @param link File to be linked, "index.html"
746 * @return a content tree for the link
747 */
748 protected Content getNavShowLists(DocPath link) {
749 DocLink dl = new DocLink(link, path.getPath(), null);
750 Content framesContent = getHyperLink(dl, contents.framesLabel, "", "_top");
751 Content li = HtmlTree.LI(framesContent);
752 return li;
753 }
754
755 /**
756 * Get "FRAMES" link, to switch to the frame version of the output.
757 *
758 * @return a content tree for the link
759 */
760 protected Content getNavShowLists() {
761 return getNavShowLists(pathToRoot.resolve(DocPaths.INDEX));
762 }
763
764 /**
765 * Get "NO FRAMES" link, to switch to the non-frame version of the output.
766 *
767 * @param link File to be linked
768 * @return a content tree for the link
769 */
770 protected Content getNavHideLists(DocPath link) {
771 Content noFramesContent = getHyperLink(link, contents.noFramesLabel, "", "_top");
772 Content li = HtmlTree.LI(noFramesContent);
773 return li;
774 }
775
776 /**
777 * Get "Tree" link in the navigation bar. If there is only one package
778 * specified on the command line, then the "Tree" link will be to the
779 * only "package-tree.html" file otherwise it will be to the
780 * "overview-tree.html" file.
781 *
782 * @return a content tree for the link
783 */
784 protected Content getNavLinkTree() {
785 List<PackageElement> packages = new ArrayList<>(configuration.getSpecifiedPackageElements());
786 DocPath docPath = packages.size() == 1 && configuration.getSpecifiedTypeElements().isEmpty()
787 ? pathString(packages.get(0), DocPaths.PACKAGE_TREE)
788 : pathToRoot.resolve(DocPaths.OVERVIEW_TREE);
789 return HtmlTree.LI(getHyperLink(docPath, contents.treeLabel, "", ""));
790 }
791
792 /**
793 * Get the overview tree link for the main tree.
794 *
795 * @param label the label for the link
796 * @return a content tree for the link
797 */
798 protected Content getNavLinkMainTree(String label) {
799 Content mainTreeContent = getHyperLink(pathToRoot.resolve(DocPaths.OVERVIEW_TREE),
800 new StringContent(label));
801 Content li = HtmlTree.LI(mainTreeContent);
802 return li;
803 }
804
805 /**
806 * Get the word "Class", to indicate that class link is not available.
807 *
808 * @return a content tree for the link
809 */
810 protected Content getNavLinkClass() {
811 Content li = HtmlTree.LI(contents.classLabel);
812 return li;
813 }
814
815 /**
816 * Get "Deprecated" API link in the navigation bar.
817 *
818 * @return a content tree for the link
819 */
820 protected Content getNavLinkDeprecated() {
821 Content linkContent = getHyperLink(pathToRoot.resolve(DocPaths.DEPRECATED_LIST),
822 contents.deprecatedLabel, "", "");
823 Content li = HtmlTree.LI(linkContent);
824 return li;
825 }
826
827 /**
828 * Get link for generated index. If the user has used "-splitindex"
829 * command line option, then link to file "index-files/index-1.html" is
830 * generated otherwise link to file "index-all.html" is generated.
831 *
832 * @return a content tree for the link
833 */
834 protected Content getNavLinkClassIndex() {
835 Content allClassesContent = getHyperLink(pathToRoot.resolve(
836 DocPaths.AllClasses(configuration.frames)),
837 contents.allClassesLabel, "", "");
838 Content li = HtmlTree.LI(allClassesContent);
839 return li;
840 }
841
842 /**
843 * Get link for generated class index.
844 *
845 * @return a content tree for the link
846 */
847 protected Content getNavLinkIndex() {
848 Content linkContent = getHyperLink(pathToRoot.resolve(
849 (configuration.splitindex
850 ? DocPaths.INDEX_FILES.resolve(DocPaths.indexN(1))
851 : DocPaths.INDEX_ALL)),
852 contents.indexLabel, "", "");
853 Content li = HtmlTree.LI(linkContent);
854 return li;
855 }
856
857 /**
858 * Get help file link. If user has provided a help file, then generate a
859 * link to the user given file, which is already copied to current or
860 * destination directory.
861 *
862 * @return a content tree for the link
863 */
864 protected Content getNavLinkHelp() {
865 String helpfile = configuration.helpfile;
866 DocPath helpfilenm;
867 if (helpfile.isEmpty()) {
868 helpfilenm = DocPaths.HELP_DOC;
869 } else {
870 DocFile file = DocFile.createFileForInput(configuration, helpfile);
871 helpfilenm = DocPath.create(file.getName());
872 }
873 Content linkContent = getHyperLink(pathToRoot.resolve(helpfilenm),
874 contents.helpLabel, "", "");
875 Content li = HtmlTree.LI(linkContent);
876 return li;
877 }
878
879 /**
880 * Add gap between navigation bar elements.
881 *
882 * @param liNav the content tree to which the gap will be added
883 */
884 protected void addNavGap(Content liNav) {
885 liNav.addContent(Contents.SPACE);
886 liNav.addContent("|");
887 liNav.addContent(Contents.SPACE);
888 }
889
890 /**
891 * Get table caption.
892 *
893 * @param title the content for the caption
894 * @return a content tree for the caption
895 */
896 public Content getTableCaption(Content title) {
897 Content captionSpan = HtmlTree.SPAN(title);
898 Content space = Contents.SPACE;
899 Content tabSpan = HtmlTree.SPAN(HtmlStyle.tabEnd, space);
900 Content caption = HtmlTree.CAPTION(captionSpan);
901 caption.addContent(tabSpan);
902 return caption;
903 }
904
905 /**
906 * Get the marker anchor which will be added to the documentation tree.
907 *
908 * @param anchorName the anchor name attribute
909 * @return a content tree for the marker anchor
910 */
911 public Content getMarkerAnchor(String anchorName) {
912 return getMarkerAnchor(getName(anchorName), null);
913 }
914
915 /**
916 * Get the marker anchor which will be added to the documentation tree.
917 *
918 * @param sectionName the section name anchor attribute for page
919 * @return a content tree for the marker anchor
920 */
921 public Content getMarkerAnchor(SectionName sectionName) {
922 return getMarkerAnchor(sectionName.getName(), null);
923 }
924
925 /**
926 * Get the marker anchor which will be added to the documentation tree.
927 *
928 * @param sectionName the section name anchor attribute for page
929 * @param anchorName the anchor name combined with section name attribute for the page
930 * @return a content tree for the marker anchor
931 */
932 public Content getMarkerAnchor(SectionName sectionName, String anchorName) {
933 return getMarkerAnchor(sectionName.getName() + getName(anchorName), null);
934 }
935
936 /**
937 * Get the marker anchor which will be added to the documentation tree.
938 *
939 * @param anchorName the anchor name or id attribute
940 * @param anchorContent the content that should be added to the anchor
941 * @return a content tree for the marker anchor
942 */
943 public Content getMarkerAnchor(String anchorName, Content anchorContent) {
944 if (anchorContent == null)
945 anchorContent = new Comment(" ");
946 Content markerAnchor = HtmlTree.A(configuration.htmlVersion, anchorName, anchorContent);
947 return markerAnchor;
948 }
949
950 /**
951 * Returns a packagename content.
952 *
953 * @param packageElement the package to check
954 * @return package name content
955 */
956 public Content getPackageName(PackageElement packageElement) {
957 return packageElement == null || packageElement.isUnnamed()
958 ? contents.defaultPackageLabel
959 : getPackageLabel(packageElement.getQualifiedName());
960 }
961
962 /**
963 * Returns a package name label.
964 *
965 * @param packageName the package name
966 * @return the package name content
967 */
968 public Content getPackageLabel(CharSequence packageName) {
969 return new StringContent(packageName);
970 }
1022 }
1023
1024 /**
1025 * Return the link to the given package.
1026 *
1027 * @param packageElement the package to link to.
1028 * @param label the label for the link.
1029 * @return a content tree for the package link.
1030 */
1031 public Content getPackageLink(PackageElement packageElement, Content label) {
1032 boolean included = packageElement != null && utils.isIncluded(packageElement);
1033 if (!included) {
1034 for (PackageElement p : configuration.packages) {
1035 if (p.equals(packageElement)) {
1036 included = true;
1037 break;
1038 }
1039 }
1040 }
1041 if (included || packageElement == null) {
1042 return getHyperLink(pathString(packageElement, DocPaths.PACKAGE_SUMMARY),
1043 label);
1044 } else {
1045 DocLink crossPkgLink = getCrossPackageLink(utils.getPackageName(packageElement));
1046 if (crossPkgLink != null) {
1047 return getHyperLink(crossPkgLink, label);
1048 } else {
1049 return label;
1050 }
1051 }
1052 }
1053
1054 /**
1055 * Get Module link.
1056 *
1057 * @param mdle the module being documented
1058 * @param label tag for the link
1059 * @return a content for the module link
1060 */
1061 public Content getModuleLink(ModuleElement mdle, Content label) {
1062 boolean included = utils.isIncluded(mdle);
1063 return (included)
1064 ? getHyperLink(pathToRoot.resolve(DocPaths.moduleSummary(mdle)), label, "", "")
1065 : label;
1066 }
1067
1068 public Content interfaceName(TypeElement typeElement, boolean qual) {
1069 Content name = new StringContent((qual)
1070 ? typeElement.getQualifiedName()
1071 : utils.getSimpleName(typeElement));
1072 return (utils.isInterface(typeElement)) ? HtmlTree.SPAN(HtmlStyle.interfaceName, name) : name;
1073 }
1074
1075 /**
1076 * Add the link to the content tree.
1077 *
1078 * @param typeElement program element typeElement for which the link will be added
1079 * @param label label for the link
1080 * @param htmltree the content tree to which the link will be added
1081 */
1082 public void addSrcLink(Element typeElement, Content label, Content htmltree) {
1083 if (typeElement == null) {
1084 return;
1085 }
1086 TypeElement te = utils.getEnclosingTypeElement(typeElement);
1087 if (te == null) {
1088 // must be a typeElement since in has no containing class.
1089 te = (TypeElement) typeElement;
1090 }
1091 DocPath href = pathToRoot
1092 .resolve(DocPaths.SOURCE_OUTPUT)
1093 .resolve(DocPath.forClass(utils, te));
1094 Content linkContent = getHyperLink(href
1095 .fragment(SourceToHTMLConverter.getAnchorName(utils, typeElement)), label, "", "");
1096 htmltree.addContent(linkContent);
1097 }
1098
1099 /**
1100 * Return the link to the given class.
1101 *
1102 * @param linkInfo the information about the link.
1103 *
1104 * @return the link for the given class.
1105 */
1106 public Content getLink(LinkInfoImpl linkInfo) {
1107 LinkFactoryImpl factory = new LinkFactoryImpl(this);
1108 return factory.getLink(linkInfo);
1109 }
1110
1111 /**
1112 * Return the type parameters for the given class.
1113 *
1114 * @param linkInfo the information about the link.
1139 String className = "";
1140 String packageName = qualifiedClassName == null ? "" : qualifiedClassName;
1141 int periodIndex;
1142 while ((periodIndex = packageName.lastIndexOf('.')) != -1) {
1143 className = packageName.substring(periodIndex + 1, packageName.length()) +
1144 (className.length() > 0 ? "." + className : "");
1145 Content defaultLabel = new StringContent(className);
1146 if (code)
1147 defaultLabel = HtmlTree.CODE(defaultLabel);
1148 packageName = packageName.substring(0, periodIndex);
1149 if (getCrossPackageLink(packageName) != null) {
1150 /*
1151 The package exists in external documentation, so link to the external
1152 class (assuming that it exists). This is definitely a limitation of
1153 the -link option. There are ways to determine if an external package
1154 exists, but no way to determine if the external class exists. We just
1155 have to assume that it does.
1156 */
1157 DocLink link = configuration.extern.getExternalLink(packageName, pathToRoot,
1158 className + ".html", refMemName);
1159 return getHyperLink(link,
1160 (label == null) || label.isEmpty() ? defaultLabel : label,
1161 strong, style,
1162 configuration.getText("doclet.Href_Class_Or_Interface_Title", packageName),
1163 "");
1164 }
1165 }
1166 return null;
1167 }
1168
1169 public boolean isClassLinkable(TypeElement typeElement) {
1170 if (utils.isIncluded(typeElement)) {
1171 return configuration.isGeneratedDoc(typeElement);
1172 }
1173 return configuration.extern.isExternal(typeElement);
1174 }
1175
1176 public DocLink getCrossPackageLink(String pkgName) {
1177 return configuration.extern.getExternalLink(pkgName, pathToRoot,
1178 DocPaths.PACKAGE_SUMMARY.getPath());
1179 }
1323 CharSequence label, boolean strong, boolean isProperty) {
1324 return getDocLink(context, typeElement, element, new StringContent(check(label)), strong, isProperty);
1325 }
1326
1327 CharSequence check(CharSequence s) {
1328 Matcher m = IMPROPER_HTML_CHARS.matcher(s);
1329 if (m.matches()) {
1330 throw new IllegalArgumentException(s.toString());
1331 }
1332 return s;
1333 }
1334
1335 public Content getDocLink(LinkInfoImpl.Kind context, TypeElement typeElement, Element element,
1336 Content label, boolean strong, boolean isProperty) {
1337 if (! (utils.isIncluded(element) || utils.isLinkable(typeElement))) {
1338 return label;
1339 } else if (utils.isExecutableElement(element)) {
1340 ExecutableElement ee = (ExecutableElement)element;
1341 return getLink(new LinkInfoImpl(configuration, context, typeElement)
1342 .label(label)
1343 .where(getName(getAnchor(ee, isProperty)))
1344 .strong(strong));
1345 } else if (utils.isVariableElement(element) || utils.isTypeElement(element)) {
1346 return getLink(new LinkInfoImpl(configuration, context, typeElement)
1347 .label(label)
1348 .where(getName(element.getSimpleName().toString()))
1349 .strong(strong));
1350 } else {
1351 return label;
1352 }
1353 }
1354
1355 /**
1356 * Return the link for the given member.
1357 *
1358 * @param context the id of the context where the link will be added
1359 * @param typeElement the typeElement that we should link to. This is not
1360 necessarily equal to element.containingClass(). We may be
1361 inheriting comments
1362 * @param element the member being linked to
1363 * @param label the label for the link
1364 * @return the link for the given member
1365 */
1366 public Content getDocLink(LinkInfoImpl.Kind context, TypeElement typeElement, Element element,
1367 Content label) {
1368 if (! (utils.isIncluded(element) || utils.isLinkable(typeElement))) {
1369 return label;
1370 } else if (utils.isExecutableElement(element)) {
1371 ExecutableElement emd = (ExecutableElement) element;
1372 return getLink(new LinkInfoImpl(configuration, context, typeElement)
1373 .label(label)
1374 .where(getName(getAnchor(emd))));
1375 } else if (utils.isVariableElement(element) || utils.isTypeElement(element)) {
1376 return getLink(new LinkInfoImpl(configuration, context, typeElement)
1377 .label(label).where(getName(element.getSimpleName().toString())));
1378 } else {
1379 return label;
1380 }
1381 }
1382
1383 public String getAnchor(ExecutableElement executableElement) {
1384 return getAnchor(executableElement, false);
1385 }
1386
1387 public String getAnchor(ExecutableElement executableElement, boolean isProperty) {
1388 if (isProperty) {
1389 return executableElement.getSimpleName().toString();
1390 }
1391 String member = anchorName(executableElement);
1392 String erasedSignature = utils.makeSignature(executableElement, true, true);
1393 return member + erasedSignature;
1394 }
1395
1396 public String anchorName(Element member) {
1397 if (member.getKind() == ElementKind.CONSTRUCTOR
1428 String refMemName = ch.getReferencedMemberName(see);
1429
1430 if (refMemName == null && refMem != null) {
1431 refMemName = refMem.toString();
1432 }
1433 if (refClass == null) {
1434 //@see is not referencing an included class
1435 PackageElement refPackage = ch.getReferencedPackage(configuration, see);
1436 if (refPackage != null && utils.isIncluded(refPackage)) {
1437 //@see is referencing an included package
1438 if (label.isEmpty())
1439 label = plainOrCode(isLinkPlain,
1440 new StringContent(refPackage.getQualifiedName()));
1441 return getPackageLink(refPackage, label);
1442 } else {
1443 // @see is not referencing an included class or package. Check for cross links.
1444 Content classCrossLink;
1445 DocLink packageCrossLink = getCrossPackageLink(refClassName);
1446 if (packageCrossLink != null) {
1447 // Package cross link found
1448 return getHyperLink(packageCrossLink,
1449 (label.isEmpty() ? text : label));
1450 } else if ((classCrossLink = getCrossClassLink(refClassName,
1451 refMemName, label, false, "", !isLinkPlain)) != null) {
1452 // Class cross link found (possibly to a member in the class)
1453 return classCrossLink;
1454 } else {
1455 // No cross link found so print warning
1456 messages.warning(ch.getDocTreePath(see),
1457 "doclet.see.class_or_package_not_found",
1458 "@" + tagName,
1459 seetext);
1460 return (label.isEmpty() ? text: label);
1461 }
1462 }
1463 } else if (refMemName == null) {
1464 // Must be a class reference since refClass is not null and refMemName is null.
1465 if (label.isEmpty()) {
1466 /*
1467 * it seems to me this is the right thing to do, but it causes comparator failures.
1468 */
|
60 import com.sun.source.doctree.IndexTree;
61 import com.sun.source.doctree.InheritDocTree;
62 import com.sun.source.doctree.LinkTree;
63 import com.sun.source.doctree.LiteralTree;
64 import com.sun.source.doctree.SeeTree;
65 import com.sun.source.doctree.StartElementTree;
66 import com.sun.source.doctree.SummaryTree;
67 import com.sun.source.doctree.TextTree;
68 import com.sun.source.util.SimpleDocTreeVisitor;
69
70 import jdk.javadoc.internal.doclets.formats.html.markup.Comment;
71 import jdk.javadoc.internal.doclets.formats.html.markup.ContentBuilder;
72 import jdk.javadoc.internal.doclets.formats.html.markup.DocType;
73 import jdk.javadoc.internal.doclets.formats.html.markup.HtmlAttr;
74 import jdk.javadoc.internal.doclets.formats.html.markup.HtmlConstants;
75 import jdk.javadoc.internal.doclets.formats.html.markup.HtmlDocWriter;
76 import jdk.javadoc.internal.doclets.formats.html.markup.HtmlDocument;
77 import jdk.javadoc.internal.doclets.formats.html.markup.HtmlStyle;
78 import jdk.javadoc.internal.doclets.formats.html.markup.HtmlTag;
79 import jdk.javadoc.internal.doclets.formats.html.markup.HtmlTree;
80 import jdk.javadoc.internal.doclets.formats.html.markup.Links;
81 import jdk.javadoc.internal.doclets.formats.html.markup.RawHtml;
82 import jdk.javadoc.internal.doclets.formats.html.markup.Script;
83 import jdk.javadoc.internal.doclets.formats.html.markup.StringContent;
84 import jdk.javadoc.internal.doclets.toolkit.AnnotationTypeWriter;
85 import jdk.javadoc.internal.doclets.toolkit.ClassWriter;
86 import jdk.javadoc.internal.doclets.toolkit.Content;
87 import jdk.javadoc.internal.doclets.toolkit.Messages;
88 import jdk.javadoc.internal.doclets.toolkit.PackageSummaryWriter;
89 import jdk.javadoc.internal.doclets.toolkit.Resources;
90 import jdk.javadoc.internal.doclets.toolkit.taglets.DocRootTaglet;
91 import jdk.javadoc.internal.doclets.toolkit.taglets.TagletWriter;
92 import jdk.javadoc.internal.doclets.toolkit.util.CommentHelper;
93 import jdk.javadoc.internal.doclets.toolkit.util.DocFile;
94 import jdk.javadoc.internal.doclets.toolkit.util.DocFileIOException;
95 import jdk.javadoc.internal.doclets.toolkit.util.DocLink;
96 import jdk.javadoc.internal.doclets.toolkit.util.DocPath;
97 import jdk.javadoc.internal.doclets.toolkit.util.DocPaths;
98 import jdk.javadoc.internal.doclets.toolkit.util.DocletConstants;
99 import jdk.javadoc.internal.doclets.toolkit.util.ImplementedMethods;
100 import jdk.javadoc.internal.doclets.toolkit.util.Utils;
138
139 /**
140 * Name of the file getting generated. If the file getting generated is
141 * "java/lang/Object.html", then the filename is "Object.html".
142 */
143 public final DocPath filename;
144
145 /**
146 * The global configuration information for this run.
147 */
148 public final HtmlConfiguration configuration;
149
150 protected final Utils utils;
151
152 protected final Contents contents;
153
154 protected final Messages messages;
155
156 protected final Resources resources;
157
158 protected final Links links;
159
160 /**
161 * To check whether annotation heading is printed or not.
162 */
163 protected boolean printedAnnotationHeading = false;
164
165 /**
166 * To check whether annotation field heading is printed or not.
167 */
168 protected boolean printedAnnotationFieldHeading = false;
169
170 /**
171 * To check whether the repeated annotations is documented or not.
172 */
173 private boolean isAnnotationDocumented = false;
174
175 /**
176 * To check whether the container annotations is documented or not.
177 */
178 private boolean isContainerDocumented = false;
179
182 final static Pattern IMPROPER_HTML_CHARS = Pattern.compile(".*[&<>].*");
183
184 /**
185 * The window title of this file.
186 */
187 protected String winTitle;
188
189 protected Script mainBodyScript;
190
191 /**
192 * Constructor to construct the HtmlStandardWriter object.
193 *
194 * @param path File to be generated.
195 */
196 public HtmlDocletWriter(HtmlConfiguration configuration, DocPath path) {
197 super(configuration, path);
198 this.configuration = configuration;
199 this.contents = configuration.contents;
200 this.messages = configuration.messages;
201 this.resources = configuration.resources;
202 this.links = configuration.links;
203 this.utils = configuration.utils;
204 this.path = path;
205 this.pathToRoot = path.parent().invert();
206 this.filename = path.basename();
207 }
208
209 /**
210 * Replace {@docRoot} tag used in options that accept HTML text, such
211 * as -header, -footer, -top and -bottom, and when converting a relative
212 * HREF where commentTagsToString inserts a {@docRoot} where one was
213 * missing. (Also see DocRootTaglet for {@docRoot} tags in doc
214 * comments.)
215 * <p>
216 * Replace {@docRoot} tag in htmlstr with the relative path to the
217 * destination directory from the directory where the file is being
218 * written, looping to handle all such tags in htmlstr.
219 * <p>
220 * For example, for "-d docs" and -header containing {@docRoot}, when
221 * the HTML page for source file p/C1.java is being generated, the
222 * {@docRoot} tag would be inserted into the header as "../",
353
354 /**
355 * Returns a TagletWriter that knows how to write HTML.
356 *
357 * @return a TagletWriter that knows how to write HTML.
358 */
359 public TagletWriter getTagletWriterInstance(boolean isFirstSentence) {
360 return new TagletWriterImpl(this, isFirstSentence);
361 }
362
363 /**
364 * Get Package link, with target frame.
365 *
366 * @param pkg The link will be to the "package-summary.html" page for this package
367 * @param target name of the target frame
368 * @param label tag for the link
369 * @return a content for the target package link
370 */
371 public Content getTargetPackageLink(PackageElement pkg, String target,
372 Content label) {
373 return Links.createLink(pathString(pkg, DocPaths.PACKAGE_SUMMARY), label, "", target);
374 }
375
376 /**
377 * Get Module Package link, with target frame.
378 *
379 * @param pkg the PackageElement
380 * @param target name of the target frame
381 * @param label tag for the link
382 * @param mdle the module being documented
383 * @return a content for the target module packages link
384 */
385 public Content getTargetModulePackageLink(PackageElement pkg, String target,
386 Content label, ModuleElement mdle) {
387 return Links.createLink(pathString(pkg, DocPaths.PACKAGE_SUMMARY),
388 label, "", target);
389 }
390
391 /**
392 * Get Module link, with target frame.
393 *
394 * @param target name of the target frame
395 * @param label tag for the link
396 * @param mdle the module being documented
397 * @return a content for the target module link
398 */
399 public Content getTargetModuleLink(String target, Content label, ModuleElement mdle) {
400 return Links.createLink(pathToRoot.resolve(
401 DocPaths.moduleSummary(mdle)), label, "", target);
402 }
403
404 /**
405 * Generates the HTML document tree and prints it out.
406 *
407 * @param metakeywords Array of String keywords for META tag. Each element
408 * of the array is assigned to a separate META tag.
409 * Pass in null for no array
410 * @param includeScript true if printing windowtitle script
411 * false for files that appear in the left-hand frames
412 * @param body the body htmltree to be included in the document
413 * @throws DocFileIOException if there is a problem writing the file
414 */
415 public void printHtmlDocument(List<String> metakeywords, boolean includeScript,
416 Content body) throws DocFileIOException {
417 DocType htmlDocType = DocType.forVersion(configuration.htmlVersion);
418 Content htmlComment = contents.newPage;
419 Head head = new Head(path, configuration.htmlVersion, configuration.docletVersion)
420 .setTimestamp(!configuration.notimestamp)
487
488 /**
489 * Adds the navigation bar for the Html page at the top and and the bottom.
490 *
491 * @param header If true print navigation bar at the top of the page else
492 * @param htmlTree the HtmlTree to which the nav links will be added
493 */
494 protected void addNavLinks(boolean header, Content htmlTree) {
495 if (!configuration.nonavbar) {
496 Content tree = (configuration.allowTag(HtmlTag.NAV))
497 ? HtmlTree.NAV()
498 : htmlTree;
499 String allClassesId = "allclasses_";
500 HtmlTree navDiv = new HtmlTree(HtmlTag.DIV);
501 fixedNavDiv.setStyle(HtmlStyle.fixedNav);
502 Content skipNavLinks = configuration.getContent("doclet.Skip_navigation_links");
503 if (header) {
504 fixedNavDiv.addContent(HtmlConstants.START_OF_TOP_NAVBAR);
505 navDiv.setStyle(HtmlStyle.topNav);
506 allClassesId += "navbar_top";
507 Content a = links.createAnchor(SectionName.NAVBAR_TOP);
508 //WCAG - Hyperlinks should contain text or an image with alt text - for AT tools
509 navDiv.addContent(a);
510 Content skipLinkContent = HtmlTree.DIV(HtmlStyle.skipNav,
511 Links.createLink(SectionName.SKIP_NAVBAR_TOP, skipNavLinks,
512 skipNavLinks.toString(), ""));
513 navDiv.addContent(skipLinkContent);
514 } else {
515 tree.addContent(HtmlConstants.START_OF_BOTTOM_NAVBAR);
516 navDiv.setStyle(HtmlStyle.bottomNav);
517 allClassesId += "navbar_bottom";
518 Content a = links.createAnchor(SectionName.NAVBAR_BOTTOM);
519 navDiv.addContent(a);
520 Content skipLinkContent = HtmlTree.DIV(HtmlStyle.skipNav,
521 Links.createLink(SectionName.SKIP_NAVBAR_BOTTOM, skipNavLinks,
522 skipNavLinks.toString(), ""));
523 navDiv.addContent(skipLinkContent);
524 }
525 if (header) {
526 navDiv.addContent(links.createAnchor(SectionName.NAVBAR_TOP_FIRSTROW));
527 } else {
528 navDiv.addContent(links.createAnchor(SectionName.NAVBAR_BOTTOM_FIRSTROW));
529 }
530 HtmlTree navList = new HtmlTree(HtmlTag.UL);
531 navList.setStyle(HtmlStyle.navList);
532 navList.addAttr(HtmlAttr.TITLE,
533 configuration.getText("doclet.Navigation"));
534 if (configuration.createoverview) {
535 navList.addContent(getNavLinkContents());
536 }
537 if (configuration.showModules) {
538 if (configuration.modules.size() == 1) {
539 navList.addContent(getNavLinkModule(configuration.modules.first()));
540 } else if (!configuration.modules.isEmpty()) {
541 navList.addContent(getNavLinkModule());
542 }
543 }
544 if (configuration.packages.size() == 1) {
545 navList.addContent(getNavLinkPackage(configuration.packages.first()));
546 } else if (!configuration.packages.isEmpty()) {
547 navList.addContent(getNavLinkPackage());
548 }
579 subDiv.addContent(ulFrames);
580 }
581 HtmlTree ulAllClasses = HtmlTree.UL(HtmlStyle.navList, getNavLinkClassIndex());
582 ulAllClasses.addAttr(HtmlAttr.ID, allClassesId);
583 subDiv.addContent(ulAllClasses);
584 if (header && configuration.createindex) {
585 String searchValueId = "search";
586 String reset = "reset";
587 HtmlTree inputText = HtmlTree.INPUT("text", searchValueId, searchValueId);
588 HtmlTree inputReset = HtmlTree.INPUT(reset, reset, reset);
589 Content searchTxt = configuration.getContent("doclet.search");
590 HtmlTree liInput = HtmlTree.LI(HtmlTree.LABEL(searchValueId, searchTxt));
591 liInput.addContent(inputText);
592 liInput.addContent(inputReset);
593 HtmlTree ulSearch = HtmlTree.UL(HtmlStyle.navListSearch, liInput);
594 subDiv.addContent(ulSearch);
595 }
596 subDiv.addContent(getAllClassesLinkScript(allClassesId));
597 addSummaryDetailLinks(subDiv);
598 if (header) {
599 subDiv.addContent(links.createAnchor(SectionName.SKIP_NAVBAR_TOP));
600 fixedNavDiv.addContent(subDiv);
601 fixedNavDiv.addContent(HtmlConstants.END_OF_TOP_NAVBAR);
602 tree.addContent(fixedNavDiv);
603 HtmlTree paddingDiv = HtmlTree.DIV(HtmlStyle.navPadding, Contents.SPACE);
604 tree.addContent(paddingDiv);
605 Script script = new Script(
606 "<!--\n"
607 + "$('.navPadding').css('padding-top', $('.fixedNav').css(\"height\"));\n"
608 + "//-->\n");
609 tree.addContent(script.asContent());
610 } else {
611 subDiv.addContent(links.createAnchor(SectionName.SKIP_NAVBAR_BOTTOM));
612 tree.addContent(subDiv);
613 tree.addContent(HtmlConstants.END_OF_BOTTOM_NAVBAR);
614 }
615 if (configuration.allowTag(HtmlTag.NAV)) {
616 htmlTree.addContent(tree);
617 }
618 }
619 }
620
621 /**
622 * Get the word "NEXT" to indicate that no link is available. Override
623 * this method to customize next link.
624 *
625 * @return a content tree for the link
626 */
627 protected Content getNavLinkNext() {
628 return getNavLinkNext(null);
629 }
630
631 /**
633 * this method to customize prev link.
634 *
635 * @return a content tree for the link
636 */
637 protected Content getNavLinkPrevious() {
638 return getNavLinkPrevious(null);
639 }
640
641 /**
642 * Do nothing. This is the default method.
643 */
644 protected void addSummaryDetailLinks(Content navDiv) {
645 }
646
647 /**
648 * Get link to the "overview-summary.html" page.
649 *
650 * @return a content tree for the link
651 */
652 protected Content getNavLinkContents() {
653 Content linkContent = Links.createLink(pathToRoot.resolve(DocPaths.overviewSummary(configuration.frames)),
654 contents.overviewLabel, "", "");
655 Content li = HtmlTree.LI(linkContent);
656 return li;
657 }
658
659 /**
660 * Get link to the module summary page for the module passed.
661 *
662 * @param mdle Module to which link will be generated
663 * @return a content tree for the link
664 */
665 protected Content getNavLinkModule(ModuleElement mdle) {
666 Content linkContent = getModuleLink(mdle, contents.moduleLabel);
667 Content li = HtmlTree.LI(linkContent);
668 return li;
669 }
670
671 /**
672 * Get the word "Module", to indicate that link is not available here.
673 *
702
703 /**
704 * Get the word "Use", to indicate that link is not available.
705 *
706 * @return a content tree for the link
707 */
708 protected Content getNavLinkClassUse() {
709 Content li = HtmlTree.LI(contents.useLabel);
710 return li;
711 }
712
713 /**
714 * Get link for previous file.
715 *
716 * @param prev File name for the prev link
717 * @return a content tree for the link
718 */
719 public Content getNavLinkPrevious(DocPath prev) {
720 Content li;
721 if (prev != null) {
722 li = HtmlTree.LI(Links.createLink(prev, contents.prevLabel, "", ""));
723 }
724 else
725 li = HtmlTree.LI(contents.prevLabel);
726 return li;
727 }
728
729 /**
730 * Get link for next file. If next is null, just print the label
731 * without linking it anywhere.
732 *
733 * @param next File name for the next link
734 * @return a content tree for the link
735 */
736 public Content getNavLinkNext(DocPath next) {
737 Content li;
738 if (next != null) {
739 li = HtmlTree.LI(Links.createLink(next, contents.nextLabel, "", ""));
740 }
741 else
742 li = HtmlTree.LI(contents.nextLabel);
743 return li;
744 }
745
746 /**
747 * Get "FRAMES" link, to switch to the frame version of the output.
748 *
749 * @param link File to be linked, "index.html"
750 * @return a content tree for the link
751 */
752 protected Content getNavShowLists(DocPath link) {
753 DocLink dl = new DocLink(link, path.getPath(), null);
754 Content framesContent = Links.createLink(dl, contents.framesLabel, "", "_top");
755 Content li = HtmlTree.LI(framesContent);
756 return li;
757 }
758
759 /**
760 * Get "FRAMES" link, to switch to the frame version of the output.
761 *
762 * @return a content tree for the link
763 */
764 protected Content getNavShowLists() {
765 return getNavShowLists(pathToRoot.resolve(DocPaths.INDEX));
766 }
767
768 /**
769 * Get "NO FRAMES" link, to switch to the non-frame version of the output.
770 *
771 * @param link File to be linked
772 * @return a content tree for the link
773 */
774 protected Content getNavHideLists(DocPath link) {
775 Content noFramesContent = Links.createLink(link, contents.noFramesLabel, "", "_top");
776 Content li = HtmlTree.LI(noFramesContent);
777 return li;
778 }
779
780 /**
781 * Get "Tree" link in the navigation bar. If there is only one package
782 * specified on the command line, then the "Tree" link will be to the
783 * only "package-tree.html" file otherwise it will be to the
784 * "overview-tree.html" file.
785 *
786 * @return a content tree for the link
787 */
788 protected Content getNavLinkTree() {
789 List<PackageElement> packages = new ArrayList<>(configuration.getSpecifiedPackageElements());
790 DocPath docPath = packages.size() == 1 && configuration.getSpecifiedTypeElements().isEmpty()
791 ? pathString(packages.get(0), DocPaths.PACKAGE_TREE)
792 : pathToRoot.resolve(DocPaths.OVERVIEW_TREE);
793 return HtmlTree.LI(Links.createLink(docPath, contents.treeLabel, "", ""));
794 }
795
796 /**
797 * Get the overview tree link for the main tree.
798 *
799 * @param label the label for the link
800 * @return a content tree for the link
801 */
802 protected Content getNavLinkMainTree(String label) {
803 Content mainTreeContent = Links.createLink(pathToRoot.resolve(DocPaths.OVERVIEW_TREE),
804 new StringContent(label));
805 Content li = HtmlTree.LI(mainTreeContent);
806 return li;
807 }
808
809 /**
810 * Get the word "Class", to indicate that class link is not available.
811 *
812 * @return a content tree for the link
813 */
814 protected Content getNavLinkClass() {
815 Content li = HtmlTree.LI(contents.classLabel);
816 return li;
817 }
818
819 /**
820 * Get "Deprecated" API link in the navigation bar.
821 *
822 * @return a content tree for the link
823 */
824 protected Content getNavLinkDeprecated() {
825 Content linkContent = Links.createLink(pathToRoot.resolve(DocPaths.DEPRECATED_LIST),
826 contents.deprecatedLabel, "", "");
827 Content li = HtmlTree.LI(linkContent);
828 return li;
829 }
830
831 /**
832 * Get link for generated index. If the user has used "-splitindex"
833 * command line option, then link to file "index-files/index-1.html" is
834 * generated otherwise link to file "index-all.html" is generated.
835 *
836 * @return a content tree for the link
837 */
838 protected Content getNavLinkClassIndex() {
839 Content allClassesContent = Links.createLink(pathToRoot.resolve(
840 DocPaths.AllClasses(configuration.frames)),
841 contents.allClassesLabel, "", "");
842 Content li = HtmlTree.LI(allClassesContent);
843 return li;
844 }
845
846 /**
847 * Get link for generated class index.
848 *
849 * @return a content tree for the link
850 */
851 protected Content getNavLinkIndex() {
852 Content linkContent = Links.createLink(pathToRoot.resolve(
853 (configuration.splitindex
854 ? DocPaths.INDEX_FILES.resolve(DocPaths.indexN(1))
855 : DocPaths.INDEX_ALL)),
856 contents.indexLabel, "", "");
857 Content li = HtmlTree.LI(linkContent);
858 return li;
859 }
860
861 /**
862 * Get help file link. If user has provided a help file, then generate a
863 * link to the user given file, which is already copied to current or
864 * destination directory.
865 *
866 * @return a content tree for the link
867 */
868 protected Content getNavLinkHelp() {
869 String helpfile = configuration.helpfile;
870 DocPath helpfilenm;
871 if (helpfile.isEmpty()) {
872 helpfilenm = DocPaths.HELP_DOC;
873 } else {
874 DocFile file = DocFile.createFileForInput(configuration, helpfile);
875 helpfilenm = DocPath.create(file.getName());
876 }
877 Content linkContent = Links.createLink(pathToRoot.resolve(helpfilenm),
878 contents.helpLabel, "", "");
879 Content li = HtmlTree.LI(linkContent);
880 return li;
881 }
882
883 /**
884 * Add gap between navigation bar elements.
885 *
886 * @param liNav the content tree to which the gap will be added
887 */
888 protected void addNavGap(Content liNav) {
889 liNav.addContent(Contents.SPACE);
890 liNav.addContent("|");
891 liNav.addContent(Contents.SPACE);
892 }
893
894 /**
895 * Get table caption.
896 *
897 * @param title the content for the caption
898 * @return a content tree for the caption
899 */
900 public Content getTableCaption(Content title) {
901 Content captionSpan = HtmlTree.SPAN(title);
902 Content space = Contents.SPACE;
903 Content tabSpan = HtmlTree.SPAN(HtmlStyle.tabEnd, space);
904 Content caption = HtmlTree.CAPTION(captionSpan);
905 caption.addContent(tabSpan);
906 return caption;
907 }
908
909 /**
910 * Returns a packagename content.
911 *
912 * @param packageElement the package to check
913 * @return package name content
914 */
915 public Content getPackageName(PackageElement packageElement) {
916 return packageElement == null || packageElement.isUnnamed()
917 ? contents.defaultPackageLabel
918 : getPackageLabel(packageElement.getQualifiedName());
919 }
920
921 /**
922 * Returns a package name label.
923 *
924 * @param packageName the package name
925 * @return the package name content
926 */
927 public Content getPackageLabel(CharSequence packageName) {
928 return new StringContent(packageName);
929 }
981 }
982
983 /**
984 * Return the link to the given package.
985 *
986 * @param packageElement the package to link to.
987 * @param label the label for the link.
988 * @return a content tree for the package link.
989 */
990 public Content getPackageLink(PackageElement packageElement, Content label) {
991 boolean included = packageElement != null && utils.isIncluded(packageElement);
992 if (!included) {
993 for (PackageElement p : configuration.packages) {
994 if (p.equals(packageElement)) {
995 included = true;
996 break;
997 }
998 }
999 }
1000 if (included || packageElement == null) {
1001 return Links.createLink(pathString(packageElement, DocPaths.PACKAGE_SUMMARY),
1002 label);
1003 } else {
1004 DocLink crossPkgLink = getCrossPackageLink(utils.getPackageName(packageElement));
1005 if (crossPkgLink != null) {
1006 return Links.createLink(crossPkgLink, label);
1007 } else {
1008 return label;
1009 }
1010 }
1011 }
1012
1013 /**
1014 * Get Module link.
1015 *
1016 * @param mdle the module being documented
1017 * @param label tag for the link
1018 * @return a content for the module link
1019 */
1020 public Content getModuleLink(ModuleElement mdle, Content label) {
1021 boolean included = utils.isIncluded(mdle);
1022 return (included)
1023 ? Links.createLink(pathToRoot.resolve(DocPaths.moduleSummary(mdle)), label, "", "")
1024 : label;
1025 }
1026
1027 public Content interfaceName(TypeElement typeElement, boolean qual) {
1028 Content name = new StringContent((qual)
1029 ? typeElement.getQualifiedName()
1030 : utils.getSimpleName(typeElement));
1031 return (utils.isInterface(typeElement)) ? HtmlTree.SPAN(HtmlStyle.interfaceName, name) : name;
1032 }
1033
1034 /**
1035 * Add the link to the content tree.
1036 *
1037 * @param typeElement program element typeElement for which the link will be added
1038 * @param label label for the link
1039 * @param htmltree the content tree to which the link will be added
1040 */
1041 public void addSrcLink(Element typeElement, Content label, Content htmltree) {
1042 if (typeElement == null) {
1043 return;
1044 }
1045 TypeElement te = utils.getEnclosingTypeElement(typeElement);
1046 if (te == null) {
1047 // must be a typeElement since in has no containing class.
1048 te = (TypeElement) typeElement;
1049 }
1050 DocPath href = pathToRoot
1051 .resolve(DocPaths.SOURCE_OUTPUT)
1052 .resolve(DocPath.forClass(utils, te));
1053 Content linkContent = Links.createLink(href
1054 .fragment(SourceToHTMLConverter.getAnchorName(utils, typeElement)), label, "", "");
1055 htmltree.addContent(linkContent);
1056 }
1057
1058 /**
1059 * Return the link to the given class.
1060 *
1061 * @param linkInfo the information about the link.
1062 *
1063 * @return the link for the given class.
1064 */
1065 public Content getLink(LinkInfoImpl linkInfo) {
1066 LinkFactoryImpl factory = new LinkFactoryImpl(this);
1067 return factory.getLink(linkInfo);
1068 }
1069
1070 /**
1071 * Return the type parameters for the given class.
1072 *
1073 * @param linkInfo the information about the link.
1098 String className = "";
1099 String packageName = qualifiedClassName == null ? "" : qualifiedClassName;
1100 int periodIndex;
1101 while ((periodIndex = packageName.lastIndexOf('.')) != -1) {
1102 className = packageName.substring(periodIndex + 1, packageName.length()) +
1103 (className.length() > 0 ? "." + className : "");
1104 Content defaultLabel = new StringContent(className);
1105 if (code)
1106 defaultLabel = HtmlTree.CODE(defaultLabel);
1107 packageName = packageName.substring(0, periodIndex);
1108 if (getCrossPackageLink(packageName) != null) {
1109 /*
1110 The package exists in external documentation, so link to the external
1111 class (assuming that it exists). This is definitely a limitation of
1112 the -link option. There are ways to determine if an external package
1113 exists, but no way to determine if the external class exists. We just
1114 have to assume that it does.
1115 */
1116 DocLink link = configuration.extern.getExternalLink(packageName, pathToRoot,
1117 className + ".html", refMemName);
1118 return Links.createLink(link,
1119 (label == null) || label.isEmpty() ? defaultLabel : label,
1120 strong, style,
1121 configuration.getText("doclet.Href_Class_Or_Interface_Title", packageName),
1122 "");
1123 }
1124 }
1125 return null;
1126 }
1127
1128 public boolean isClassLinkable(TypeElement typeElement) {
1129 if (utils.isIncluded(typeElement)) {
1130 return configuration.isGeneratedDoc(typeElement);
1131 }
1132 return configuration.extern.isExternal(typeElement);
1133 }
1134
1135 public DocLink getCrossPackageLink(String pkgName) {
1136 return configuration.extern.getExternalLink(pkgName, pathToRoot,
1137 DocPaths.PACKAGE_SUMMARY.getPath());
1138 }
1282 CharSequence label, boolean strong, boolean isProperty) {
1283 return getDocLink(context, typeElement, element, new StringContent(check(label)), strong, isProperty);
1284 }
1285
1286 CharSequence check(CharSequence s) {
1287 Matcher m = IMPROPER_HTML_CHARS.matcher(s);
1288 if (m.matches()) {
1289 throw new IllegalArgumentException(s.toString());
1290 }
1291 return s;
1292 }
1293
1294 public Content getDocLink(LinkInfoImpl.Kind context, TypeElement typeElement, Element element,
1295 Content label, boolean strong, boolean isProperty) {
1296 if (! (utils.isIncluded(element) || utils.isLinkable(typeElement))) {
1297 return label;
1298 } else if (utils.isExecutableElement(element)) {
1299 ExecutableElement ee = (ExecutableElement)element;
1300 return getLink(new LinkInfoImpl(configuration, context, typeElement)
1301 .label(label)
1302 .where(links.getName(getAnchor(ee, isProperty)))
1303 .strong(strong));
1304 } else if (utils.isVariableElement(element) || utils.isTypeElement(element)) {
1305 return getLink(new LinkInfoImpl(configuration, context, typeElement)
1306 .label(label)
1307 .where(links.getName(element.getSimpleName().toString()))
1308 .strong(strong));
1309 } else {
1310 return label;
1311 }
1312 }
1313
1314 /**
1315 * Return the link for the given member.
1316 *
1317 * @param context the id of the context where the link will be added
1318 * @param typeElement the typeElement that we should link to. This is not
1319 necessarily equal to element.containingClass(). We may be
1320 inheriting comments
1321 * @param element the member being linked to
1322 * @param label the label for the link
1323 * @return the link for the given member
1324 */
1325 public Content getDocLink(LinkInfoImpl.Kind context, TypeElement typeElement, Element element,
1326 Content label) {
1327 if (! (utils.isIncluded(element) || utils.isLinkable(typeElement))) {
1328 return label;
1329 } else if (utils.isExecutableElement(element)) {
1330 ExecutableElement emd = (ExecutableElement) element;
1331 return getLink(new LinkInfoImpl(configuration, context, typeElement)
1332 .label(label)
1333 .where(links.getName(getAnchor(emd))));
1334 } else if (utils.isVariableElement(element) || utils.isTypeElement(element)) {
1335 return getLink(new LinkInfoImpl(configuration, context, typeElement)
1336 .label(label).where(links.getName(element.getSimpleName().toString())));
1337 } else {
1338 return label;
1339 }
1340 }
1341
1342 public String getAnchor(ExecutableElement executableElement) {
1343 return getAnchor(executableElement, false);
1344 }
1345
1346 public String getAnchor(ExecutableElement executableElement, boolean isProperty) {
1347 if (isProperty) {
1348 return executableElement.getSimpleName().toString();
1349 }
1350 String member = anchorName(executableElement);
1351 String erasedSignature = utils.makeSignature(executableElement, true, true);
1352 return member + erasedSignature;
1353 }
1354
1355 public String anchorName(Element member) {
1356 if (member.getKind() == ElementKind.CONSTRUCTOR
1387 String refMemName = ch.getReferencedMemberName(see);
1388
1389 if (refMemName == null && refMem != null) {
1390 refMemName = refMem.toString();
1391 }
1392 if (refClass == null) {
1393 //@see is not referencing an included class
1394 PackageElement refPackage = ch.getReferencedPackage(configuration, see);
1395 if (refPackage != null && utils.isIncluded(refPackage)) {
1396 //@see is referencing an included package
1397 if (label.isEmpty())
1398 label = plainOrCode(isLinkPlain,
1399 new StringContent(refPackage.getQualifiedName()));
1400 return getPackageLink(refPackage, label);
1401 } else {
1402 // @see is not referencing an included class or package. Check for cross links.
1403 Content classCrossLink;
1404 DocLink packageCrossLink = getCrossPackageLink(refClassName);
1405 if (packageCrossLink != null) {
1406 // Package cross link found
1407 return Links.createLink(packageCrossLink,
1408 (label.isEmpty() ? text : label));
1409 } else if ((classCrossLink = getCrossClassLink(refClassName,
1410 refMemName, label, false, "", !isLinkPlain)) != null) {
1411 // Class cross link found (possibly to a member in the class)
1412 return classCrossLink;
1413 } else {
1414 // No cross link found so print warning
1415 messages.warning(ch.getDocTreePath(see),
1416 "doclet.see.class_or_package_not_found",
1417 "@" + tagName,
1418 seetext);
1419 return (label.isEmpty() ? text: label);
1420 }
1421 }
1422 } else if (refMemName == null) {
1423 // Must be a class reference since refClass is not null and refMemName is null.
1424 if (label.isEmpty()) {
1425 /*
1426 * it seems to me this is the right thing to do, but it causes comparator failures.
1427 */
|