ClassWriterImpl.java revision 3233:b5d08bc0d224
1/*
2 * Copyright (c) 1997, 2016, 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 */
25
26package jdk.javadoc.internal.doclets.formats.html;
27
28import java.io.IOException;
29import java.util.*;
30
31import javax.lang.model.element.AnnotationMirror;
32import javax.lang.model.element.Element;
33import javax.lang.model.element.PackageElement;
34import javax.lang.model.element.TypeElement;
35import javax.lang.model.type.TypeMirror;
36import javax.lang.model.util.SimpleElementVisitor8;
37
38import com.sun.source.doctree.DocTree;
39import com.sun.tools.javac.util.DefinedBy;
40import com.sun.tools.javac.util.DefinedBy.Api;
41import jdk.javadoc.internal.doclets.formats.html.markup.HtmlConstants;
42import jdk.javadoc.internal.doclets.formats.html.markup.HtmlStyle;
43import jdk.javadoc.internal.doclets.formats.html.markup.HtmlTag;
44import jdk.javadoc.internal.doclets.formats.html.markup.HtmlTree;
45import jdk.javadoc.internal.doclets.formats.html.markup.StringContent;
46import jdk.javadoc.internal.doclets.toolkit.ClassWriter;
47import jdk.javadoc.internal.doclets.toolkit.Content;
48import jdk.javadoc.internal.doclets.toolkit.builders.MemberSummaryBuilder;
49import jdk.javadoc.internal.doclets.toolkit.taglets.ParamTaglet;
50import jdk.javadoc.internal.doclets.toolkit.util.ClassTree;
51import jdk.javadoc.internal.doclets.toolkit.util.CommentHelper;
52import jdk.javadoc.internal.doclets.toolkit.util.DocPath;
53import jdk.javadoc.internal.doclets.toolkit.util.DocPaths;
54import jdk.javadoc.internal.doclets.toolkit.util.DocletAbortException;
55import jdk.javadoc.internal.doclets.toolkit.util.DocletConstants;
56import jdk.javadoc.internal.doclets.toolkit.util.VisibleMemberMap;
57import jdk.javadoc.internal.doclets.toolkit.util.VisibleMemberMap.Kind;
58
59/**
60 * Generate the Class Information Page.
61 *
62 *  <p><b>This is NOT part of any supported API.
63 *  If you write code that depends on this, you do so at your own risk.
64 *  This code and its internal interfaces are subject to change or
65 *  deletion without notice.</b>
66 *
67 * @see javax.lang.model.element.TypeElement
68 * @see java.util.Collections
69 * @see java.util.List
70 * @see java.util.ArrayList
71 * @see java.util.HashMap
72 *
73 * @author Atul M Dambalkar
74 * @author Robert Field
75 * @author Bhavesh Patel (Modified)
76 */
77public class ClassWriterImpl extends SubWriterHolderWriter implements ClassWriter {
78
79    protected final TypeElement typeElement;
80
81    protected final ClassTree classtree;
82
83    protected final TypeElement prev;
84
85    protected final TypeElement next;
86
87    /**
88     * @param configuration the configuration data for the doclet
89     * @param typeElement the class being documented.
90     * @param prevClass the previous class that was documented.
91     * @param nextClass the next class being documented.
92     * @param classTree the class tree for the given class.
93     * @throws java.io.IOException
94     */
95    public ClassWriterImpl(ConfigurationImpl configuration, TypeElement typeElement,
96            TypeElement prevClass, TypeElement nextClass, ClassTree classTree)
97            throws IOException {
98        super(configuration, DocPath.forClass(configuration.utils, typeElement));
99        this.typeElement = typeElement;
100        configuration.currentTypeElement = typeElement;
101        this.classtree = classTree;
102        this.prev = prevClass;
103        this.next = nextClass;
104    }
105
106    /**
107     * Get this package link.
108     *
109     * @return a content tree for the package link
110     */
111    @Override
112    protected Content getNavLinkPackage() {
113        Content linkContent = getHyperLink(DocPaths.PACKAGE_SUMMARY,
114                packageLabel);
115        Content li = HtmlTree.LI(linkContent);
116        return li;
117    }
118
119    /**
120     * Get the class link.
121     *
122     * @return a content tree for the class link
123     */
124    @Override
125    protected Content getNavLinkClass() {
126        Content li = HtmlTree.LI(HtmlStyle.navBarCell1Rev, classLabel);
127        return li;
128    }
129
130    /**
131     * Get the class use link.
132     *
133     * @return a content tree for the class use link
134     */
135    @Override
136    protected Content getNavLinkClassUse() {
137        Content linkContent = getHyperLink(DocPaths.CLASS_USE.resolve(filename), useLabel);
138        Content li = HtmlTree.LI(linkContent);
139        return li;
140    }
141
142    /**
143     * Get link to previous class.
144     *
145     * @return a content tree for the previous class link
146     */
147    @Override
148    public Content getNavLinkPrevious() {
149        Content li;
150        if (prev != null) {
151            Content prevLink = getLink(new LinkInfoImpl(configuration,
152                    LinkInfoImpl.Kind.CLASS, prev)
153                    .label(prevclassLabel).strong(true));
154            li = HtmlTree.LI(prevLink);
155        }
156        else
157            li = HtmlTree.LI(prevclassLabel);
158        return li;
159    }
160
161    /**
162     * Get link to next class.
163     *
164     * @return a content tree for the next class link
165     */
166    @Override
167    public Content getNavLinkNext() {
168        Content li;
169        if (next != null) {
170            Content nextLink = getLink(new LinkInfoImpl(configuration,
171                    LinkInfoImpl.Kind.CLASS, next)
172                    .label(nextclassLabel).strong(true));
173            li = HtmlTree.LI(nextLink);
174        }
175        else
176            li = HtmlTree.LI(nextclassLabel);
177        return li;
178    }
179
180    /**
181     * {@inheritDoc}
182     */
183    @Override
184    public Content getHeader(String header) {
185        HtmlTree bodyTree = getBody(true, getWindowTitle(utils.getSimpleName(typeElement)));
186        HtmlTree htmlTree = (configuration.allowTag(HtmlTag.HEADER))
187                ? HtmlTree.HEADER()
188                : bodyTree;
189        addTop(htmlTree);
190        addNavLinks(true, htmlTree);
191        if (configuration.allowTag(HtmlTag.HEADER)) {
192            bodyTree.addContent(htmlTree);
193        }
194        bodyTree.addContent(HtmlConstants.START_OF_CLASS_DATA);
195        HtmlTree div = new HtmlTree(HtmlTag.DIV);
196        div.addStyle(HtmlStyle.header);
197        PackageElement pkg = utils.containingPackage(typeElement);
198        if (!pkg.isUnnamed()) {
199            Content pkgNameContent = new StringContent(utils.getPackageName(pkg));
200            Content pkgNameDiv = HtmlTree.DIV(HtmlStyle.subTitle, pkgNameContent);
201            div.addContent(pkgNameDiv);
202        }
203        LinkInfoImpl linkInfo = new LinkInfoImpl(configuration,
204                LinkInfoImpl.Kind.CLASS_HEADER, typeElement);
205        //Let's not link to ourselves in the header.
206        linkInfo.linkToSelf = false;
207        Content headerContent = new StringContent(header);
208        Content heading = HtmlTree.HEADING(HtmlConstants.CLASS_PAGE_HEADING, true,
209                HtmlStyle.title, headerContent);
210        heading.addContent(getTypeParameterLinks(linkInfo));
211        div.addContent(heading);
212        if (configuration.allowTag(HtmlTag.MAIN)) {
213            mainTree.addContent(div);
214        } else {
215            bodyTree.addContent(div);
216        }
217        return bodyTree;
218    }
219
220    /**
221     * {@inheritDoc}
222     */
223    @Override
224    public Content getClassContentHeader() {
225        return getContentHeader();
226    }
227
228    /**
229     * {@inheritDoc}
230     */
231    @Override
232    public void addFooter(Content contentTree) {
233        contentTree.addContent(HtmlConstants.END_OF_CLASS_DATA);
234        Content htmlTree = (configuration.allowTag(HtmlTag.FOOTER))
235                ? HtmlTree.FOOTER()
236                : contentTree;
237        addNavLinks(false, htmlTree);
238        addBottom(htmlTree);
239        if (configuration.allowTag(HtmlTag.FOOTER)) {
240            contentTree.addContent(htmlTree);
241        }
242    }
243
244    /**
245     * {@inheritDoc}
246     */
247    @Override
248    public void printDocument(Content contentTree) throws IOException {
249        printHtmlDocument(configuration.metakeywords.getMetaKeywords(typeElement),
250                true, contentTree);
251    }
252
253    /**
254     * {@inheritDoc}
255     */
256    @Override
257    public Content getClassInfoTreeHeader() {
258        return getMemberTreeHeader();
259    }
260
261    /**
262     * {@inheritDoc}
263     */
264    @Override
265    public Content getClassInfo(Content classInfoTree) {
266        return getMemberTree(HtmlStyle.description, classInfoTree);
267    }
268
269    /**
270     * {@inheritDoc}
271     */
272    @Override
273    public void addClassSignature(String modifiers, Content classInfoTree) {
274        classInfoTree.addContent(new HtmlTree(HtmlTag.BR));
275        Content pre = new HtmlTree(HtmlTag.PRE);
276        addAnnotationInfo(typeElement, pre);
277        pre.addContent(modifiers);
278        LinkInfoImpl linkInfo = new LinkInfoImpl(configuration,
279                LinkInfoImpl.Kind.CLASS_SIGNATURE, typeElement);
280        //Let's not link to ourselves in the signature.
281        linkInfo.linkToSelf = false;
282        Content className = new StringContent(utils.getSimpleName(typeElement));
283        Content parameterLinks = getTypeParameterLinks(linkInfo);
284        if (configuration.linksource) {
285            addSrcLink(typeElement, className, pre);
286            pre.addContent(parameterLinks);
287        } else {
288            Content span = HtmlTree.SPAN(HtmlStyle.typeNameLabel, className);
289            span.addContent(parameterLinks);
290            pre.addContent(span);
291        }
292        if (!utils.isInterface(typeElement)) {
293            TypeMirror superclass = utils.getFirstVisibleSuperClass(typeElement);
294            if (superclass != null) {
295                pre.addContent(DocletConstants.NL);
296                pre.addContent("extends ");
297                Content link = getLink(new LinkInfoImpl(configuration,
298                        LinkInfoImpl.Kind.CLASS_SIGNATURE_PARENT_NAME,
299                        superclass));
300                pre.addContent(link);
301            }
302        }
303        List<? extends TypeMirror> interfaces = typeElement.getInterfaces();
304        if (!interfaces.isEmpty()) {
305            boolean isFirst = true;
306            for (TypeMirror type : interfaces) {
307                TypeElement tDoc = utils.asTypeElement(type);
308                if (!(utils.isPublic(tDoc) || utils.isLinkable(tDoc))) {
309                    continue;
310                }
311                if (isFirst) {
312                    pre.addContent(DocletConstants.NL);
313                    pre.addContent(utils.isInterface(typeElement) ? "extends " : "implements ");
314                    isFirst = false;
315                } else {
316                    pre.addContent(", ");
317                }
318                Content link = getLink(new LinkInfoImpl(configuration,
319                                                        LinkInfoImpl.Kind.CLASS_SIGNATURE_PARENT_NAME,
320                                                        type));
321                pre.addContent(link);
322            }
323        }
324        classInfoTree.addContent(pre);
325    }
326
327    /**
328     * {@inheritDoc}
329     */
330    @Override
331    public void addClassDescription(Content classInfoTree) {
332        if(!configuration.nocomment) {
333            // generate documentation for the class.
334            if (!utils.getBody(typeElement).isEmpty()) {
335                addInlineComment(typeElement, classInfoTree);
336            }
337        }
338    }
339
340    /**
341     * {@inheritDoc}
342     */
343    @Override
344    public void addClassTagInfo(Content classInfoTree) {
345        if(!configuration.nocomment) {
346            // Print Information about all the tags here
347            addTagsInfo(typeElement, classInfoTree);
348        }
349    }
350
351    /**
352     * Get the class hierarchy tree for the given class.
353     *
354     * @param type the class to print the hierarchy for
355     * @return a content tree for class inheritence
356     */
357    private Content getClassInheritenceTree(TypeMirror type) {
358        TypeMirror sup;
359        HtmlTree classTreeUl = new HtmlTree(HtmlTag.UL);
360        classTreeUl.addStyle(HtmlStyle.inheritance);
361        Content liTree = null;
362        do {
363            sup = utils.getFirstVisibleSuperClass(type);
364            if (sup != null) {
365                HtmlTree ul = new HtmlTree(HtmlTag.UL);
366                ul.addStyle(HtmlStyle.inheritance);
367                ul.addContent(getTreeForClassHelper(type));
368                if (liTree != null)
369                    ul.addContent(liTree);
370                Content li = HtmlTree.LI(ul);
371                liTree = li;
372                type = sup;
373            } else
374                classTreeUl.addContent(getTreeForClassHelper(type));
375        } while (sup != null);
376        if (liTree != null)
377            classTreeUl.addContent(liTree);
378        return classTreeUl;
379    }
380
381    /**
382     * Get the class helper tree for the given class.
383     *
384     * @param type the class to print the helper for
385     * @return a content tree for class helper
386     */
387    private Content getTreeForClassHelper(TypeMirror type) {
388        Content li = new HtmlTree(HtmlTag.LI);
389        if (type.equals(typeElement.asType())) {
390            Content typeParameters = getTypeParameterLinks(
391                    new LinkInfoImpl(configuration, LinkInfoImpl.Kind.TREE,
392                    typeElement));
393            if (configuration.shouldExcludeQualifier(utils.containingPackage(typeElement).toString())) {
394                li.addContent(utils.asTypeElement(type).getSimpleName().toString());
395                li.addContent(typeParameters);
396            } else {
397                li.addContent(utils.asTypeElement(type).getQualifiedName().toString());
398                li.addContent(typeParameters);
399            }
400        } else {
401            Content link = getLink(new LinkInfoImpl(configuration,
402                    LinkInfoImpl.Kind.CLASS_TREE_PARENT, type)
403                    .label(configuration.getClassName(utils.asTypeElement(type))));
404            li.addContent(link);
405        }
406        return li;
407    }
408
409    /**
410     * {@inheritDoc}
411     */
412    @Override
413    public void addClassTree(Content classContentTree) {
414        if (!utils.isClass(typeElement)) {
415            return;
416        }
417        classContentTree.addContent(getClassInheritenceTree(typeElement.asType()));
418    }
419
420    /**
421     * {@inheritDoc}
422     */
423    @Override
424    public void addTypeParamInfo(Content classInfoTree) {
425        if (!utils.getTypeParamTrees(typeElement).isEmpty()) {
426            Content typeParam = (new ParamTaglet()).getTagletOutput(typeElement,
427                    getTagletWriterInstance(false));
428            Content dl = HtmlTree.DL(typeParam);
429            classInfoTree.addContent(dl);
430        }
431    }
432
433    /**
434     * {@inheritDoc}
435     */
436    @Override
437    public void addSubClassInfo(Content classInfoTree) {
438        if (utils.isClass(typeElement)) {
439            if (typeElement.getQualifiedName().toString().equals("java.lang.Object") ||
440                    typeElement.getQualifiedName().toString().equals("org.omg.CORBA.Object")) {
441                return;    // Don't generate the list, too huge
442            }
443            Set<TypeElement> subclasses = classtree.directSubClasses(typeElement, false);
444            if (!subclasses.isEmpty()) {
445                Content label = getResource(
446                        "doclet.Subclasses");
447                Content dt = HtmlTree.DT(label);
448                Content dl = HtmlTree.DL(dt);
449                dl.addContent(getClassLinks(LinkInfoImpl.Kind.SUBCLASSES,
450                        subclasses));
451                classInfoTree.addContent(dl);
452            }
453        }
454    }
455
456    /**
457     * {@inheritDoc}
458     */
459    @Override
460    public void addSubInterfacesInfo(Content classInfoTree) {
461        if (utils.isInterface(typeElement)) {
462            Set<TypeElement> subInterfaces = classtree.allSubClasses(typeElement, false);
463            if (!subInterfaces.isEmpty()) {
464                Content label = getResource(
465                        "doclet.Subinterfaces");
466                Content dt = HtmlTree.DT(label);
467                Content dl = HtmlTree.DL(dt);
468                dl.addContent(getClassLinks(LinkInfoImpl.Kind.SUBINTERFACES,
469                        subInterfaces));
470                classInfoTree.addContent(dl);
471            }
472        }
473    }
474
475    /**
476     * {@inheritDoc}
477     */
478    @Override
479    public void addInterfaceUsageInfo (Content classInfoTree) {
480        if (!utils.isInterface(typeElement)) {
481            return;
482        }
483        if (typeElement.getQualifiedName().toString().equals("java.lang.Cloneable") ||
484                typeElement.getQualifiedName().toString().equals("java.io.Serializable")) {
485            return;   // Don't generate the list, too big
486        }
487        Set<TypeElement> implcl = classtree.implementingClasses(typeElement);
488        if (!implcl.isEmpty()) {
489            Content label = getResource(
490                    "doclet.Implementing_Classes");
491            Content dt = HtmlTree.DT(label);
492            Content dl = HtmlTree.DL(dt);
493            dl.addContent(getClassLinks(LinkInfoImpl.Kind.IMPLEMENTED_CLASSES,
494                    implcl));
495            classInfoTree.addContent(dl);
496        }
497    }
498
499    /**
500     * {@inheritDoc}
501     */
502    @Override
503    public void addImplementedInterfacesInfo(Content classInfoTree) {
504        SortedSet<TypeMirror> interfaces = new TreeSet<>(utils.makeTypeMirrorClassUseComparator());
505        interfaces.addAll(utils.getAllInterfaces(typeElement));
506        if (utils.isClass(typeElement) && !interfaces.isEmpty()) {
507            Content label = getResource(
508                    "doclet.All_Implemented_Interfaces");
509            Content dt = HtmlTree.DT(label);
510            Content dl = HtmlTree.DL(dt);
511            dl.addContent(getClassLinks(LinkInfoImpl.Kind.IMPLEMENTED_INTERFACES, interfaces));
512            classInfoTree.addContent(dl);
513        }
514    }
515
516    /**
517     * {@inheritDoc}
518     */
519    @Override
520    public void addSuperInterfacesInfo(Content classInfoTree) {
521        SortedSet<TypeMirror> interfaces =
522                new TreeSet<>(utils.makeTypeMirrorIndexUseComparator());
523        interfaces.addAll(utils.getAllInterfaces(typeElement));
524
525        if (utils.isInterface(typeElement) && !interfaces.isEmpty()) {
526            Content label = getResource("doclet.All_Superinterfaces");
527            Content dt = HtmlTree.DT(label);
528            Content dl = HtmlTree.DL(dt);
529            dl.addContent(getClassLinks(LinkInfoImpl.Kind.SUPER_INTERFACES, interfaces));
530            classInfoTree.addContent(dl);
531        }
532    }
533
534    /**
535     * {@inheritDoc}
536     */
537    @Override
538    public void addNestedClassInfo(final Content classInfoTree) {
539        Element outerClass = typeElement.getEnclosingElement();
540        if (outerClass == null)
541            return;
542        new SimpleElementVisitor8<Void, Void>() {
543            @Override @DefinedBy(Api.LANGUAGE_MODEL)
544            public Void visitType(TypeElement e, Void p) {
545                String label = utils.isInterface(e)
546                        ? "doclet.Enclosing_Interface"
547                        : "doclet.Enclosing_Class";
548                Content dt = HtmlTree.DT(getResource(label));
549                Content dl = HtmlTree.DL(dt);
550                Content dd = new HtmlTree(HtmlTag.DD);
551                dd.addContent(getLink(new LinkInfoImpl(configuration,
552                        LinkInfoImpl.Kind.CLASS, e)));
553                dl.addContent(dd);
554                classInfoTree.addContent(dl);
555                return null;
556            }
557        }.visit(outerClass);
558    }
559
560    /**
561     * {@inheritDoc}
562     */
563    @Override
564    public void addFunctionalInterfaceInfo (Content classInfoTree) {
565        if (isFunctionalInterface()) {
566            Content dt = HtmlTree.DT(getResource("doclet.Functional_Interface"));
567            Content dl = HtmlTree.DL(dt);
568            Content dd = new HtmlTree(HtmlTag.DD);
569            dd.addContent(getResource("doclet.Functional_Interface_Message"));
570            dl.addContent(dd);
571            classInfoTree.addContent(dl);
572        }
573    }
574
575    public boolean isFunctionalInterface() {
576        List<? extends AnnotationMirror> annotationMirrors = ((Element) typeElement).getAnnotationMirrors();
577        for (AnnotationMirror anno : annotationMirrors) {
578            if (utils.isFunctionalInterface(anno)) {
579                return true;
580            }
581        }
582        return false;
583    }
584
585
586    /**
587     * {@inheritDoc}
588     */
589    @Override
590    public void addClassDeprecationInfo(Content classInfoTree) {
591        Content hr = new HtmlTree(HtmlTag.HR);
592        classInfoTree.addContent(hr);
593        List<? extends DocTree> deprs = utils.getBlockTags(typeElement, DocTree.Kind.DEPRECATED);
594        if (utils.isDeprecated(typeElement)) {
595            Content deprLabel = HtmlTree.SPAN(HtmlStyle.deprecatedLabel, deprecatedPhrase);
596            Content div = HtmlTree.DIV(HtmlStyle.block, deprLabel);
597            if (!deprs.isEmpty()) {
598                CommentHelper ch = utils.getCommentHelper(typeElement);
599                DocTree dt = deprs.get(0);
600                List<? extends DocTree> commentTags = ch.getBody(configuration, dt);
601                if (!commentTags.isEmpty()) {
602                    div.addContent(getSpace());
603                    addInlineDeprecatedComment(typeElement, deprs.get(0), div);
604                }
605            }
606            classInfoTree.addContent(div);
607        }
608    }
609
610    /**
611     * Get links to the given classes.
612     *
613     * @param context the id of the context where the link will be printed
614     * @param list the list of classes
615     * @return a content tree for the class list
616     */
617    private Content getClassLinks(LinkInfoImpl.Kind context, Collection<?> list) {
618        Content dd = new HtmlTree(HtmlTag.DD);
619        boolean isFirst = true;
620        for (Object type : list) {
621            if (!isFirst) {
622                Content separator = new StringContent(", ");
623                dd.addContent(separator);
624            } else {
625                isFirst = false;
626            }
627            // TODO: should we simply split this method up to avoid instanceof ?
628            if (type instanceof TypeElement) {
629                Content link = getLink(
630                        new LinkInfoImpl(configuration, context, (TypeElement)(type)));
631                dd.addContent(link);
632            } else {
633                Content link = getLink(
634                        new LinkInfoImpl(configuration, context, ((TypeMirror)type)));
635                dd.addContent(link);
636            }
637        }
638        return dd;
639    }
640
641    /**
642     * {@inheritDoc}
643     */
644    @Override
645    protected Content getNavLinkTree() {
646        Content treeLinkContent = getHyperLink(DocPaths.PACKAGE_TREE,
647                treeLabel, "", "");
648        Content li = HtmlTree.LI(treeLinkContent);
649        return li;
650    }
651
652    /**
653     * Add summary details to the navigation bar.
654     *
655     * @param subDiv the content tree to which the summary detail links will be added
656     */
657    protected void addSummaryDetailLinks(Content subDiv) {
658        try {
659            Content div = HtmlTree.DIV(getNavSummaryLinks());
660            div.addContent(getNavDetailLinks());
661            subDiv.addContent(div);
662        } catch (Exception e) {
663            throw new DocletAbortException(e);
664        }
665    }
666
667    /**
668     * Get summary links for navigation bar.
669     *
670     * @return the content tree for the navigation summary links
671     */
672    protected Content getNavSummaryLinks() throws Exception {
673        Content li = HtmlTree.LI(summaryLabel);
674        li.addContent(getSpace());
675        Content ulNav = HtmlTree.UL(HtmlStyle.subNavList, li);
676        MemberSummaryBuilder memberSummaryBuilder = (MemberSummaryBuilder)
677                configuration.getBuilderFactory().getMemberSummaryBuilder(this);
678        for (VisibleMemberMap.Kind kind : VisibleMemberMap.Kind.summarySet) {
679            Content liNav = new HtmlTree(HtmlTag.LI);
680            if (kind == VisibleMemberMap.Kind.ENUM_CONSTANTS && !utils.isEnum(typeElement)) {
681                continue;
682            }
683            if (kind == VisibleMemberMap.Kind.CONSTRUCTORS && utils.isEnum(typeElement)) {
684                continue;
685            }
686            AbstractMemberWriter writer =
687                ((AbstractMemberWriter) memberSummaryBuilder.getMemberSummaryWriter(kind));
688            if (writer == null) {
689                liNav.addContent(getResource(VisibleMemberMap.Kind.getNavLinkLabels(kind)));
690            } else {
691                writer.addNavSummaryLink(
692                        memberSummaryBuilder.members(kind),
693                        memberSummaryBuilder.getVisibleMemberMap(kind), liNav);
694            }
695            if (kind != Kind.METHODS) {
696                addNavGap(liNav);
697            }
698            ulNav.addContent(liNav);
699        }
700        return ulNav;
701    }
702
703    /**
704     * Get detail links for the navigation bar.
705     *
706     * @return the content tree for the detail links
707     * @throws java.lang.Exception
708     */
709    protected Content getNavDetailLinks() throws Exception {
710        Content li = HtmlTree.LI(detailLabel);
711        li.addContent(getSpace());
712        Content ulNav = HtmlTree.UL(HtmlStyle.subNavList, li);
713        MemberSummaryBuilder memberSummaryBuilder = (MemberSummaryBuilder)
714                configuration.getBuilderFactory().getMemberSummaryBuilder(this);
715        for (VisibleMemberMap.Kind kind : VisibleMemberMap.Kind.detailSet) {
716            Content liNav = new HtmlTree(HtmlTag.LI);
717            AbstractMemberWriter writer =
718                    ((AbstractMemberWriter) memberSummaryBuilder.
719                    getMemberSummaryWriter(kind));
720            if (kind == VisibleMemberMap.Kind.ENUM_CONSTANTS && !utils.isEnum(typeElement)) {
721                continue;
722            }
723            if (kind == VisibleMemberMap.Kind.CONSTRUCTORS && utils.isEnum(typeElement)) {
724                continue;
725            }
726            if (writer == null) {
727                liNav.addContent(getResource(VisibleMemberMap.Kind.getNavLinkLabels(kind)));
728            } else {
729                writer.addNavDetailLink(memberSummaryBuilder.members(kind), liNav);
730            }
731            if (kind != Kind.METHODS) {
732                addNavGap(liNav);
733            }
734            ulNav.addContent(liNav);
735        }
736        return ulNav;
737    }
738
739    /**
740     * Add gap between navigation bar elements.
741     *
742     * @param liNav the content tree to which the gap will be added
743     */
744    protected void addNavGap(Content liNav) {
745        liNav.addContent(getSpace());
746        liNav.addContent("|");
747        liNav.addContent(getSpace());
748    }
749
750    /**
751     * Return the TypeElement being documented.
752     *
753     * @return the TypeElement being documented.
754     */
755    @Override
756    public TypeElement getTypeElement() {
757        return typeElement;
758    }
759}
760