001    /*
002     * Copyright 1997-2004 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.taglets.*;
031    
032    import java.io.*;
033    import com.sun.javadoc.*;
034    
035    /**
036     * Writes method documentation in HTML format.
037     *
038     * @author Robert Field
039     * @author Atul M Dambalkar
040     * @author Jamie Ho (rewrite)
041     */
042    public class MethodWriterImpl extends AbstractExecutableMemberWriter
043            implements MethodWriter, MemberSummaryWriter {
044    
045        private boolean printedSummaryHeader = false;
046    
047        /**
048         * Construct a new MethodWriterImpl.
049         *
050         * @param writer the writer for the class that the methods belong to.
051         * @param classDoc the class being documented.
052         */
053        public MethodWriterImpl(SubWriterHolderWriter writer, ClassDoc classDoc) {
054            super(writer, classDoc);
055        }
056    
057        /**
058         * Construct a new MethodWriterImpl.
059         *
060         * @param writer The writer for the class that the methods belong to.
061         */
062        public MethodWriterImpl(SubWriterHolderWriter writer) {
063            super(writer);
064        }
065    
066        /**
067         * Write the methods summary header for the given class.
068         *
069         * @param classDoc the class the summary belongs to.
070         */
071        public void writeMemberSummaryHeader(ClassDoc classDoc) {
072            printedSummaryHeader = true;
073            writer.println();
074            writer.println("<!-- ========== METHOD SUMMARY =========== -->");
075            writer.println();
076            writer.printSummaryHeader(this, classDoc);
077        }
078    
079        /**
080         * Write the methods summary footer for the given class.
081         *
082         * @param classDoc the class the summary belongs to.
083         */
084        public void writeMemberSummaryFooter(ClassDoc classDoc) {
085            writer.printSummaryFooter(this, classDoc);
086        }
087    
088        /**
089         * Write the inherited methods summary header for the given class.
090         *
091         * @param classDoc the class the summary belongs to.
092         */
093        public void writeInheritedMemberSummaryHeader(ClassDoc classDoc) {
094            if(! printedSummaryHeader){
095                //We don't want inherited summary to not be under heading.
096                writeMemberSummaryHeader(classDoc);
097                writeMemberSummaryFooter(classDoc);
098                printedSummaryHeader = true;
099            }
100            writer.printInheritedSummaryHeader(this, classDoc);
101        }
102    
103        /**
104         * {@inheritDoc}
105         */
106        public void writeInheritedMemberSummary(ClassDoc classDoc,
107            ProgramElementDoc method, boolean isFirst, boolean isLast) {
108            writer.printInheritedSummaryMember(this, classDoc, method, isFirst);
109        }
110    
111        /**
112         * Write the inherited methods summary footer for the given class.
113         *
114         * @param classDoc the class the summary belongs to.
115         */
116        public void writeInheritedMemberSummaryFooter(ClassDoc classDoc) {
117            writer.printInheritedSummaryFooter(this, classDoc);        ;
118        }
119    
120        /**
121         * Write the header for the method documentation.
122         *
123         * @param classDoc the class that the methods belong to.
124         */
125        public void writeHeader(ClassDoc classDoc, String header) {
126            writer.println();
127            writer.println("<!-- ============ METHOD DETAIL ========== -->");
128            writer.println();
129            writer.anchor("method_detail");
130            writer.printTableHeadingBackground(header);
131        }
132    
133        /**
134         * Write the method header for the given method.
135         *
136         * @param method the method being documented.
137         * @param isFirst the flag to indicate whether or not the method is the
138         *        first to be documented.
139         */
140        public void writeMethodHeader(MethodDoc method, boolean isFirst) {
141            if (! isFirst) {
142                writer.printMemberHeader();
143            }
144            writer.println();
145            String erasureAnchor;
146            if ((erasureAnchor = getErasureAnchor(method)) != null) {
147                writer.anchor(erasureAnchor);
148            }
149            writer.anchor(method);
150            writer.h3();
151            writer.print(method.name());
152            writer.h3End();
153        }
154    
155        /**
156         * Write the signature for the given method.
157         *
158         * @param method the method being documented.
159         */
160        public void writeSignature(MethodDoc method) {
161            writer.displayLength = 0;
162            writer.pre();
163            writer.writeAnnotationInfo(method);
164            printModifiers(method);
165            writeTypeParameters(method);
166            printReturnType(method);
167            if (configuration().linksource) {
168                writer.printSrcLink(method, method.name());
169            } else {
170                strong(method.name());
171            }
172            writeParameters(method);
173            writeExceptions(method);
174            writer.preEnd();
175            writer.dl();
176        }
177    
178        /**
179         * Write the deprecated output for the given method.
180         *
181         * @param method the method being documented.
182         */
183        public void writeDeprecated(MethodDoc method) {
184            String output = ((TagletOutputImpl)
185                (new DeprecatedTaglet()).getTagletOutput(method,
186                writer.getTagletWriterInstance(false))).toString();
187            if (output != null && output.trim().length() > 0) {
188                writer.print(output);
189            }
190        }
191    
192        /**
193         * Write the comments for the given method.
194         *
195         * @param method the method being documented.
196         */
197        public void writeComments(Type holder, MethodDoc method) {
198            ClassDoc holderClassDoc = holder.asClassDoc();
199            if (method.inlineTags().length > 0) {
200                if (holder.asClassDoc().equals(classdoc) ||
201                    (! (holderClassDoc.isPublic() ||
202                        Util.isLinkable(holderClassDoc, configuration())))) {
203                    writer.dd();
204                    writer.printInlineComment(method);
205                } else {
206                    String classlink = writer.codeText(
207                        writer.getDocLink(LinkInfoImpl.CONTEXT_METHOD_DOC_COPY,
208                            holder.asClassDoc(), method,
209                            holder.asClassDoc().isIncluded() ?
210                                holder.typeName() : holder.qualifiedTypeName(),
211                            false));
212                    writer.dd();
213                    writer.strongText(holder.asClassDoc().isClass()?
214                            "doclet.Description_From_Class":
215                            "doclet.Description_From_Interface",
216                        classlink);
217                    writer.ddEnd();
218                    writer.dd();
219                    writer.printInlineComment(method);
220                }
221            }
222        }
223    
224        /**
225         * Write the tag output for the given method.
226         *
227         * @param method the method being documented.
228         */
229        public void writeTags(MethodDoc method) {
230            writer.printTags(method);
231        }
232    
233        /**
234         * Write the method footer.
235         */
236        public void writeMethodFooter() {
237            writer.ddEnd();
238            writer.dlEnd();
239        }
240    
241        /**
242         * Write the footer for the method documentation.
243         *
244         * @param classDoc the class that the methods belong to.
245         */
246        public void writeFooter(ClassDoc classDoc) {
247            //No footer to write for method documentation
248        }
249    
250        /**
251         * Close the writer.
252         */
253        public void close() throws IOException {
254            writer.close();
255        }
256    
257        public int getMemberKind() {
258            return VisibleMemberMap.METHODS;
259        }
260    
261        public void printSummaryLabel(ClassDoc cd) {
262            writer.strongText("doclet.Method_Summary");
263        }
264    
265        public void printSummaryAnchor(ClassDoc cd) {
266            writer.anchor("method_summary");
267        }
268    
269        public void printInheritedSummaryAnchor(ClassDoc cd) {
270            writer.anchor("methods_inherited_from_class_" +
271                ConfigurationImpl.getInstance().getClassName(cd));
272        }
273    
274        public void printInheritedSummaryLabel(ClassDoc cd) {
275            String classlink = writer.getPreQualifiedClassLink(
276                LinkInfoImpl.CONTEXT_MEMBER, cd, false);
277            writer.strong();
278            String key = cd.isClass()?
279                "doclet.Methods_Inherited_From_Class" :
280                "doclet.Methods_Inherited_From_Interface";
281            writer.printText(key, classlink);
282            writer.strongEnd();
283        }
284    
285        protected void printSummaryType(ProgramElementDoc member) {
286            MethodDoc meth = (MethodDoc)member;
287            printModifierAndType(meth, meth.returnType());
288        }
289    
290        protected static void printOverridden(HtmlDocletWriter writer,
291                Type overriddenType, MethodDoc method) {
292            if(writer.configuration.nocomment){
293                return;
294            }
295            ClassDoc holderClassDoc = overriddenType.asClassDoc();
296            if (! (holderClassDoc.isPublic() ||
297                Util.isLinkable(holderClassDoc, writer.configuration()))) {
298                //This is an implementation detail that should not be documented.
299                return;
300            }
301            if (overriddenType.asClassDoc().isIncluded() && ! method.isIncluded()) {
302                //The class is included but the method is not.  That means that it
303                //is not visible so don't document this.
304                return;
305            }
306            String label = "doclet.Overrides";
307            int context = LinkInfoImpl.CONTEXT_METHOD_OVERRIDES;
308    
309            if (method != null) {
310                if(overriddenType.asClassDoc().isAbstract() && method.isAbstract()){
311                    //Abstract method is implemented from abstract class,
312                    //not overridden
313                    label = "doclet.Specified_By";
314                    context = LinkInfoImpl.CONTEXT_METHOD_SPECIFIED_BY;
315                }
316                String overriddenTypeLink = writer.codeText(
317                    writer.getLink(new LinkInfoImpl(context, overriddenType)));
318                String name = method.name();
319                writer.dt();
320                writer.strongText(label);
321                writer.dd();
322                String methLink = writer.codeText(
323                    writer.getLink(
324                        new LinkInfoImpl(LinkInfoImpl.CONTEXT_MEMBER,
325                            overriddenType.asClassDoc(),
326                            writer.getAnchor(method), name, false)
327                    ));
328                writer.printText("doclet.in_class", methLink, overriddenTypeLink);
329            }
330        }
331    
332        /**
333         * Parse the &lt;Code&gt; tag and return the text.
334         */
335        protected String parseCodeTag(String tag){
336            if(tag == null){
337                return "";
338            }
339    
340            String lc = tag.toLowerCase();
341            int begin = lc.indexOf("<code>");
342            int end = lc.indexOf("</code>");
343            if(begin == -1 || end == -1 || end <= begin){
344                return tag;
345            } else {
346                return tag.substring(begin + 6, end);
347            }
348        }
349    
350        protected static void printImplementsInfo(HtmlDocletWriter writer,
351                MethodDoc method) {
352            if(writer.configuration.nocomment){
353                return;
354            }
355            ImplementedMethods implementedMethodsFinder =
356                new ImplementedMethods(method, writer.configuration);
357            MethodDoc[] implementedMethods = implementedMethodsFinder.build();
358            for (int i = 0; i < implementedMethods.length; i++) {
359                MethodDoc implementedMeth = implementedMethods[i];
360                Type intfac = implementedMethodsFinder.getMethodHolder(implementedMeth);
361                String methlink = "";
362                String intfaclink = writer.codeText(
363                    writer.getLink(new LinkInfoImpl(
364                        LinkInfoImpl.CONTEXT_METHOD_SPECIFIED_BY, intfac)));
365                writer.dt();
366                writer.strongText("doclet.Specified_By");
367                writer.dd();
368                methlink = writer.codeText(writer.getDocLink(
369                    LinkInfoImpl.CONTEXT_MEMBER, implementedMeth,
370                    implementedMeth.name(), false));
371                writer.printText("doclet.in_interface", methlink, intfaclink);
372            }
373    
374        }
375    
376        protected void printReturnType(MethodDoc method) {
377            Type type = method.returnType();
378            if (type != null) {
379                writer.printLink(new LinkInfoImpl(LinkInfoImpl.CONTEXT_RETURN_TYPE,
380                    type));
381                print(' ');
382            }
383        }
384    
385        protected void printNavSummaryLink(ClassDoc cd, boolean link) {
386            if (link) {
387                writer.printHyperLink("", (cd == null)?
388                    "method_summary":
389                    "methods_inherited_from_class_" +
390                    ConfigurationImpl.getInstance().getClassName(cd),
391                    ConfigurationImpl.getInstance().getText("doclet.navMethod"));
392            } else {
393                writer.printText("doclet.navMethod");
394            }
395        }
396    
397        protected void printNavDetailLink(boolean link) {
398            if (link) {
399                writer.printHyperLink("", "method_detail",
400                    ConfigurationImpl.getInstance().getText("doclet.navMethod"));
401            } else {
402                writer.printText("doclet.navMethod");
403            }
404        }
405    }