|
1 /* |
|
2 * Copyright 1997-2005 Sun Microsystems, Inc. All Rights Reserved. |
|
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
|
4 * |
|
5 * This code is free software; you can redistribute it and/or modify it |
|
6 * under the terms of the GNU General Public License version 2 only, as |
|
7 * published by the Free Software Foundation. Sun designates this |
|
8 * particular file as subject to the "Classpath" exception as provided |
|
9 * by Sun in the LICENSE file that accompanied this code. |
|
10 * |
|
11 * This code is distributed in the hope that it will be useful, but WITHOUT |
|
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
|
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
|
14 * version 2 for more details (a copy is included in the LICENSE file that |
|
15 * accompanied this code). |
|
16 * |
|
17 * You should have received a copy of the GNU General Public License version |
|
18 * 2 along with this work; if not, write to the Free Software Foundation, |
|
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. |
|
20 * |
|
21 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, |
|
22 * CA 95054 USA or visit www.sun.com if you need additional information or |
|
23 * have any questions. |
|
24 */ |
|
25 |
|
26 package com.sun.tools.doclets.formats.html; |
|
27 |
|
28 import com.sun.tools.doclets.internal.toolkit.*; |
|
29 import com.sun.tools.doclets.internal.toolkit.util.*; |
|
30 import com.sun.tools.doclets.internal.toolkit.builders.*; |
|
31 import com.sun.javadoc.*; |
|
32 |
|
33 import java.util.*; |
|
34 import com.sun.tools.doclets.internal.toolkit.taglets.*; |
|
35 |
|
36 /** |
|
37 * Generate the Class Information Page. |
|
38 * @see com.sun.javadoc.ClassDoc |
|
39 * @see java.util.Collections |
|
40 * @see java.util.List |
|
41 * @see java.util.ArrayList |
|
42 * @see java.util.HashMap |
|
43 * |
|
44 * @author Atul M Dambalkar |
|
45 * @author Robert Field |
|
46 */ |
|
47 public class ClassWriterImpl extends SubWriterHolderWriter |
|
48 implements ClassWriter { |
|
49 |
|
50 protected ClassDoc classDoc; |
|
51 |
|
52 protected ClassTree classtree; |
|
53 |
|
54 protected ClassDoc prev; |
|
55 |
|
56 protected ClassDoc next; |
|
57 |
|
58 /** |
|
59 * @param classDoc the class being documented. |
|
60 * @param prevClass the previous class that was documented. |
|
61 * @param nextClass the next class being documented. |
|
62 * @param classTree the class tree for the given class. |
|
63 */ |
|
64 public ClassWriterImpl (ClassDoc classDoc, |
|
65 ClassDoc prevClass, ClassDoc nextClass, ClassTree classTree) |
|
66 throws Exception { |
|
67 super(ConfigurationImpl.getInstance(), |
|
68 DirectoryManager.getDirectoryPath(classDoc.containingPackage()), |
|
69 classDoc.name() + ".html", |
|
70 DirectoryManager.getRelativePath(classDoc.containingPackage().name())); |
|
71 this.classDoc = classDoc; |
|
72 configuration.currentcd = classDoc; |
|
73 this.classtree = classTree; |
|
74 this.prev = prevClass; |
|
75 this.next = nextClass; |
|
76 } |
|
77 |
|
78 /** |
|
79 * Print this package link |
|
80 */ |
|
81 protected void navLinkPackage() { |
|
82 navCellStart(); |
|
83 printHyperLink("package-summary.html", "", |
|
84 configuration.getText("doclet.Package"), true, "NavBarFont1"); |
|
85 navCellEnd(); |
|
86 } |
|
87 |
|
88 /** |
|
89 * Print class page indicator |
|
90 */ |
|
91 protected void navLinkClass() { |
|
92 navCellRevStart(); |
|
93 fontStyle("NavBarFont1Rev"); |
|
94 boldText("doclet.Class"); |
|
95 fontEnd(); |
|
96 navCellEnd(); |
|
97 } |
|
98 |
|
99 /** |
|
100 * Print class use link |
|
101 */ |
|
102 protected void navLinkClassUse() { |
|
103 navCellStart(); |
|
104 printHyperLink("class-use/" + filename, "", |
|
105 configuration.getText("doclet.navClassUse"), true, "NavBarFont1"); |
|
106 navCellEnd(); |
|
107 } |
|
108 |
|
109 /** |
|
110 * Print previous package link |
|
111 */ |
|
112 protected void navLinkPrevious() { |
|
113 if (prev == null) { |
|
114 printText("doclet.Prev_Class"); |
|
115 } else { |
|
116 printLink(new LinkInfoImpl(LinkInfoImpl.CONTEXT_CLASS, prev, "", |
|
117 configuration.getText("doclet.Prev_Class"), true)); |
|
118 } |
|
119 } |
|
120 |
|
121 /** |
|
122 * Print next package link |
|
123 */ |
|
124 protected void navLinkNext() { |
|
125 if (next == null) { |
|
126 printText("doclet.Next_Class"); |
|
127 } else { |
|
128 printLink(new LinkInfoImpl(LinkInfoImpl.CONTEXT_CLASS, next, "", |
|
129 configuration.getText("doclet.Next_Class"), true)); |
|
130 } |
|
131 } |
|
132 |
|
133 /** |
|
134 * {@inheritDoc} |
|
135 */ |
|
136 public void writeHeader(String header) { |
|
137 String pkgname = (classDoc.containingPackage() != null)? |
|
138 classDoc.containingPackage().name(): ""; |
|
139 String clname = classDoc.name(); |
|
140 printHtmlHeader(clname, |
|
141 configuration.metakeywords.getMetaKeywords(classDoc), true); |
|
142 printTop(); |
|
143 navLinks(true); |
|
144 hr(); |
|
145 println("<!-- ======== START OF CLASS DATA ======== -->"); |
|
146 h2(); |
|
147 if (pkgname.length() > 0) { |
|
148 font("-1"); print(pkgname); fontEnd(); br(); |
|
149 } |
|
150 LinkInfoImpl linkInfo = new LinkInfoImpl( LinkInfoImpl.CONTEXT_CLASS_HEADER, |
|
151 classDoc, false); |
|
152 //Let's not link to ourselves in the header. |
|
153 linkInfo.linkToSelf = false; |
|
154 print(header + getTypeParameterLinks(linkInfo)); |
|
155 h2End(); |
|
156 } |
|
157 |
|
158 /** |
|
159 * {@inheritDoc} |
|
160 */ |
|
161 public void writeFooter() { |
|
162 println("<!-- ========= END OF CLASS DATA ========= -->"); |
|
163 hr(); |
|
164 navLinks(false); |
|
165 printBottom(); |
|
166 printBodyHtmlEnd(); |
|
167 } |
|
168 |
|
169 /** |
|
170 * {@inheritDoc} |
|
171 */ |
|
172 public void writeClassSignature(String modifiers) { |
|
173 boolean isInterface = classDoc.isInterface(); |
|
174 dl(); |
|
175 dt(); |
|
176 preNoNewLine(); |
|
177 writeAnnotationInfo(classDoc); |
|
178 print(modifiers); |
|
179 LinkInfoImpl linkInfo = new LinkInfoImpl( |
|
180 LinkInfoImpl.CONTEXT_CLASS_SIGNATURE, classDoc, false); |
|
181 //Let's not link to ourselves in the signature. |
|
182 linkInfo.linkToSelf = false; |
|
183 String name = classDoc.name() + |
|
184 getTypeParameterLinks(linkInfo); |
|
185 if (configuration().linksource) { |
|
186 printSrcLink(classDoc, name); |
|
187 } else { |
|
188 bold(name); |
|
189 } |
|
190 if (!isInterface) { |
|
191 Type superclass = Util.getFirstVisibleSuperClass(classDoc, |
|
192 configuration()); |
|
193 if (superclass != null) { |
|
194 dt(); |
|
195 print("extends "); |
|
196 printLink(new LinkInfoImpl( |
|
197 LinkInfoImpl.CONTEXT_CLASS_SIGNATURE_PARENT_NAME, |
|
198 superclass)); |
|
199 } |
|
200 } |
|
201 Type[] implIntfacs = classDoc.interfaceTypes(); |
|
202 if (implIntfacs != null && implIntfacs.length > 0) { |
|
203 int counter = 0; |
|
204 for (int i = 0; i < implIntfacs.length; i++) { |
|
205 ClassDoc classDoc = implIntfacs[i].asClassDoc(); |
|
206 if (! (classDoc.isPublic() || |
|
207 Util.isLinkable(classDoc, configuration()))) { |
|
208 continue; |
|
209 } |
|
210 if (counter == 0) { |
|
211 dt(); |
|
212 print(isInterface? "extends " : "implements "); |
|
213 } else { |
|
214 print(", "); |
|
215 } |
|
216 printLink(new LinkInfoImpl( |
|
217 LinkInfoImpl.CONTEXT_CLASS_SIGNATURE_PARENT_NAME, |
|
218 implIntfacs[i])); |
|
219 counter++; |
|
220 } |
|
221 } |
|
222 dlEnd(); |
|
223 preEnd(); |
|
224 p(); |
|
225 } |
|
226 |
|
227 /** |
|
228 * {@inheritDoc} |
|
229 */ |
|
230 public void writeClassDescription() { |
|
231 if(!configuration.nocomment) { |
|
232 // generate documentation for the class. |
|
233 if (classDoc.inlineTags().length > 0) { |
|
234 printInlineComment(classDoc); |
|
235 p(); |
|
236 } |
|
237 } |
|
238 } |
|
239 |
|
240 /** |
|
241 * {@inheritDoc} |
|
242 */ |
|
243 public void writeClassTagInfo() { |
|
244 if(!configuration.nocomment) { |
|
245 // Print Information about all the tags here |
|
246 printTags(classDoc); |
|
247 hr(); |
|
248 p(); |
|
249 } else { |
|
250 hr(); |
|
251 } |
|
252 } |
|
253 |
|
254 /** |
|
255 * {@inheritDoc} |
|
256 */ |
|
257 public void writeClassDeprecationInfo() { |
|
258 hr(); |
|
259 Tag[] deprs = classDoc.tags("deprecated"); |
|
260 if (Util.isDeprecated(classDoc)) { |
|
261 boldText("doclet.Deprecated"); |
|
262 if (deprs.length > 0) { |
|
263 Tag[] commentTags = deprs[0].inlineTags(); |
|
264 if (commentTags.length > 0) { |
|
265 space(); |
|
266 printInlineDeprecatedComment(classDoc, deprs[0]); |
|
267 } |
|
268 } |
|
269 p(); |
|
270 } |
|
271 } |
|
272 |
|
273 /** |
|
274 * Generate the indent and get the line image for the class tree. |
|
275 * For user accessibility, the image includes the alt attribute |
|
276 * "extended by". (This method is not intended for a class |
|
277 * implementing an interface, where "implemented by" would be required.) |
|
278 * |
|
279 * indent integer indicating the number of spaces to indent |
|
280 */ |
|
281 private void writeStep(int indent) { |
|
282 print(spaces(4 * indent - 2)); |
|
283 print("<IMG SRC=\"" + relativepathNoSlash + "/resources/inherit.gif\" " + |
|
284 "ALT=\"" + configuration.getText("doclet.extended_by") + " \">"); |
|
285 } |
|
286 |
|
287 /** |
|
288 * Print the class hierarchy tree for the given class. |
|
289 * @param type the class to print the hierarchy for. |
|
290 * @return return the amount that should be indented in |
|
291 * the next level of the tree. |
|
292 */ |
|
293 private int writeTreeForClassHelper(Type type) { |
|
294 Type sup = Util.getFirstVisibleSuperClass( |
|
295 type instanceof ClassDoc ? (ClassDoc) type : type.asClassDoc(), |
|
296 configuration()); |
|
297 int indent = 0; |
|
298 if (sup != null) { |
|
299 indent = writeTreeForClassHelper(sup); |
|
300 writeStep(indent); |
|
301 } |
|
302 |
|
303 if (type.equals(classDoc)) { |
|
304 String typeParameters = getTypeParameterLinks( |
|
305 new LinkInfoImpl( |
|
306 LinkInfoImpl.CONTEXT_TREE, |
|
307 classDoc, false)); |
|
308 if (configuration.shouldExcludeQualifier( |
|
309 classDoc.containingPackage().name())) { |
|
310 bold(type.asClassDoc().name() + typeParameters); |
|
311 } else { |
|
312 bold(type.asClassDoc().qualifiedName() + typeParameters); |
|
313 } |
|
314 } else { |
|
315 print(getLink(new LinkInfoImpl(LinkInfoImpl.CONTEXT_CLASS_TREE_PARENT, |
|
316 type instanceof ClassDoc ? (ClassDoc) type : type, |
|
317 configuration.getClassName(type.asClassDoc()), false))); |
|
318 } |
|
319 println(); |
|
320 return indent + 1; |
|
321 } |
|
322 |
|
323 /** |
|
324 * Print the class hierarchy tree for this class only. |
|
325 */ |
|
326 public void writeClassTree() { |
|
327 if (! classDoc.isClass()) { |
|
328 return; |
|
329 } |
|
330 pre(); |
|
331 writeTreeForClassHelper(classDoc); |
|
332 preEnd(); |
|
333 } |
|
334 |
|
335 /** |
|
336 * Write the type parameter information. |
|
337 */ |
|
338 public void writeTypeParamInfo() { |
|
339 if (classDoc.typeParamTags().length > 0) { |
|
340 dl(); |
|
341 dt(); |
|
342 TagletOutput output = (new ParamTaglet()).getTagletOutput(classDoc, |
|
343 getTagletWriterInstance(false)); |
|
344 print(output.toString()); |
|
345 dlEnd(); |
|
346 } |
|
347 } |
|
348 |
|
349 /** |
|
350 * {@inheritDoc} |
|
351 */ |
|
352 public void writeSubClassInfo() { |
|
353 if (classDoc.isClass()) { |
|
354 if (classDoc.qualifiedName().equals("java.lang.Object") || |
|
355 classDoc.qualifiedName().equals("org.omg.CORBA.Object")) { |
|
356 return; // Don't generate the list, too huge |
|
357 } |
|
358 List subclasses = classtree.subs(classDoc, false); |
|
359 if (subclasses.size() > 0) { |
|
360 dl(); |
|
361 dt(); |
|
362 boldText("doclet.Subclasses"); |
|
363 writeClassLinks(LinkInfoImpl.CONTEXT_SUBCLASSES, |
|
364 subclasses); |
|
365 } |
|
366 } |
|
367 } |
|
368 |
|
369 /** |
|
370 * {@inheritDoc} |
|
371 */ |
|
372 public void writeSubInterfacesInfo() { |
|
373 if (classDoc.isInterface()) { |
|
374 List subInterfaces = classtree.allSubs(classDoc, false); |
|
375 if (subInterfaces.size() > 0) { |
|
376 dl(); |
|
377 dt(); |
|
378 boldText("doclet.Subinterfaces"); |
|
379 writeClassLinks(LinkInfoImpl.CONTEXT_SUBINTERFACES, |
|
380 subInterfaces); |
|
381 } |
|
382 } |
|
383 } |
|
384 |
|
385 /** |
|
386 * If this is the interface which are the classes, that implement this? |
|
387 */ |
|
388 public void writeInterfaceUsageInfo () { |
|
389 if (! classDoc.isInterface()) { |
|
390 return; |
|
391 } |
|
392 if (classDoc.qualifiedName().equals("java.lang.Cloneable") || |
|
393 classDoc.qualifiedName().equals("java.io.Serializable")) { |
|
394 return; // Don't generate the list, too big |
|
395 } |
|
396 List implcl = classtree.implementingclasses(classDoc); |
|
397 if (implcl.size() > 0) { |
|
398 dl(); |
|
399 dt(); |
|
400 boldText("doclet.Implementing_Classes"); |
|
401 writeClassLinks(LinkInfoImpl.CONTEXT_IMPLEMENTED_CLASSES, |
|
402 implcl); |
|
403 } |
|
404 } |
|
405 |
|
406 /** |
|
407 * {@inheritDoc} |
|
408 */ |
|
409 public void writeImplementedInterfacesInfo() { |
|
410 //NOTE: we really should be using ClassDoc.interfaceTypes() here, but |
|
411 // it doesn't walk up the tree like we want it to. |
|
412 List interfaceArray = Util.getAllInterfaces(classDoc, configuration); |
|
413 if (classDoc.isClass() && interfaceArray.size() > 0) { |
|
414 dl(); |
|
415 dt(); |
|
416 boldText("doclet.All_Implemented_Interfaces"); |
|
417 writeClassLinks(LinkInfoImpl.CONTEXT_IMPLEMENTED_INTERFACES, |
|
418 interfaceArray); |
|
419 } |
|
420 } |
|
421 |
|
422 /** |
|
423 * {@inheritDoc} |
|
424 */ |
|
425 public void writeSuperInterfacesInfo() { |
|
426 //NOTE: we really should be using ClassDoc.interfaceTypes() here, but |
|
427 // it doesn't walk up the tree like we want it to. |
|
428 List interfaceArray = Util.getAllInterfaces(classDoc, configuration); |
|
429 if (classDoc.isInterface() && interfaceArray.size() > 0) { |
|
430 dl(); |
|
431 dt(); |
|
432 boldText("doclet.All_Superinterfaces"); |
|
433 writeClassLinks(LinkInfoImpl.CONTEXT_SUPER_INTERFACES, |
|
434 interfaceArray); |
|
435 } |
|
436 } |
|
437 |
|
438 /** |
|
439 * Generate links to the given classes. |
|
440 */ |
|
441 private void writeClassLinks(int context, List list) { |
|
442 Object[] typeList = list.toArray(); |
|
443 //Sort the list to be printed. |
|
444 print(' '); |
|
445 dd(); |
|
446 for (int i = 0; i < list.size(); i++) { |
|
447 if (i > 0) { |
|
448 print(", "); |
|
449 } |
|
450 if (typeList[i] instanceof ClassDoc) { |
|
451 printLink(new LinkInfoImpl(context, (ClassDoc)(typeList[i]))); |
|
452 |
|
453 } else { |
|
454 printLink(new LinkInfoImpl(context, (Type)(typeList[i]))); |
|
455 } |
|
456 } |
|
457 ddEnd(); |
|
458 dlEnd(); |
|
459 } |
|
460 |
|
461 protected void navLinkTree() { |
|
462 navCellStart(); |
|
463 printHyperLink("package-tree.html", "", |
|
464 configuration.getText("doclet.Tree"), true, "NavBarFont1"); |
|
465 navCellEnd(); |
|
466 } |
|
467 |
|
468 protected void printSummaryDetailLinks() { |
|
469 try { |
|
470 tr(); |
|
471 tdVAlignClass("top", "NavBarCell3"); |
|
472 font("-2"); |
|
473 print(" "); |
|
474 navSummaryLinks(); |
|
475 fontEnd(); |
|
476 tdEnd(); |
|
477 tdVAlignClass("top", "NavBarCell3"); |
|
478 font("-2"); |
|
479 navDetailLinks(); |
|
480 fontEnd(); |
|
481 tdEnd(); |
|
482 trEnd(); |
|
483 } catch (Exception e) { |
|
484 e.printStackTrace(); |
|
485 throw new DocletAbortException(); |
|
486 } |
|
487 } |
|
488 |
|
489 protected void navSummaryLinks() throws Exception { |
|
490 printText("doclet.Summary"); |
|
491 space(); |
|
492 MemberSummaryBuilder memberSummaryBuilder = (MemberSummaryBuilder) |
|
493 configuration.getBuilderFactory().getMemberSummaryBuilder(this); |
|
494 String[] navLinkLabels = new String[] { |
|
495 "doclet.navNested", "doclet.navEnum", "doclet.navField", "doclet.navConstructor", |
|
496 "doclet.navMethod" |
|
497 }; |
|
498 for (int i = 0; i < navLinkLabels.length; i++ ) { |
|
499 if (i == VisibleMemberMap.ENUM_CONSTANTS && ! classDoc.isEnum()) { |
|
500 continue; |
|
501 } |
|
502 if (i == VisibleMemberMap.CONSTRUCTORS && classDoc.isEnum()) { |
|
503 continue; |
|
504 } |
|
505 AbstractMemberWriter writer = |
|
506 ((AbstractMemberWriter) memberSummaryBuilder. |
|
507 getMemberSummaryWriter(i)); |
|
508 if (writer == null) { |
|
509 printText(navLinkLabels[i]); |
|
510 } else { |
|
511 writer.navSummaryLink( |
|
512 memberSummaryBuilder.members(i), |
|
513 memberSummaryBuilder.getVisibleMemberMap(i)); |
|
514 } |
|
515 if (i < navLinkLabels.length-1) { |
|
516 navGap(); |
|
517 } |
|
518 } |
|
519 } |
|
520 |
|
521 /** |
|
522 * Method navDetailLinks |
|
523 * |
|
524 * @throws Exception |
|
525 * |
|
526 */ |
|
527 protected void navDetailLinks() throws Exception { |
|
528 printText("doclet.Detail"); |
|
529 space(); |
|
530 MemberSummaryBuilder memberSummaryBuilder = (MemberSummaryBuilder) |
|
531 configuration.getBuilderFactory().getMemberSummaryBuilder(this); |
|
532 String[] navLinkLabels = new String[] { |
|
533 "doclet.navNested", "doclet.navEnum", "doclet.navField", "doclet.navConstructor", |
|
534 "doclet.navMethod" |
|
535 }; |
|
536 for (int i = 1; i < navLinkLabels.length; i++ ) { |
|
537 AbstractMemberWriter writer = |
|
538 ((AbstractMemberWriter) memberSummaryBuilder. |
|
539 getMemberSummaryWriter(i)); |
|
540 if (i == VisibleMemberMap.ENUM_CONSTANTS && ! classDoc.isEnum()) { |
|
541 continue; |
|
542 } |
|
543 if (i == VisibleMemberMap.CONSTRUCTORS && classDoc.isEnum()) { |
|
544 continue; |
|
545 } |
|
546 if (writer == null) { |
|
547 printText(navLinkLabels[i]); |
|
548 } else { |
|
549 writer.navDetailLink(memberSummaryBuilder.members(i)); |
|
550 } |
|
551 if (i < navLinkLabels.length - 1) { |
|
552 navGap(); |
|
553 } |
|
554 } |
|
555 } |
|
556 |
|
557 protected void navGap() { |
|
558 space(); |
|
559 print('|'); |
|
560 space(); |
|
561 } |
|
562 |
|
563 /** |
|
564 * If this is an inner class or interface, write the enclosing class or |
|
565 * interface. |
|
566 */ |
|
567 public void writeNestedClassInfo() { |
|
568 ClassDoc outerClass = classDoc.containingClass(); |
|
569 if (outerClass != null) { |
|
570 dl(); |
|
571 dt(); |
|
572 if (outerClass.isInterface()) { |
|
573 boldText("doclet.Enclosing_Interface"); |
|
574 } else { |
|
575 boldText("doclet.Enclosing_Class"); |
|
576 } |
|
577 dd(); |
|
578 printLink(new LinkInfoImpl(LinkInfoImpl.CONTEXT_CLASS, outerClass, |
|
579 false)); |
|
580 ddEnd(); |
|
581 dlEnd(); |
|
582 } |
|
583 } |
|
584 |
|
585 /** |
|
586 * Return the classDoc being documented. |
|
587 * |
|
588 * @return the classDoc being documented. |
|
589 */ |
|
590 public ClassDoc getClassDoc() { |
|
591 return classDoc; |
|
592 } |
|
593 |
|
594 /** |
|
595 * {@inheritDoc} |
|
596 */ |
|
597 public void completeMemberSummaryBuild() { |
|
598 p(); |
|
599 } |
|
600 } |