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