1 /*
2  * Copyright (c) 2018, 2020, 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 package jdk.javadoc.internal.doclets.formats.html;
26 
27 import java.util.ArrayList;
28 import java.util.List;
29 import java.util.Set;
30 import java.util.SortedSet;
31 
32 import javax.lang.model.element.Element;
33 import javax.lang.model.element.ElementKind;
34 import javax.lang.model.element.ModuleElement;
35 import javax.lang.model.element.PackageElement;
36 import javax.lang.model.element.TypeElement;
37 
38 import jdk.javadoc.internal.doclets.formats.html.markup.Comment;
39 import jdk.javadoc.internal.doclets.formats.html.markup.ContentBuilder;
40 import jdk.javadoc.internal.doclets.formats.html.markup.Entity;
41 import jdk.javadoc.internal.doclets.formats.html.markup.HtmlAttr;
42 import jdk.javadoc.internal.doclets.formats.html.markup.HtmlStyle;
43 import jdk.javadoc.internal.doclets.formats.html.markup.TagName;
44 import jdk.javadoc.internal.doclets.formats.html.markup.HtmlTree;
45 import jdk.javadoc.internal.doclets.formats.html.markup.Links;
46 import jdk.javadoc.internal.doclets.toolkit.Content;
47 import jdk.javadoc.internal.doclets.toolkit.builders.MemberSummaryBuilder;
48 import jdk.javadoc.internal.doclets.toolkit.util.DocFile;
49 import jdk.javadoc.internal.doclets.toolkit.util.DocLink;
50 import jdk.javadoc.internal.doclets.toolkit.util.DocPath;
51 import jdk.javadoc.internal.doclets.toolkit.util.DocPaths;
52 import jdk.javadoc.internal.doclets.toolkit.util.VisibleMemberTable;
53 
54 import static jdk.javadoc.internal.doclets.toolkit.util.VisibleMemberTable.Kind.*;
55 
56 /**
57  * Factory for navigation bar.
58  *
59  * <p>
60  * <b>This is NOT part of any supported API. If you write code that depends on this, you do so at
61  * your own risk. This code and its internal interfaces are subject to change or deletion without
62  * notice.</b>
63  */
64 public class Navigation {
65 
66     private final HtmlConfiguration configuration;
67     private final HtmlOptions options;
68     private final Element element;
69     private final Contents contents;
70     private final DocPath path;
71     private final DocPath pathToRoot;
72     private final Links links;
73     private final PageMode documentedPage;
74     private Content navLinkModule;
75     private Content navLinkPackage;
76     private Content navLinkClass;
77     private MemberSummaryBuilder memberSummaryBuilder;
78     private boolean displaySummaryModuleDescLink;
79     private boolean displaySummaryModulesLink;
80     private boolean displaySummaryPackagesLink;
81     private boolean displaySummaryServicesLink;
82     private Content userHeader;
83     private Content userFooter;
84     private final String rowListTitle;
85     private final Content searchLabel;
86 
87     private static final Content EMPTY_COMMENT = new Comment(" ");
88 
89     public enum PageMode {
90         ALL_CLASSES,
91         ALL_PACKAGES,
92         CLASS,
93         CONSTANT_VALUES,
94         DEPRECATED,
95         DOC_FILE,
96         HELP,
97         INDEX,
98         MODULE,
99         OVERVIEW,
100         PACKAGE,
101         SERIALIZED_FORM,
102         SYSTEM_PROPERTIES,
103         TREE,
104         USE;
105     }
106 
107     enum Position {
108         BOTTOM(MarkerComments.START_OF_BOTTOM_NAVBAR, MarkerComments.END_OF_BOTTOM_NAVBAR),
109         TOP(MarkerComments.START_OF_TOP_NAVBAR, MarkerComments.END_OF_TOP_NAVBAR);
110 
111         final Content startOfNav;
112         final Content endOfNav;
113 
Position(Content startOfNav, Content endOfNav)114         Position(Content startOfNav, Content endOfNav) {
115             this.startOfNav = startOfNav;
116             this.endOfNav = endOfNav;
117         }
118 
startOfNav()119         Content startOfNav() {
120             return startOfNav;
121         }
122 
endOfNav()123         Content endOfNav() {
124             return endOfNav;
125         }
126     }
127 
128     /**
129      * Creates a {@code Navigation} object for a specific file, to be written in a specific HTML
130      * version.
131      *
132      * @param element element being documented. null if its not an element documentation page
133      * @param configuration the configuration object
134      * @param page the kind of page being documented
135      * @param path the DocPath object
136      */
Navigation(Element element, HtmlConfiguration configuration, PageMode page, DocPath path)137     public Navigation(Element element, HtmlConfiguration configuration, PageMode page, DocPath path) {
138         this.configuration = configuration;
139         this.options = configuration.getOptions();
140         this.element = element;
141         this.contents = configuration.contents;
142         this.documentedPage = page;
143         this.path = path;
144         this.pathToRoot = path.parent().invert();
145         this.links = new Links(path);
146         this.rowListTitle = configuration.getDocResources().getText("doclet.Navigation");
147         this.searchLabel = contents.getContent("doclet.search");
148     }
149 
setNavLinkModule(Content navLinkModule)150     public Navigation setNavLinkModule(Content navLinkModule) {
151         this.navLinkModule = navLinkModule;
152         return this;
153     }
154 
setNavLinkPackage(Content navLinkPackage)155     public Navigation setNavLinkPackage(Content navLinkPackage) {
156         this.navLinkPackage = navLinkPackage;
157         return this;
158     }
159 
setNavLinkClass(Content navLinkClass)160     public Navigation setNavLinkClass(Content navLinkClass) {
161         this.navLinkClass = navLinkClass;
162         return this;
163     }
164 
setMemberSummaryBuilder(MemberSummaryBuilder memberSummaryBuilder)165     public Navigation setMemberSummaryBuilder(MemberSummaryBuilder memberSummaryBuilder) {
166         this.memberSummaryBuilder = memberSummaryBuilder;
167         return this;
168     }
169 
setDisplaySummaryModuleDescLink(boolean displaySummaryModuleDescLink)170     public Navigation setDisplaySummaryModuleDescLink(boolean displaySummaryModuleDescLink) {
171         this.displaySummaryModuleDescLink = displaySummaryModuleDescLink;
172         return this;
173     }
174 
setDisplaySummaryModulesLink(boolean displaySummaryModulesLink)175     public Navigation setDisplaySummaryModulesLink(boolean displaySummaryModulesLink) {
176         this.displaySummaryModulesLink = displaySummaryModulesLink;
177         return this;
178     }
179 
setDisplaySummaryPackagesLink(boolean displaySummaryPackagesLink)180     public Navigation setDisplaySummaryPackagesLink(boolean displaySummaryPackagesLink) {
181         this.displaySummaryPackagesLink = displaySummaryPackagesLink;
182         return this;
183     }
184 
setDisplaySummaryServicesLink(boolean displaySummaryServicesLink)185     public Navigation setDisplaySummaryServicesLink(boolean displaySummaryServicesLink) {
186         this.displaySummaryServicesLink = displaySummaryServicesLink;
187         return this;
188     }
189 
setUserHeader(Content userHeader)190     public Navigation setUserHeader(Content userHeader) {
191         this.userHeader = userHeader;
192         return this;
193     }
194 
setUserFooter(Content userFooter)195     public Navigation setUserFooter(Content userFooter) {
196         this.userFooter = userFooter;
197         return this;
198     }
199 
200     /**
201      * Add the links for the main navigation.
202      *
203      * @param tree the content tree to which the main navigation will added
204      */
addMainNavLinks(Content tree)205     private void addMainNavLinks(Content tree) {
206         switch (documentedPage) {
207             case OVERVIEW:
208                 addActivePageLink(tree, contents.overviewLabel, options.createOverview());
209                 addModuleLink(tree);
210                 addPackageLink(tree);
211                 addPageLabel(tree, contents.classLabel, true);
212                 addPageLabel(tree, contents.useLabel, options.classUse());
213                 addTreeLink(tree);
214                 addDeprecatedLink(tree);
215                 addIndexLink(tree);
216                 addHelpLink(tree);
217                 break;
218             case MODULE:
219                 addOverviewLink(tree);
220                 addActivePageLink(tree, contents.moduleLabel, configuration.showModules);
221                 addPackageLink(tree);
222                 addPageLabel(tree, contents.classLabel, true);
223                 addPageLabel(tree, contents.useLabel, options.classUse());
224                 addTreeLink(tree);
225                 addDeprecatedLink(tree);
226                 addIndexLink(tree);
227                 addHelpLink(tree);
228                 break;
229             case PACKAGE:
230                 addOverviewLink(tree);
231                 addModuleOfElementLink(tree);
232                 addActivePageLink(tree, contents.packageLabel, true);
233                 addPageLabel(tree, contents.classLabel, true);
234                 if (options.classUse()) {
235                     addContentToTree(tree, links.createLink(DocPaths.PACKAGE_USE,
236                             contents.useLabel, "", ""));
237                 }
238                 if (options.createTree()) {
239                     addContentToTree(tree, links.createLink(DocPaths.PACKAGE_TREE,
240                             contents.treeLabel, "", ""));
241                 }
242                 addDeprecatedLink(tree);
243                 addIndexLink(tree);
244                 addHelpLink(tree);
245                 break;
246             case CLASS:
247                 addOverviewLink(tree);
248                 addModuleOfElementLink(tree);
249                 addPackageSummaryLink(tree);
250                 addActivePageLink(tree, contents.classLabel, true);
251                 if (options.classUse()) {
252                     addContentToTree(tree, links.createLink(DocPaths.CLASS_USE.resolve(path.basename()),
253                             contents.useLabel));
254                 }
255                 if (options.createTree()) {
256                     addContentToTree(tree, links.createLink(DocPaths.PACKAGE_TREE,
257                             contents.treeLabel, "", ""));
258                 }
259                 addDeprecatedLink(tree);
260                 addIndexLink(tree);
261                 addHelpLink(tree);
262                 break;
263             case USE:
264                 addOverviewLink(tree);
265                 addModuleOfElementLink(tree);
266                 if (element instanceof PackageElement) {
267                     addPackageSummaryLink(tree);
268                     addPageLabel(tree, contents.classLabel, true);
269                 } else {
270                     addPackageOfElementLink(tree);
271                     addContentToTree(tree, navLinkClass);
272                 }
273                 addActivePageLink(tree, contents.useLabel, options.classUse());
274                 if (element instanceof PackageElement) {
275                     addContentToTree(tree, links.createLink(DocPaths.PACKAGE_TREE, contents.treeLabel));
276                 } else {
277                     addContentToTree(tree, configuration.utils.isEnclosingPackageIncluded((TypeElement) element)
278                             ? links.createLink(DocPath.parent.resolve(DocPaths.PACKAGE_TREE), contents.treeLabel)
279                             : links.createLink(pathToRoot.resolve(DocPaths.OVERVIEW_TREE), contents.treeLabel));
280                 }
281                 addDeprecatedLink(tree);
282                 addIndexLink(tree);
283                 addHelpLink(tree);
284                 break;
285             case TREE:
286                 addOverviewLink(tree);
287                 if (element == null) {
288                     addPageLabel(tree, contents.moduleLabel, configuration.showModules);
289                     addPageLabel(tree, contents.packageLabel, true);
290                 } else {
291                     addModuleOfElementLink(tree);
292                     addPackageSummaryLink(tree);
293                 }
294                 addPageLabel(tree, contents.classLabel, true);
295                 addPageLabel(tree, contents.useLabel, options.classUse());
296                 addActivePageLink(tree, contents.treeLabel, options.createTree());
297                 addDeprecatedLink(tree);
298                 addIndexLink(tree);
299                 addHelpLink(tree);
300                 break;
301             case DEPRECATED:
302             case INDEX:
303             case HELP:
304                 addOverviewLink(tree);
305                 addModuleLink(tree);
306                 addPackageLink(tree);
307                 addPageLabel(tree, contents.classLabel, true);
308                 addPageLabel(tree, contents.useLabel, options.classUse());
309                 addTreeLink(tree);
310                 if (documentedPage == PageMode.DEPRECATED) {
311                     addActivePageLink(tree, contents.deprecatedLabel, !(options.noDeprecated()
312                             || options.noDeprecatedList()));
313                 } else {
314                     addDeprecatedLink(tree);
315                 }
316                 if (documentedPage == PageMode.INDEX) {
317                     addActivePageLink(tree, contents.indexLabel, options.createIndex());
318                 } else {
319                     addIndexLink(tree);
320                 }
321                 if (documentedPage == PageMode.HELP) {
322                     addActivePageLink(tree, contents.helpLabel, !options.noHelp());
323                 } else {
324                     addHelpLink(tree);
325                 }
326                 break;
327             case ALL_CLASSES:
328             case ALL_PACKAGES:
329             case CONSTANT_VALUES:
330             case SERIALIZED_FORM:
331             case SYSTEM_PROPERTIES:
332                 addOverviewLink(tree);
333                 addModuleLink(tree);
334                 addPackageLink(tree);
335                 addPageLabel(tree, contents.classLabel, true);
336                 addPageLabel(tree, contents.useLabel, options.classUse());
337                 addTreeLink(tree);
338                 addDeprecatedLink(tree);
339                 addIndexLink(tree);
340                 addHelpLink(tree);
341                 break;
342             case DOC_FILE:
343                 addOverviewLink(tree);
344                 addModuleOfElementLink(tree);
345                 addContentToTree(tree, navLinkPackage);
346                 addPageLabel(tree, contents.classLabel, true);
347                 addPageLabel(tree, contents.useLabel, options.classUse());
348                 addTreeLink(tree);
349                 addDeprecatedLink(tree);
350                 addIndexLink(tree);
351                 addHelpLink(tree);
352                 break;
353             default:
354                 break;
355         }
356     }
357 
358     /**
359      * Add the summary links to the sub-navigation.
360      *
361      * @param tree the content tree to which the sub-navigation will added
362      */
addSummaryLinks(Content tree)363     private void addSummaryLinks(Content tree) {
364         List<Content> listContents = new ArrayList<>();
365         switch (documentedPage) {
366             case CLASS:
367                 if (element.getKind() == ElementKind.ANNOTATION_TYPE) {
368                     addAnnotationTypeSummaryLink("doclet.navField",
369                             FIELDS, listContents);
370                     addAnnotationTypeSummaryLink("doclet.navAnnotationTypeRequiredMember",
371                             ANNOTATION_TYPE_MEMBER_REQUIRED, listContents);
372                     addAnnotationTypeSummaryLink("doclet.navAnnotationTypeOptionalMember",
373                             ANNOTATION_TYPE_MEMBER_OPTIONAL, listContents);
374                 } else {
375                     TypeElement typeElement = (TypeElement) element;
376                     for (VisibleMemberTable.Kind kind : summarySet) {
377                         if (kind == ENUM_CONSTANTS && !configuration.utils.isEnum(typeElement)) {
378                             continue;
379                         }
380                         if (kind == CONSTRUCTORS && configuration.utils.isEnum(typeElement)) {
381                             continue;
382                         }
383                         AbstractMemberWriter writer
384                                 = ((AbstractMemberWriter) memberSummaryBuilder.getMemberSummaryWriter(kind));
385                         if (writer == null) {
386                             addContentToList(listContents, contents.getNavLinkLabelContent(kind));
387                         } else {
388                             addTypeSummaryLink(memberSummaryBuilder.members(kind),
389                                     memberSummaryBuilder.getVisibleMemberTable(),
390                                     kind, listContents);
391                         }
392                     }
393                 }
394                 if (!listContents.isEmpty()) {
395                     Content li = HtmlTree.LI(contents.summaryLabel);
396                     li.add(Entity.NO_BREAK_SPACE);
397                     tree.add(li);
398                     addListToNav(listContents, tree);
399                 }
400                 break;
401             case MODULE:
402                 if (displaySummaryModuleDescLink) {
403                     addContentToList(listContents,
404                             links.createLink(SectionName.MODULE_DESCRIPTION, contents.navModuleDescription));
405                 } else {
406                     addContentToList(listContents, contents.navModuleDescription);
407                 }
408                 if (displaySummaryModulesLink) {
409                     addContentToList(listContents,
410                             links.createLink(SectionName.MODULES, contents.navModules));
411                 } else {
412                     addContentToList(listContents, contents.navModules);
413                 }
414                 if (displaySummaryPackagesLink) {
415                     addContentToList(listContents,
416                             links.createLink(SectionName.PACKAGES, contents.navPackages));
417                 } else {
418                     addContentToList(listContents, contents.navPackages);
419                 }
420                 if (displaySummaryServicesLink) {
421                     addContentToList(listContents,
422                             links.createLink(SectionName.SERVICES, contents.navServices));
423                 } else {
424                     addContentToList(listContents, contents.navServices);
425                 }
426                 if (!listContents.isEmpty()) {
427                     Content li = HtmlTree.LI(contents.moduleSubNavLabel);
428                     li.add(Entity.NO_BREAK_SPACE);
429                     tree.add(li);
430                     addListToNav(listContents, tree);
431                 }
432                 break;
433             default:
434                 break;
435         }
436     }
437 
438     /**
439      * Add the navigation summary link.
440      *
441      * @param members members to be linked
442      * @param vmt the visible member table
443      * @param kind the visible member kind
444      * @param listContents the list of contents
445      */
addTypeSummaryLink(SortedSet<? extends Element> members, VisibleMemberTable vmt, VisibleMemberTable.Kind kind, List<Content> listContents)446     private void addTypeSummaryLink(SortedSet<? extends Element> members,
447             VisibleMemberTable vmt,
448             VisibleMemberTable.Kind kind, List<Content> listContents) {
449         if (!members.isEmpty()) {
450             addTypeSummaryLink(null, kind, true, listContents);
451             return;
452         }
453         Set<TypeElement> visibleClasses = vmt.getVisibleTypeElements();
454         for (TypeElement t : visibleClasses) {
455             if (configuration.getVisibleMemberTable(t).hasVisibleMembers(kind)) {
456                 addTypeSummaryLink(null, kind, true, listContents);
457                 return;
458             }
459         }
460         addTypeSummaryLink(null, kind, false, listContents);
461     }
462 
463     /**
464      * Add the navigation Type summary link.
465      *
466      * @param typeElement the Type being documented
467      * @param kind the kind of member being documented
468      * @param link true if the members are listed and need to be linked
469      * @param listContents the list of contents to which the summary will be added
470      */
addTypeSummaryLink(TypeElement typeElement, VisibleMemberTable.Kind kind, boolean link, List<Content> listContents)471     private void addTypeSummaryLink(TypeElement typeElement, VisibleMemberTable.Kind kind, boolean link,
472             List<Content> listContents) {
473         switch (kind) {
474             case CONSTRUCTORS:
475                 if (link) {
476                     addContentToList(listContents, links.createLink(SectionName.CONSTRUCTOR_SUMMARY,
477                             contents.navConstructor));
478                 } else {
479                     addContentToList(listContents, contents.navConstructor);
480                 }
481                 break;
482             case ENUM_CONSTANTS:
483                 if (link) {
484                     if (typeElement == null) {
485                         addContentToList(listContents, links.createLink(SectionName.ENUM_CONSTANT_SUMMARY,
486                                 contents.navEnum));
487                     } else {
488                         addContentToList(listContents, links.createLink(
489                                 SectionName.ENUM_CONSTANTS_INHERITANCE,
490                                 configuration.getClassName(typeElement), contents.navEnum));
491                     }
492                 } else {
493                     addContentToList(listContents, contents.navEnum);
494                 }
495                 break;
496             case FIELDS:
497                 if (link) {
498                     if (typeElement == null) {
499                         addContentToList(listContents,
500                                 links.createLink(SectionName.FIELD_SUMMARY, contents.navField));
501                     } else {
502                         addContentToList(listContents, links.createLink(SectionName.FIELDS_INHERITANCE,
503                                 configuration.getClassName(typeElement), contents.navField));
504                     }
505                 } else {
506                     addContentToList(listContents, contents.navField);
507                 }
508                 break;
509             case METHODS:
510                 if (link) {
511                     if (typeElement == null) {
512                         addContentToList(listContents,
513                                 links.createLink(SectionName.METHOD_SUMMARY, contents.navMethod));
514                     } else {
515                         addContentToList(listContents, links.createLink(SectionName.METHODS_INHERITANCE,
516                                 configuration.getClassName(typeElement), contents.navMethod));
517                     }
518                 } else {
519                     addContentToList(listContents, contents.navMethod);
520                 }
521                 break;
522             case INNER_CLASSES:
523                 if (link) {
524                     if (typeElement == null) {
525                         addContentToList(listContents,
526                                 links.createLink(SectionName.NESTED_CLASS_SUMMARY, contents.navNested));
527                     } else {
528                         addContentToList(listContents, links.createLink(SectionName.NESTED_CLASSES_INHERITANCE,
529                                 configuration.utils.getFullyQualifiedName(typeElement), contents.navNested));
530                     }
531                 } else {
532                     addContentToList(listContents, contents.navNested);
533                 }
534                 break;
535             case PROPERTIES:
536                 if (link) {
537                     if (typeElement == null) {
538                         addContentToList(listContents,
539                                 links.createLink(SectionName.PROPERTY_SUMMARY, contents.navProperty));
540                     } else {
541                         addContentToList(listContents, links.createLink(SectionName.PROPERTIES_INHERITANCE,
542                                 configuration.getClassName(typeElement), contents.navProperty));
543                     }
544                 } else {
545                     addContentToList(listContents, contents.navProperty);
546                 }
547                 break;
548             default:
549                 break;
550         }
551     }
552 
553     /**
554      * Add the navigation Type summary link.
555      *
556      * @param label the label to be added
557      * @param kind the kind of member being documented
558      * @param listContents the list of contents to which the summary will be added
559      */
addAnnotationTypeSummaryLink(String label, VisibleMemberTable.Kind kind, List<Content> listContents)560     private void addAnnotationTypeSummaryLink(String label, VisibleMemberTable.Kind kind, List<Content> listContents) {
561         AbstractMemberWriter writer = ((AbstractMemberWriter) memberSummaryBuilder.
562                 getMemberSummaryWriter(kind));
563         if (writer == null) {
564             addContentToList(listContents, contents.getContent(label));
565         } else {
566             boolean link = memberSummaryBuilder.getVisibleMemberTable().hasVisibleMembers(kind);
567             switch (kind) {
568                 case FIELDS:
569                     if (link) {
570                         addContentToList(listContents, links.createLink(SectionName.FIELD_SUMMARY,
571                                 contents.navField));
572                     } else {
573                         addContentToList(listContents, contents.navField);
574                     }
575                     break;
576                 case ANNOTATION_TYPE_MEMBER_REQUIRED:
577                     if (link) {
578                         addContentToList(listContents, links.createLink(
579                                 SectionName.ANNOTATION_TYPE_REQUIRED_ELEMENT_SUMMARY,
580                                 contents.navAnnotationTypeRequiredMember));
581                     } else {
582                         addContentToList(listContents, contents.navAnnotationTypeRequiredMember);
583                     }
584                     break;
585                 case ANNOTATION_TYPE_MEMBER_OPTIONAL:
586                     if (link) {
587                         addContentToList(listContents, links.createLink(
588                                 SectionName.ANNOTATION_TYPE_OPTIONAL_ELEMENT_SUMMARY,
589                                 contents.navAnnotationTypeOptionalMember));
590                     } else {
591                         addContentToList(listContents, contents.navAnnotationTypeOptionalMember);
592                     }
593                     break;
594                 default:
595                     break;
596             }
597         }
598     }
599 
600     /**
601      * Add the detail links to sub-navigation.
602      *
603      * @param tree the content tree to which the links will be added
604      */
addDetailLinks(Content tree)605     private void addDetailLinks(Content tree) {
606         switch (documentedPage) {
607             case CLASS:
608                 List<Content> listContents = new ArrayList<>();
609                 if (element.getKind() == ElementKind.ANNOTATION_TYPE) {
610                     addAnnotationTypeDetailLink(listContents);
611                 } else {
612                     TypeElement typeElement = (TypeElement) element;
613                     for (VisibleMemberTable.Kind kind : detailSet) {
614                         AbstractMemberWriter writer
615                                 = ((AbstractMemberWriter) memberSummaryBuilder.
616                                         getMemberSummaryWriter(kind));
617                         if (kind == ENUM_CONSTANTS && !configuration.utils.isEnum(typeElement)) {
618                             continue;
619                         }
620                         if (kind == CONSTRUCTORS && configuration.utils.isEnum(typeElement)) {
621                             continue;
622                         }
623                         if (writer == null) {
624                             addContentToList(listContents, contents.getNavLinkLabelContent(kind));
625                         } else {
626                             addTypeDetailLink(kind, memberSummaryBuilder.hasMembers(kind), listContents);
627                         }
628                     }
629                 }
630                 if (!listContents.isEmpty()) {
631                     Content li = HtmlTree.LI(contents.detailLabel);
632                     li.add(Entity.NO_BREAK_SPACE);
633                     tree.add(li);
634                     addListToNav(listContents, tree);
635                 }
636                 break;
637             default:
638                 break;
639         }
640     }
641 
642     /**
643      * Add the navigation Type detail link.
644      *
645      * @param kind the kind of member being documented
646      * @param link true if the members are listed and need to be linked
647      * @param listContents the list of contents to which the detail will be added.
648      */
addTypeDetailLink(VisibleMemberTable.Kind kind, boolean link, List<Content> listContents)649     protected void addTypeDetailLink(VisibleMemberTable.Kind kind, boolean link, List<Content> listContents) {
650         switch (kind) {
651             case CONSTRUCTORS:
652                 if (link) {
653                     addContentToList(listContents, links.createLink(SectionName.CONSTRUCTOR_DETAIL, contents.navConstructor));
654                 } else {
655                     addContentToList(listContents, contents.navConstructor);
656                 }
657                 break;
658             case ENUM_CONSTANTS:
659                 if (link) {
660                     addContentToList(listContents, links.createLink(SectionName.ENUM_CONSTANT_DETAIL, contents.navEnum));
661                 } else {
662                     addContentToList(listContents, contents.navEnum);
663                 }
664                 break;
665             case FIELDS:
666                 if (link) {
667                     addContentToList(listContents, links.createLink(SectionName.FIELD_DETAIL, contents.navField));
668                 } else {
669                     addContentToList(listContents, contents.navField);
670                 }
671                 break;
672             case METHODS:
673                 if (link) {
674                     addContentToList(listContents, links.createLink(SectionName.METHOD_DETAIL, contents.navMethod));
675                 } else {
676                     addContentToList(listContents, contents.navMethod);
677                 }
678                 break;
679             case PROPERTIES:
680                 if (link) {
681                     addContentToList(listContents, links.createLink(SectionName.PROPERTY_DETAIL, contents.navProperty));
682                 } else {
683                     addContentToList(listContents, contents.navProperty);
684                 }
685                 break;
686             default:
687                 break;
688         }
689     }
690 
691     /**
692      * Add the navigation Annotation Type detail link.
693      *
694      * @param listContents the list of contents to which the annotation detail will be added.
695      */
addAnnotationTypeDetailLink(List<Content> listContents)696     protected void addAnnotationTypeDetailLink(List<Content> listContents) {
697         TypeElement annotationType = (TypeElement) element;
698         AbstractMemberWriter writerField
699                 = ((AbstractMemberWriter) memberSummaryBuilder.
700                         getMemberSummaryWriter(FIELDS));
701         AbstractMemberWriter writerOptional
702                 = ((AbstractMemberWriter) memberSummaryBuilder.
703                         getMemberSummaryWriter(ANNOTATION_TYPE_MEMBER_OPTIONAL));
704         AbstractMemberWriter writerRequired
705                 = ((AbstractMemberWriter) memberSummaryBuilder.
706                         getMemberSummaryWriter(ANNOTATION_TYPE_MEMBER_REQUIRED));
707         if (writerField != null) {
708             addAnnotationTypeDetailLink(FIELDS,
709                     !configuration.utils.getFields(annotationType).isEmpty(),
710                     listContents);
711         } else {
712             addContentToList(listContents, contents.navField);
713         }
714         if (writerOptional != null) {
715             addAnnotationTypeDetailLink(ANNOTATION_TYPE_MEMBER_OPTIONAL,
716                     !annotationType.getAnnotationMirrors().isEmpty(), listContents);
717         } else if (writerRequired != null) {
718             addAnnotationTypeDetailLink(ANNOTATION_TYPE_MEMBER_REQUIRED,
719                     !annotationType.getAnnotationMirrors().isEmpty(), listContents);
720         } else {
721             addContentToList(listContents, contents.navAnnotationTypeMember);
722         }
723     }
724 
725     /**
726      * Add the navigation Annotation Type detail link.
727      *
728      * @param type the kind of member being documented
729      * @param link true if the member details need to be linked
730      * @param listContents the list of contents to which the annotation detail will be added.
731      */
addAnnotationTypeDetailLink(VisibleMemberTable.Kind type, boolean link, List<Content> listContents)732     protected void addAnnotationTypeDetailLink(VisibleMemberTable.Kind type, boolean link, List<Content> listContents) {
733         switch (type) {
734             case FIELDS:
735                 if (link) {
736                     addContentToList(listContents, links.createLink(SectionName.FIELD_DETAIL,
737                             contents.navField));
738                 } else {
739                     addContentToList(listContents, contents.navField);
740                 }
741                 break;
742             case ANNOTATION_TYPE_MEMBER_REQUIRED:
743             case ANNOTATION_TYPE_MEMBER_OPTIONAL:
744                 if (link) {
745                     addContentToList(listContents, links.createLink(SectionName.ANNOTATION_TYPE_ELEMENT_DETAIL,
746                             contents.navAnnotationTypeMember));
747                 } else {
748                     addContentToList(listContents, contents.navAnnotationTypeMember);
749                 }
750                 break;
751             default:
752                 break;
753         }
754     }
755 
addContentToList(List<Content> listContents, Content tree)756     private void addContentToList(List<Content> listContents, Content tree) {
757         listContents.add(HtmlTree.LI(tree));
758     }
759 
addContentToTree(Content tree, Content content)760     private void addContentToTree(Content tree, Content content) {
761         tree.add(HtmlTree.LI(content));
762     }
763 
addListToNav(List<Content> listContents, Content tree)764     private void addListToNav(List<Content> listContents, Content tree) {
765         int count = 0;
766         for (Content liContent : listContents) {
767             if (count < listContents.size() - 1) {
768                 liContent.add(Entity.NO_BREAK_SPACE);
769                 liContent.add("|");
770                 liContent.add(Entity.NO_BREAK_SPACE);
771             }
772             tree.add(liContent);
773             count++;
774         }
775     }
776 
addActivePageLink(Content tree, Content label, boolean display)777     private void addActivePageLink(Content tree, Content label, boolean display) {
778         if (display) {
779             tree.add(HtmlTree.LI(HtmlStyle.navBarCell1Rev, label));
780         }
781     }
782 
addPageLabel(Content tree, Content label, boolean display)783     private void addPageLabel(Content tree, Content label, boolean display) {
784         if (display) {
785             tree.add(HtmlTree.LI(label));
786         }
787     }
788 
addOverviewLink(Content tree)789     private void addOverviewLink(Content tree) {
790         if (options.createOverview()) {
791             tree.add(HtmlTree.LI(links.createLink(pathToRoot.resolve(DocPaths.INDEX),
792                     contents.overviewLabel, "", "")));
793         }
794     }
795 
addModuleLink(Content tree)796     private void addModuleLink(Content tree) {
797         if (configuration.showModules) {
798             if (configuration.modules.size() == 1) {
799                 ModuleElement mdle = configuration.modules.first();
800                 boolean included = configuration.utils.isIncluded(mdle);
801                 tree.add(HtmlTree.LI((included)
802                         ? links.createLink(pathToRoot.resolve(configuration.docPaths.moduleSummary(mdle)), contents.moduleLabel, "", "")
803                         : contents.moduleLabel));
804             } else if (!configuration.modules.isEmpty()) {
805                 addPageLabel(tree, contents.moduleLabel, true);
806             }
807         }
808     }
809 
addModuleOfElementLink(Content tree)810     private void addModuleOfElementLink(Content tree) {
811         if (configuration.showModules) {
812             tree.add(HtmlTree.LI(navLinkModule));
813         }
814     }
815 
addPackageLink(Content tree)816     private void addPackageLink(Content tree) {
817         if (configuration.packages.size() == 1) {
818             PackageElement packageElement = configuration.packages.first();
819             boolean included = packageElement != null && configuration.utils.isIncluded(packageElement);
820             if (!included) {
821                 for (PackageElement p : configuration.packages) {
822                     if (p.equals(packageElement)) {
823                         included = true;
824                         break;
825                     }
826                 }
827             }
828             if (included || packageElement == null) {
829                 tree.add(HtmlTree.LI(links.createLink(
830                         pathToRoot.resolve(configuration.docPaths.forPackage(packageElement).resolve(DocPaths.PACKAGE_SUMMARY)),
831                         contents.packageLabel)));
832             } else {
833                 DocLink crossPkgLink = configuration.extern.getExternalLink(
834                         packageElement, pathToRoot, DocPaths.PACKAGE_SUMMARY.getPath());
835                 if (crossPkgLink != null) {
836                     tree.add(HtmlTree.LI(links.createLink(crossPkgLink, contents.packageLabel)));
837                 } else {
838                     tree.add(HtmlTree.LI(contents.packageLabel));
839                 }
840             }
841         } else if (!configuration.packages.isEmpty()) {
842             addPageLabel(tree, contents.packageLabel, true);
843         }
844     }
845 
addPackageOfElementLink(Content tree)846     private void addPackageOfElementLink(Content tree) {
847         tree.add(HtmlTree.LI(links.createLink(DocPath.parent.resolve(DocPaths.PACKAGE_SUMMARY),
848                 contents.packageLabel)));
849     }
850 
addPackageSummaryLink(Content tree)851     private void addPackageSummaryLink(Content tree) {
852         tree.add(HtmlTree.LI(links.createLink(DocPaths.PACKAGE_SUMMARY, contents.packageLabel)));
853     }
854 
addTreeLink(Content tree)855     private void addTreeLink(Content tree) {
856         if (options.createTree()) {
857             List<PackageElement> packages = new ArrayList<>(configuration.getSpecifiedPackageElements());
858             DocPath docPath = packages.size() == 1 && configuration.getSpecifiedTypeElements().isEmpty()
859                     ? pathToRoot.resolve(configuration.docPaths.forPackage(packages.get(0)).resolve(DocPaths.PACKAGE_TREE))
860                     : pathToRoot.resolve(DocPaths.OVERVIEW_TREE);
861             tree.add(HtmlTree.LI(links.createLink(docPath, contents.treeLabel, "", "")));
862         }
863     }
864 
addDeprecatedLink(Content tree)865     private void addDeprecatedLink(Content tree) {
866         if (!(options.noDeprecated() || options.noDeprecatedList())) {
867             tree.add(HtmlTree.LI(links.createLink(pathToRoot.resolve(DocPaths.DEPRECATED_LIST),
868                     contents.deprecatedLabel, "", "")));
869         }
870     }
871 
addIndexLink(Content tree)872     private void addIndexLink(Content tree) {
873         if (options.createIndex()) {
874             tree.add(HtmlTree.LI(links.createLink(pathToRoot.resolve(
875                     (options.splitIndex()
876                             ? DocPaths.INDEX_FILES.resolve(DocPaths.indexN(1))
877                             : DocPaths.INDEX_ALL)),
878                     contents.indexLabel, "", "")));
879         }
880     }
881 
addHelpLink(Content tree)882     private void addHelpLink(Content tree) {
883         if (!options.noHelp()) {
884             String helpfile = options.helpFile();
885             DocPath helpfilenm;
886             if (helpfile.isEmpty()) {
887                 helpfilenm = DocPaths.HELP_DOC;
888             } else {
889                 DocFile file = DocFile.createFileForInput(configuration, helpfile);
890                 helpfilenm = DocPath.create(file.getName());
891             }
892             tree.add(HtmlTree.LI(links.createLink(pathToRoot.resolve(helpfilenm),
893                     contents.helpLabel, "", "")));
894         }
895     }
896 
addSearch(Content tree)897     private void addSearch(Content tree) {
898         String searchValueId = "search";
899         String reset = "reset";
900         HtmlTree inputText = HtmlTree.INPUT("text", searchValueId, searchValueId);
901         HtmlTree inputReset = HtmlTree.INPUT(reset, reset, reset);
902         HtmlTree searchDiv = HtmlTree.DIV(HtmlStyle.navListSearch, HtmlTree.LABEL(searchValueId, searchLabel));
903         searchDiv.add(inputText);
904         searchDiv.add(inputReset);
905         tree.add(searchDiv);
906     }
907 
908     /**
909      * Get the navigation content.
910      *
911      * @param posn the position for the navigation bar
912      * @return the navigation contents
913      */
getContent(Position posn)914     public Content getContent(Position posn) {
915         if (options.noNavbar()) {
916             return new ContentBuilder();
917         }
918         Content tree = HtmlTree.NAV();
919 
920         HtmlTree navDiv = new HtmlTree(TagName.DIV);
921         Content skipNavLinks = contents.getContent("doclet.Skip_navigation_links");
922         SectionName navListSection;
923         Content aboutContent;
924         boolean addSearch;
925         switch (posn) {
926             case TOP:
927                 tree.add(Position.TOP.startOfNav());
928                 navDiv.setStyle(HtmlStyle.topNav)
929                         .setId(SectionName.NAVBAR_TOP.getName())
930                         .add(HtmlTree.DIV(HtmlStyle.skipNav,
931                                 links.createLink(SectionName.SKIP_NAVBAR_TOP, skipNavLinks,
932                                         skipNavLinks.toString(), "")));
933                 navListSection = SectionName.NAVBAR_TOP_FIRSTROW;
934                 aboutContent = userHeader;
935                 addSearch = options.createIndex();
936                 break;
937 
938             case BOTTOM:
939                 tree.add(Position.BOTTOM.startOfNav());
940                 navDiv.setStyle(HtmlStyle.bottomNav)
941                         .setId(SectionName.NAVBAR_BOTTOM.getName())
942                         .add(HtmlTree.DIV(HtmlStyle.skipNav,
943                                 links.createLink(SectionName.SKIP_NAVBAR_BOTTOM, skipNavLinks,
944                                         skipNavLinks.toString(), "")));
945                 navListSection = SectionName.NAVBAR_BOTTOM_FIRSTROW;
946                 aboutContent = userFooter;
947                 addSearch = false;
948                 break;
949 
950             default:
951                 throw new Error();
952         }
953 
954         HtmlTree navList = new HtmlTree(TagName.UL)
955                 .setId(navListSection.getName())
956                 .setStyle(HtmlStyle.navList)
957                 .put(HtmlAttr.TITLE, rowListTitle);
958         addMainNavLinks(navList);
959         navDiv.add(navList);
960         Content aboutDiv = HtmlTree.DIV(HtmlStyle.aboutLanguage, aboutContent);
961         navDiv.add(aboutDiv);
962         tree.add(navDiv);
963 
964         HtmlTree subDiv = new HtmlTree(TagName.DIV).setStyle(HtmlStyle.subNav);
965 
966         HtmlTree div = new HtmlTree(TagName.DIV);
967         // Add the summary links if present.
968         HtmlTree ulNavSummary = new HtmlTree(TagName.UL).setStyle(HtmlStyle.subNavList);
969         addSummaryLinks(ulNavSummary);
970         div.add(ulNavSummary);
971         // Add the detail links if present.
972         HtmlTree ulNavDetail = new HtmlTree(TagName.UL).setStyle(HtmlStyle.subNavList);
973         addDetailLinks(ulNavDetail);
974         div.add(ulNavDetail);
975         subDiv.add(div);
976 
977         if (addSearch) {
978             addSearch(subDiv);
979         }
980         tree.add(subDiv);
981 
982         switch (posn) {
983             case TOP:
984                 tree.add(Position.TOP.endOfNav());
985                 tree.add(HtmlTree.SPAN(HtmlStyle.skipNav, EMPTY_COMMENT)
986                         .setId(SectionName.SKIP_NAVBAR_TOP.getName()));
987                 break;
988 
989             case BOTTOM:
990                 tree.add(Position.BOTTOM.endOfNav());
991                 tree.add(HtmlTree.SPAN(HtmlStyle.skipNav, EMPTY_COMMENT)
992                         .setId(SectionName.SKIP_NAVBAR_BOTTOM.getName()));
993         }
994         return tree;
995     }
996 }
997