Fri, 05 Oct 2012 14:13:47 -0700
7132631: The help-doc.html generates an invalid link to constant-values.html
Reviewed-by: jjg
1 /*
2 * Copyright (c) 1997, 2011, 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.util.*;
30 import com.sun.javadoc.*;
31 import com.sun.tools.doclets.internal.toolkit.*;
32 import com.sun.tools.doclets.internal.toolkit.util.*;
33 import com.sun.tools.doclets.internal.toolkit.builders.*;
34 import com.sun.tools.doclets.internal.toolkit.taglets.*;
35 import com.sun.tools.doclets.formats.html.markup.*;
37 /**
38 * Generate the Class Information Page.
39 * @see com.sun.javadoc.ClassDoc
40 * @see java.util.Collections
41 * @see java.util.List
42 * @see java.util.ArrayList
43 * @see java.util.HashMap
44 *
45 * @author Atul M Dambalkar
46 * @author Robert Field
47 * @author Bhavesh Patel (Modified)
48 */
49 public class ClassWriterImpl extends SubWriterHolderWriter
50 implements ClassWriter {
52 protected ClassDoc classDoc;
54 protected ClassTree classtree;
56 protected ClassDoc prev;
58 protected ClassDoc next;
60 /**
61 * @param classDoc the class being documented.
62 * @param prevClass the previous class that was documented.
63 * @param nextClass the next class being documented.
64 * @param classTree the class tree for the given class.
65 */
66 public ClassWriterImpl (ClassDoc classDoc,
67 ClassDoc prevClass, ClassDoc nextClass, ClassTree classTree)
68 throws Exception {
69 super(ConfigurationImpl.getInstance(),
70 DirectoryManager.getDirectoryPath(classDoc.containingPackage()),
71 classDoc.name() + ".html",
72 DirectoryManager.getRelativePath(classDoc.containingPackage().name()));
73 this.classDoc = classDoc;
74 configuration.currentcd = classDoc;
75 this.classtree = classTree;
76 this.prev = prevClass;
77 this.next = nextClass;
78 }
80 /**
81 * Get this package link.
82 *
83 * @return a content tree for the package link
84 */
85 protected Content getNavLinkPackage() {
86 Content linkContent = getHyperLink("package-summary.html", "",
87 packageLabel);
88 Content li = HtmlTree.LI(linkContent);
89 return li;
90 }
92 /**
93 * Get the class link.
94 *
95 * @return a content tree for the class link
96 */
97 protected Content getNavLinkClass() {
98 Content li = HtmlTree.LI(HtmlStyle.navBarCell1Rev, classLabel);
99 return li;
100 }
102 /**
103 * Get the class use link.
104 *
105 * @return a content tree for the class use link
106 */
107 protected Content getNavLinkClassUse() {
108 Content linkContent = getHyperLink("class-use/" + filename, "", useLabel);
109 Content li = HtmlTree.LI(linkContent);
110 return li;
111 }
113 /**
114 * Get link to previous class.
115 *
116 * @return a content tree for the previous class link
117 */
118 public Content getNavLinkPrevious() {
119 Content li;
120 if (prev != null) {
121 Content prevLink = new RawHtml(getLink(new LinkInfoImpl(
122 LinkInfoImpl.CONTEXT_CLASS, prev, "",
123 configuration.getText("doclet.Prev_Class"), true)));
124 li = HtmlTree.LI(prevLink);
125 }
126 else
127 li = HtmlTree.LI(prevclassLabel);
128 return li;
129 }
131 /**
132 * Get link to next class.
133 *
134 * @return a content tree for the next class link
135 */
136 public Content getNavLinkNext() {
137 Content li;
138 if (next != null) {
139 Content nextLink = new RawHtml(getLink(new LinkInfoImpl(
140 LinkInfoImpl.CONTEXT_CLASS, next, "",
141 configuration.getText("doclet.Next_Class"), true)));
142 li = HtmlTree.LI(nextLink);
143 }
144 else
145 li = HtmlTree.LI(nextclassLabel);
146 return li;
147 }
149 /**
150 * {@inheritDoc}
151 */
152 public Content getHeader(String header) {
153 String pkgname = (classDoc.containingPackage() != null)?
154 classDoc.containingPackage().name(): "";
155 String clname = classDoc.name();
156 Content bodyTree = getBody(true, getWindowTitle(clname));
157 addTop(bodyTree);
158 addNavLinks(true, bodyTree);
159 bodyTree.addContent(HtmlConstants.START_OF_CLASS_DATA);
160 HtmlTree div = new HtmlTree(HtmlTag.DIV);
161 div.addStyle(HtmlStyle.header);
162 if (pkgname.length() > 0) {
163 Content pkgNameContent = new StringContent(pkgname);
164 Content pkgNameDiv = HtmlTree.DIV(HtmlStyle.subTitle, pkgNameContent);
165 div.addContent(pkgNameDiv);
166 }
167 LinkInfoImpl linkInfo = new LinkInfoImpl( LinkInfoImpl.CONTEXT_CLASS_HEADER,
168 classDoc, false);
169 //Let's not link to ourselves in the header.
170 linkInfo.linkToSelf = false;
171 Content headerContent = new StringContent(header);
172 Content heading = HtmlTree.HEADING(HtmlConstants.CLASS_PAGE_HEADING, true,
173 HtmlStyle.title, headerContent);
174 heading.addContent(new RawHtml(getTypeParameterLinks(linkInfo)));
175 div.addContent(heading);
176 bodyTree.addContent(div);
177 return bodyTree;
178 }
180 /**
181 * {@inheritDoc}
182 */
183 public Content getClassContentHeader() {
184 return getContentHeader();
185 }
187 /**
188 * {@inheritDoc}
189 */
190 public void addFooter(Content contentTree) {
191 contentTree.addContent(HtmlConstants.END_OF_CLASS_DATA);
192 addNavLinks(false, contentTree);
193 addBottom(contentTree);
194 }
196 /**
197 * {@inheritDoc}
198 */
199 public void printDocument(Content contentTree) {
200 printHtmlDocument(configuration.metakeywords.getMetaKeywords(classDoc),
201 true, contentTree);
202 }
204 /**
205 * {@inheritDoc}
206 */
207 public Content getClassInfoTreeHeader() {
208 return getMemberTreeHeader();
209 }
211 /**
212 * {@inheritDoc}
213 */
214 public Content getClassInfo(Content classInfoTree) {
215 return getMemberTree(HtmlStyle.description, classInfoTree);
216 }
218 /**
219 * {@inheritDoc}
220 */
221 public void addClassSignature(String modifiers, Content classInfoTree) {
222 boolean isInterface = classDoc.isInterface();
223 classInfoTree.addContent(new HtmlTree(HtmlTag.BR));
224 Content pre = new HtmlTree(HtmlTag.PRE);
225 addAnnotationInfo(classDoc, pre);
226 pre.addContent(modifiers);
227 LinkInfoImpl linkInfo = new LinkInfoImpl(
228 LinkInfoImpl.CONTEXT_CLASS_SIGNATURE, classDoc, false);
229 //Let's not link to ourselves in the signature.
230 linkInfo.linkToSelf = false;
231 Content className = new StringContent(classDoc.name());
232 Content parameterLinks = new RawHtml(getTypeParameterLinks(linkInfo));
233 if (configuration().linksource) {
234 addSrcLink(classDoc, className, pre);
235 pre.addContent(parameterLinks);
236 } else {
237 Content span = HtmlTree.SPAN(HtmlStyle.strong, className);
238 span.addContent(parameterLinks);
239 pre.addContent(span);
240 }
241 if (!isInterface) {
242 Type superclass = Util.getFirstVisibleSuperClass(classDoc,
243 configuration());
244 if (superclass != null) {
245 pre.addContent(DocletConstants.NL);
246 pre.addContent("extends ");
247 Content link = new RawHtml(getLink(new LinkInfoImpl(
248 LinkInfoImpl.CONTEXT_CLASS_SIGNATURE_PARENT_NAME,
249 superclass)));
250 pre.addContent(link);
251 }
252 }
253 Type[] implIntfacs = classDoc.interfaceTypes();
254 if (implIntfacs != null && implIntfacs.length > 0) {
255 int counter = 0;
256 for (int i = 0; i < implIntfacs.length; i++) {
257 ClassDoc classDoc = implIntfacs[i].asClassDoc();
258 if (! (classDoc.isPublic() ||
259 Util.isLinkable(classDoc, configuration()))) {
260 continue;
261 }
262 if (counter == 0) {
263 pre.addContent(DocletConstants.NL);
264 pre.addContent(isInterface? "extends " : "implements ");
265 } else {
266 pre.addContent(", ");
267 }
268 Content link = new RawHtml(getLink(new LinkInfoImpl(
269 LinkInfoImpl.CONTEXT_CLASS_SIGNATURE_PARENT_NAME,
270 implIntfacs[i])));
271 pre.addContent(link);
272 counter++;
273 }
274 }
275 classInfoTree.addContent(pre);
276 }
278 /**
279 * {@inheritDoc}
280 */
281 public void addClassDescription(Content classInfoTree) {
282 if(!configuration.nocomment) {
283 // generate documentation for the class.
284 if (classDoc.inlineTags().length > 0) {
285 addInlineComment(classDoc, classInfoTree);
286 }
287 }
288 }
290 /**
291 * {@inheritDoc}
292 */
293 public void addClassTagInfo(Content classInfoTree) {
294 if(!configuration.nocomment) {
295 // Print Information about all the tags here
296 addTagsInfo(classDoc, classInfoTree);
297 }
298 }
300 /**
301 * Get the class hierarchy tree for the given class.
302 *
303 * @param type the class to print the hierarchy for
304 * @return a content tree for class inheritence
305 */
306 private Content getClassInheritenceTree(Type type) {
307 Type sup;
308 HtmlTree classTreeUl = new HtmlTree(HtmlTag.UL);
309 classTreeUl.addStyle(HtmlStyle.inheritance);
310 Content liTree = null;
311 do {
312 sup = Util.getFirstVisibleSuperClass(
313 type instanceof ClassDoc ? (ClassDoc) type : type.asClassDoc(),
314 configuration());
315 if (sup != null) {
316 HtmlTree ul = new HtmlTree(HtmlTag.UL);
317 ul.addStyle(HtmlStyle.inheritance);
318 ul.addContent(getTreeForClassHelper(type));
319 if (liTree != null)
320 ul.addContent(liTree);
321 Content li = HtmlTree.LI(ul);
322 liTree = li;
323 type = sup;
324 }
325 else
326 classTreeUl.addContent(getTreeForClassHelper(type));
327 }
328 while (sup != null);
329 if (liTree != null)
330 classTreeUl.addContent(liTree);
331 return classTreeUl;
332 }
334 /**
335 * Get the class helper tree for the given class.
336 *
337 * @param type the class to print the helper for
338 * @return a content tree for class helper
339 */
340 private Content getTreeForClassHelper(Type type) {
341 Content li = new HtmlTree(HtmlTag.LI);
342 if (type.equals(classDoc)) {
343 String typeParameters = getTypeParameterLinks(
344 new LinkInfoImpl(LinkInfoImpl.CONTEXT_TREE,
345 classDoc, false));
346 if (configuration.shouldExcludeQualifier(
347 classDoc.containingPackage().name())) {
348 li.addContent(type.asClassDoc().name());
349 li.addContent(new RawHtml(typeParameters));
350 } else {
351 li.addContent(type.asClassDoc().qualifiedName());
352 li.addContent(new RawHtml(typeParameters));
353 }
354 } else {
355 Content link = new RawHtml(getLink(new LinkInfoImpl(
356 LinkInfoImpl.CONTEXT_CLASS_TREE_PARENT,
357 type instanceof ClassDoc ? (ClassDoc) type : type,
358 configuration.getClassName(type.asClassDoc()), false)));
359 li.addContent(link);
360 }
361 return li;
362 }
364 /**
365 * {@inheritDoc}
366 */
367 public void addClassTree(Content classContentTree) {
368 if (!classDoc.isClass()) {
369 return;
370 }
371 classContentTree.addContent(getClassInheritenceTree(classDoc));
372 }
374 /**
375 * {@inheritDoc}
376 */
377 public void addTypeParamInfo(Content classInfoTree) {
378 if (classDoc.typeParamTags().length > 0) {
379 TagletOutput output = (new ParamTaglet()).getTagletOutput(classDoc,
380 getTagletWriterInstance(false));
381 Content typeParam = new RawHtml(output.toString());
382 Content dl = HtmlTree.DL(typeParam);
383 classInfoTree.addContent(dl);
384 }
385 }
387 /**
388 * {@inheritDoc}
389 */
390 public void addSubClassInfo(Content classInfoTree) {
391 if (classDoc.isClass()) {
392 if (classDoc.qualifiedName().equals("java.lang.Object") ||
393 classDoc.qualifiedName().equals("org.omg.CORBA.Object")) {
394 return; // Don't generate the list, too huge
395 }
396 List<ClassDoc> subclasses = classtree.subs(classDoc, false);
397 if (subclasses.size() > 0) {
398 Content label = getResource(
399 "doclet.Subclasses");
400 Content dt = HtmlTree.DT(label);
401 Content dl = HtmlTree.DL(dt);
402 dl.addContent(getClassLinks(LinkInfoImpl.CONTEXT_SUBCLASSES,
403 subclasses));
404 classInfoTree.addContent(dl);
405 }
406 }
407 }
409 /**
410 * {@inheritDoc}
411 */
412 public void addSubInterfacesInfo(Content classInfoTree) {
413 if (classDoc.isInterface()) {
414 List<ClassDoc> subInterfaces = classtree.allSubs(classDoc, false);
415 if (subInterfaces.size() > 0) {
416 Content label = getResource(
417 "doclet.Subinterfaces");
418 Content dt = HtmlTree.DT(label);
419 Content dl = HtmlTree.DL(dt);
420 dl.addContent(getClassLinks(LinkInfoImpl.CONTEXT_SUBINTERFACES,
421 subInterfaces));
422 classInfoTree.addContent(dl);
423 }
424 }
425 }
427 /**
428 * {@inheritDoc}
429 */
430 public void addInterfaceUsageInfo (Content classInfoTree) {
431 if (! classDoc.isInterface()) {
432 return;
433 }
434 if (classDoc.qualifiedName().equals("java.lang.Cloneable") ||
435 classDoc.qualifiedName().equals("java.io.Serializable")) {
436 return; // Don't generate the list, too big
437 }
438 List<ClassDoc> implcl = classtree.implementingclasses(classDoc);
439 if (implcl.size() > 0) {
440 Content label = getResource(
441 "doclet.Implementing_Classes");
442 Content dt = HtmlTree.DT(label);
443 Content dl = HtmlTree.DL(dt);
444 dl.addContent(getClassLinks(LinkInfoImpl.CONTEXT_IMPLEMENTED_CLASSES,
445 implcl));
446 classInfoTree.addContent(dl);
447 }
448 }
450 /**
451 * {@inheritDoc}
452 */
453 public void addImplementedInterfacesInfo(Content classInfoTree) {
454 //NOTE: we really should be using ClassDoc.interfaceTypes() here, but
455 // it doesn't walk up the tree like we want it to.
456 List<Type> interfaceArray = Util.getAllInterfaces(classDoc, configuration);
457 if (classDoc.isClass() && interfaceArray.size() > 0) {
458 Content label = getResource(
459 "doclet.All_Implemented_Interfaces");
460 Content dt = HtmlTree.DT(label);
461 Content dl = HtmlTree.DL(dt);
462 dl.addContent(getClassLinks(LinkInfoImpl.CONTEXT_IMPLEMENTED_INTERFACES,
463 interfaceArray));
464 classInfoTree.addContent(dl);
465 }
466 }
468 /**
469 * {@inheritDoc}
470 */
471 public void addSuperInterfacesInfo(Content classInfoTree) {
472 //NOTE: we really should be using ClassDoc.interfaceTypes() here, but
473 // it doesn't walk up the tree like we want it to.
474 List<Type> interfaceArray = Util.getAllInterfaces(classDoc, configuration);
475 if (classDoc.isInterface() && interfaceArray.size() > 0) {
476 Content label = getResource(
477 "doclet.All_Superinterfaces");
478 Content dt = HtmlTree.DT(label);
479 Content dl = HtmlTree.DL(dt);
480 dl.addContent(getClassLinks(LinkInfoImpl.CONTEXT_SUPER_INTERFACES,
481 interfaceArray));
482 classInfoTree.addContent(dl);
483 }
484 }
486 /**
487 * {@inheritDoc}
488 */
489 public void addNestedClassInfo(Content classInfoTree) {
490 ClassDoc outerClass = classDoc.containingClass();
491 if (outerClass != null) {
492 Content label;
493 if (outerClass.isInterface()) {
494 label = getResource(
495 "doclet.Enclosing_Interface");
496 } else {
497 label = getResource(
498 "doclet.Enclosing_Class");
499 }
500 Content dt = HtmlTree.DT(label);
501 Content dl = HtmlTree.DL(dt);
502 Content dd = new HtmlTree(HtmlTag.DD);
503 dd.addContent(new RawHtml(getLink(new LinkInfoImpl(LinkInfoImpl.CONTEXT_CLASS, outerClass,
504 false))));
505 dl.addContent(dd);
506 classInfoTree.addContent(dl);
507 }
508 }
510 /**
511 * {@inheritDoc}
512 */
513 public void addClassDeprecationInfo(Content classInfoTree) {
514 Content hr = new HtmlTree(HtmlTag.HR);
515 classInfoTree.addContent(hr);
516 Tag[] deprs = classDoc.tags("deprecated");
517 if (Util.isDeprecated(classDoc)) {
518 Content strong = HtmlTree.STRONG(deprecatedPhrase);
519 Content div = HtmlTree.DIV(HtmlStyle.block, strong);
520 if (deprs.length > 0) {
521 Tag[] commentTags = deprs[0].inlineTags();
522 if (commentTags.length > 0) {
523 div.addContent(getSpace());
524 addInlineDeprecatedComment(classDoc, deprs[0], div);
525 }
526 }
527 classInfoTree.addContent(div);
528 }
529 }
531 /**
532 * Get links to the given classes.
533 *
534 * @param context the id of the context where the link will be printed
535 * @param list the list of classes
536 * @return a content tree for the class list
537 */
538 private Content getClassLinks(int context, List<?> list) {
539 Object[] typeList = list.toArray();
540 Content dd = new HtmlTree(HtmlTag.DD);
541 for (int i = 0; i < list.size(); i++) {
542 if (i > 0) {
543 Content separator = new StringContent(", ");
544 dd.addContent(separator);
545 }
546 if (typeList[i] instanceof ClassDoc) {
547 Content link = new RawHtml(getLink(
548 new LinkInfoImpl(context, (ClassDoc)(typeList[i]))));
549 dd.addContent(link);
550 } else {
551 Content link = new RawHtml(getLink(
552 new LinkInfoImpl(context, (Type)(typeList[i]))));
553 dd.addContent(link);
554 }
555 }
556 return dd;
557 }
559 /**
560 * {@inheritDoc}
561 */
562 protected Content getNavLinkTree() {
563 Content treeLinkContent = getHyperLink("package-tree.html",
564 "", treeLabel, "", "");
565 Content li = HtmlTree.LI(treeLinkContent);
566 return li;
567 }
569 /**
570 * Add summary details to the navigation bar.
571 *
572 * @param subDiv the content tree to which the summary detail links will be added
573 */
574 protected void addSummaryDetailLinks(Content subDiv) {
575 try {
576 Content div = HtmlTree.DIV(getNavSummaryLinks());
577 div.addContent(getNavDetailLinks());
578 subDiv.addContent(div);
579 } catch (Exception e) {
580 e.printStackTrace();
581 throw new DocletAbortException();
582 }
583 }
585 /**
586 * Get summary links for navigation bar.
587 *
588 * @return the content tree for the navigation summary links
589 */
590 protected Content getNavSummaryLinks() throws Exception {
591 Content li = HtmlTree.LI(summaryLabel);
592 li.addContent(getSpace());
593 Content ulNav = HtmlTree.UL(HtmlStyle.subNavList, li);
594 MemberSummaryBuilder memberSummaryBuilder = (MemberSummaryBuilder)
595 configuration.getBuilderFactory().getMemberSummaryBuilder(this);
596 String[] navLinkLabels = new String[] {
597 "doclet.navNested", "doclet.navEnum", "doclet.navField", "doclet.navConstructor",
598 "doclet.navMethod"
599 };
600 for (int i = 0; i < navLinkLabels.length; i++ ) {
601 Content liNav = new HtmlTree(HtmlTag.LI);
602 if (i == VisibleMemberMap.ENUM_CONSTANTS && ! classDoc.isEnum()) {
603 continue;
604 }
605 if (i == VisibleMemberMap.CONSTRUCTORS && classDoc.isEnum()) {
606 continue;
607 }
608 AbstractMemberWriter writer =
609 ((AbstractMemberWriter) memberSummaryBuilder.
610 getMemberSummaryWriter(i));
611 if (writer == null) {
612 liNav.addContent(getResource(navLinkLabels[i]));
613 } else {
614 writer.addNavSummaryLink(
615 memberSummaryBuilder.members(i),
616 memberSummaryBuilder.getVisibleMemberMap(i), liNav);
617 }
618 if (i < navLinkLabels.length-1) {
619 addNavGap(liNav);
620 }
621 ulNav.addContent(liNav);
622 }
623 return ulNav;
624 }
626 /**
627 * Get detail links for the navigation bar.
628 *
629 * @return the content tree for the detail links
630 */
631 protected Content getNavDetailLinks() throws Exception {
632 Content li = HtmlTree.LI(detailLabel);
633 li.addContent(getSpace());
634 Content ulNav = HtmlTree.UL(HtmlStyle.subNavList, li);
635 MemberSummaryBuilder memberSummaryBuilder = (MemberSummaryBuilder)
636 configuration.getBuilderFactory().getMemberSummaryBuilder(this);
637 String[] navLinkLabels = new String[] {
638 "doclet.navNested", "doclet.navEnum", "doclet.navField", "doclet.navConstructor",
639 "doclet.navMethod"
640 };
641 for (int i = 1; i < navLinkLabels.length; i++ ) {
642 Content liNav = new HtmlTree(HtmlTag.LI);
643 AbstractMemberWriter writer =
644 ((AbstractMemberWriter) memberSummaryBuilder.
645 getMemberSummaryWriter(i));
646 if (i == VisibleMemberMap.ENUM_CONSTANTS && ! classDoc.isEnum()) {
647 continue;
648 }
649 if (i == VisibleMemberMap.CONSTRUCTORS && classDoc.isEnum()) {
650 continue;
651 }
652 if (writer == null) {
653 liNav.addContent(getResource(navLinkLabels[i]));
654 } else {
655 writer.addNavDetailLink(memberSummaryBuilder.members(i), liNav);
656 }
657 if (i < navLinkLabels.length - 1) {
658 addNavGap(liNav);
659 }
660 ulNav.addContent(liNav);
661 }
662 return ulNav;
663 }
665 /**
666 * Add gap between navigation bar elements.
667 *
668 * @param liNav the content tree to which the gap will be added
669 */
670 protected void addNavGap(Content liNav) {
671 liNav.addContent(getSpace());
672 liNav.addContent("|");
673 liNav.addContent(getSpace());
674 }
676 /**
677 * Return the classDoc being documented.
678 *
679 * @return the classDoc being documented.
680 */
681 public ClassDoc getClassDoc() {
682 return classDoc;
683 }
684 }