001    /*
002     * Copyright 1997-2005 Sun Microsystems, Inc.  All Rights Reserved.
003     * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
004     *
005     * This code is free software; you can redistribute it and/or modify it
006     * under the terms of the GNU General Public License version 2 only, as
007     * published by the Free Software Foundation.  Sun designates this
008     * particular file as subject to the "Classpath" exception as provided
009     * by Sun in the LICENSE file that accompanied this code.
010     *
011     * This code is distributed in the hope that it will be useful, but WITHOUT
012     * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
013     * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
014     * version 2 for more details (a copy is included in the LICENSE file that
015     * accompanied this code).
016     *
017     * You should have received a copy of the GNU General Public License version
018     * 2 along with this work; if not, write to the Free Software Foundation,
019     * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
020     *
021     * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
022     * CA 95054 USA or visit www.sun.com if you need additional information or
023     * have any questions.
024     */
025    
026    package com.sun.tools.doclets.formats.html;
027    
028    import com.sun.tools.doclets.internal.toolkit.*;
029    import com.sun.tools.doclets.internal.toolkit.util.*;
030    import com.sun.tools.doclets.internal.toolkit.builders.*;
031    import com.sun.javadoc.*;
032    
033    import java.util.*;
034    import com.sun.tools.doclets.internal.toolkit.taglets.*;
035    
036    /**
037     * Generate the Class Information Page.
038     * @see com.sun.javadoc.ClassDoc
039     * @see java.util.Collections
040     * @see java.util.List
041     * @see java.util.ArrayList
042     * @see java.util.HashMap
043     *
044     * @author Atul M Dambalkar
045     * @author Robert Field
046     */
047    public class ClassWriterImpl extends SubWriterHolderWriter
048            implements ClassWriter {
049    
050        protected ClassDoc classDoc;
051    
052        protected ClassTree classtree;
053    
054        protected ClassDoc prev;
055    
056        protected ClassDoc next;
057    
058        /**
059         * @param classDoc the class being documented.
060         * @param prevClass the previous class that was documented.
061         * @param nextClass the next class being documented.
062         * @param classTree the class tree for the given class.
063         */
064        public ClassWriterImpl (ClassDoc classDoc,
065                ClassDoc prevClass, ClassDoc nextClass, ClassTree classTree)
066        throws Exception {
067            super(ConfigurationImpl.getInstance(),
068                  DirectoryManager.getDirectoryPath(classDoc.containingPackage()),
069                  classDoc.name() + ".html",
070                  DirectoryManager.getRelativePath(classDoc.containingPackage().name()));
071            this.classDoc = classDoc;
072            configuration.currentcd = classDoc;
073            this.classtree = classTree;
074            this.prev = prevClass;
075            this.next = nextClass;
076        }
077    
078        /**
079         * Print this package link
080         */
081        protected void navLinkPackage() {
082            navCellStart();
083            printHyperLink("package-summary.html", "",
084                configuration.getText("doclet.Package"), true, "NavBarFont1");
085            navCellEnd();
086        }
087    
088        /**
089         * Print class page indicator
090         */
091        protected void navLinkClass() {
092            navCellRevStart();
093            fontStyle("NavBarFont1Rev");
094            strongText("doclet.Class");
095            fontEnd();
096            navCellEnd();
097        }
098    
099        /**
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                strong(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                strongText("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                    strong(type.asClassDoc().name() + typeParameters);
311                } else {
312                    strong(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<ClassDoc> subclasses = classtree.subs(classDoc, false);
359                if (subclasses.size() > 0) {
360                    dl();
361                    dt();
362                    strongText("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<ClassDoc> subInterfaces = classtree.allSubs(classDoc, false);
375                if (subInterfaces.size() > 0) {
376                    dl();
377                    dt();
378                    strongText("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<ClassDoc> implcl = classtree.implementingclasses(classDoc);
397            if (implcl.size() > 0) {
398                dl();
399                dt();
400                strongText("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<Type> interfaceArray = Util.getAllInterfaces(classDoc, configuration);
413            if (classDoc.isClass() && interfaceArray.size() > 0) {
414                dl();
415                dt();
416                strongText("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<Type> interfaceArray = Util.getAllInterfaces(classDoc, configuration);
429            if (classDoc.isInterface() && interfaceArray.size() > 0) {
430                dl();
431                dt();
432                strongText("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                    strongText("doclet.Enclosing_Interface");
574                } else {
575                    strongText("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    }