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