8263507: Improve structure of package summary pages

Reviewed-by: jjg
This commit is contained in:
Hannes Wallnöfer 2021-05-07 10:44:02 +00:00
parent a65021e38c
commit d2b53509c0
40 changed files with 705 additions and 853 deletions

@ -115,13 +115,14 @@ public class AllClassesIndexWriter extends HtmlDocletWriter {
.setHeader(new TableHeader(contents.classLabel, contents.descriptionLabel))
.setColumnStyles(HtmlStyle.colFirst, HtmlStyle.colLast)
.setId(HtmlIds.ALL_CLASSES_TABLE)
.setDefaultTab(resources.getText("doclet.All_Classes"))
.addTab(contents.interfaceSummary, utils::isInterface)
.addTab(contents.classSummary, e -> utils.isOrdinaryClass((TypeElement)e))
.addTab(contents.enumSummary, utils::isEnum)
.addTab(contents.exceptionSummary, e -> utils.isException((TypeElement)e))
.addTab(contents.errorSummary, e -> utils.isError((TypeElement)e))
.addTab(contents.annotationTypeSummary, utils::isAnnotationType);
.setDefaultTab(contents.allClassesAndInterfacesLabel.toString())
.addTab(contents.interfaces.toString(), utils::isInterface)
.addTab(contents.classes.toString(), e -> utils.isOrdinaryClass((TypeElement)e))
.addTab(contents.enums.toString(), utils::isEnum)
.addTab(contents.records.toString(), e -> utils.isRecord((TypeElement)e))
.addTab(contents.exceptions.toString(), e -> utils.isException((TypeElement)e))
.addTab(contents.errors.toString(), e -> utils.isError((TypeElement)e))
.addTab(contents.annotationTypes.toString(), utils::isAnnotationType);
for (Character unicode : indexBuilder.getFirstCharacters()) {
for (IndexItem indexItem : indexBuilder.getItems(unicode)) {
TypeElement typeElement = (TypeElement) indexItem.getElement();

@ -95,7 +95,7 @@ public class AllPackagesIndexWriter extends HtmlDocletWriter {
*/
protected void addPackages(Content content) {
Table table = new Table(HtmlStyle.summaryTable)
.setCaption(Text.of(contents.packageSummary))
.setCaption(Text.of(contents.packageSummaryLabel.toString()))
.setHeader(new TableHeader(contents.packageLabel, contents.descriptionLabel))
.setColumnStyles(HtmlStyle.colFirst, HtmlStyle.colLast);
for (PackageElement pkg : configuration.packages) {

@ -25,6 +25,7 @@
package jdk.javadoc.internal.doclets.formats.html;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Set;
@ -55,6 +56,7 @@ import jdk.javadoc.internal.doclets.toolkit.util.ClassTree;
import jdk.javadoc.internal.doclets.toolkit.util.CommentHelper;
import jdk.javadoc.internal.doclets.toolkit.util.DocFileIOException;
import jdk.javadoc.internal.doclets.toolkit.util.DocPath;
import jdk.javadoc.internal.doclets.toolkit.util.VisibleMemberTable;
/**
* Generate the Class Information Page.
@ -150,7 +152,17 @@ public class ClassWriterImpl extends SubWriterHolderWriter implements ClassWrite
contents.moduleLabel);
return super.getNavBar(pageMode, element)
.setNavLinkModule(linkContent)
.setMemberSummaryBuilder(configuration.getBuilderFactory().getMemberSummaryBuilder(this));
.setSubNavLinks(() -> {
List<Content> list = new ArrayList<>();
VisibleMemberTable vmt = configuration.getVisibleMemberTable(typeElement);
Set<VisibleMemberTable.Kind> summarySet =
VisibleMemberTable.Kind.forSummariesOf(element.getKind());
for (VisibleMemberTable.Kind kind : summarySet) {
list.add(links.createLink(HtmlIds.forMemberSummary(kind),
contents.getNavLinkLabelContent(kind), vmt.hasVisibleMembers(kind)));
}
return list;
});
}
@Override

@ -36,7 +36,6 @@ import jdk.javadoc.internal.doclets.formats.html.markup.Entity;
import jdk.javadoc.internal.doclets.formats.html.markup.Text;
import jdk.javadoc.internal.doclets.toolkit.Content;
import jdk.javadoc.internal.doclets.toolkit.Resources;
import jdk.javadoc.internal.doclets.toolkit.util.DocletConstants;
import jdk.javadoc.internal.doclets.toolkit.util.VisibleMemberTable;
@ -53,6 +52,7 @@ import jdk.javadoc.internal.doclets.toolkit.util.VisibleMemberTable;
public class Contents {
public final Content allClassesLabel;
public final Content allClassesAndInterfacesLabel;
public final Content allImplementedInterfacesLabel;
public final Content allModulesLabel;
public final Content allPackagesLabel;
@ -128,13 +128,14 @@ public class Contents {
public final Content navAnnotationTypeMember;
public final Content navAnnotationTypeOptionalMember;
public final Content navAnnotationTypeRequiredMember;
public final Content navClassesAndInterfaces;
public final Content navConstructor;
public final Content navDescription;
public final Content navEnum;
public final Content navField;
public final Content navHelpNavigation;
public final Content navHelpPages;
public final Content navMethod;
public final Content navModuleDescription;
public final Content navModules;
public final Content navNested;
public final Content navPackages;
@ -150,6 +151,8 @@ public class Contents {
public final Content packageLabel;
public final Content package_;
public final Content packagesLabel;
public final Content packageSubNavLabel;
public final Content packageSummaryLabel;
public final Content parameters;
public final Content previewAPI;
public final Content previewLabel;
@ -159,7 +162,7 @@ public class Contents {
public final Content propertyLabel;
public final Content propertyDetailsLabel;
public final Content propertySummaryLabel;
public final Content record;
public final Content records;
public final Content recordComponents;
public final Content referencedIn;
public final Content relatedPackages;
@ -182,15 +185,6 @@ public class Contents {
private final EnumMap<VisibleMemberTable.Kind, Content> navLinkLabels;
public final String annotationTypeSummary;
public final String classSummary;
public final String enumSummary;
public final String errorSummary;
public final String exceptionSummary;
public final String interfaceSummary;
public final String packageSummary;
public final String recordSummary;
private final Resources resources;
/**
@ -203,6 +197,7 @@ public class Contents {
this.resources = configuration.getDocResources();
allClassesLabel = getNonBreakResource("doclet.All_Classes");
this.allClassesAndInterfacesLabel = getContent("doclet.All_Classes_And_Interfaces");
allImplementedInterfacesLabel = getContent("doclet.All_Implemented_Interfaces");
allModulesLabel = getNonBreakResource("doclet.All_Modules");
allPackagesLabel = getNonBreakResource("doclet.All_Packages");
@ -278,13 +273,14 @@ public class Contents {
navAnnotationTypeMember = getContent("doclet.navAnnotationTypeMember");
navAnnotationTypeOptionalMember = getContent("doclet.navAnnotationTypeOptionalMember");
navAnnotationTypeRequiredMember = getContent("doclet.navAnnotationTypeRequiredMember");
navClassesAndInterfaces = getContent("doclet.navClassesAndInterfaces");
navConstructor = getContent("doclet.navConstructor");
navEnum = getContent("doclet.navEnum");
navField = getContent("doclet.navField");
navHelpNavigation = getContent("doclet.navNavigation");
navHelpPages = getContent("doclet.navPages");
navMethod = getContent("doclet.navMethod");
navModuleDescription = getContent("doclet.navModuleDescription");
navDescription = getContent("doclet.navDescription");
navModules = getContent("doclet.navModules");
navNested = getContent("doclet.navNested");
navPackages = getContent("doclet.navPackages");
@ -300,6 +296,8 @@ public class Contents {
packageLabel = getContent("doclet.Package");
package_ = getContent("doclet.package");
packagesLabel = getContent("doclet.Packages");
packageSubNavLabel = getContent("doclet.Package_Sub_Nav");
this.packageSummaryLabel = getContent("doclet.Package_Summary");
parameters = getContent("doclet.Parameters");
previewAPI = getContent("doclet.Preview_API");
previewLabel = getContent("doclet.Preview_Label");
@ -309,7 +307,7 @@ public class Contents {
propertyLabel = getContent("doclet.Property");
propertyDetailsLabel = getContent("doclet.Property_Detail");
propertySummaryLabel = getContent("doclet.Property_Summary");
record = getContent("doclet.RecordClass");
records = getContent("doclet.RecordClasses");
recordComponents = getContent("doclet.RecordComponents");
referencedIn = getContent("doclet.ReferencedIn");
relatedPackages = getContent("doclet.Related_Packages");
@ -331,20 +329,15 @@ public class Contents {
valueLabel = getContent("doclet.Value");
navLinkLabels = new EnumMap<>(VisibleMemberTable.Kind.class);
navLinkLabels.put(VisibleMemberTable.Kind.INNER_CLASSES, getContent("doclet.navNested"));
navLinkLabels.put(VisibleMemberTable.Kind.NESTED_CLASSES, getContent("doclet.navNested"));
navLinkLabels.put(VisibleMemberTable.Kind.ENUM_CONSTANTS, getContent("doclet.navEnum"));
navLinkLabels.put(VisibleMemberTable.Kind.FIELDS, getContent("doclet.navField"));
navLinkLabels.put(VisibleMemberTable.Kind.CONSTRUCTORS, getContent("doclet.navConstructor"));
navLinkLabels.put(VisibleMemberTable.Kind.METHODS, getContent("doclet.navMethod"));
this.annotationTypeSummary = resources.getText("doclet.Annotation_Types_Summary");
this.classSummary = resources.getText("doclet.Class_Summary");
this.enumSummary = resources.getText("doclet.Enum_Summary");
this.errorSummary = resources.getText("doclet.Error_Summary");
this.exceptionSummary = resources.getText("doclet.Exception_Summary");
this.interfaceSummary = resources.getText("doclet.Interface_Summary");
this.packageSummary = resources.getText("doclet.Package_Summary");
this.recordSummary = resources.getText("doclet.Record_Class_Summary");
navLinkLabels.put(VisibleMemberTable.Kind.ANNOTATION_TYPE_MEMBER_OPTIONAL,
getContent("doclet.navAnnotationTypeOptionalMember"));
navLinkLabels.put(VisibleMemberTable.Kind.ANNOTATION_TYPE_MEMBER_REQUIRED,
getContent("doclet.navAnnotationTypeRequiredMember"));
}
/**

@ -26,6 +26,7 @@
package jdk.javadoc.internal.doclets.formats.html;
import java.util.List;
import javax.lang.model.element.Element;
import jdk.javadoc.internal.doclets.formats.html.markup.BodyContents;
import jdk.javadoc.internal.doclets.formats.html.markup.ContentBuilder;
@ -143,6 +144,15 @@ public class HelpWriter extends HtmlDocletWriter {
getContent("doclet.help.footnote")));
}
@Override
protected Navigation getNavBar(PageMode pageMode, Element element) {
return super.getNavBar(pageMode, element)
.setSubNavLinks(() -> List.of(
links.createLink(HtmlIds.HELP_NAVIGATION, contents.navHelpNavigation),
links.createLink(HtmlIds.HELP_PAGES, contents.navHelpPages))
);
}
/**
* Creates the navigation help, adding an entry into the main table-of-contents.
*

@ -139,8 +139,6 @@ public class HtmlDoclet extends AbstractDoclet {
{ "doclet.help.annotation_type.description", "doclet.help.annotation_interface.description" },
// in doclets.properties
{ "doclet.Annotation_Types_Summary", "doclet.Annotation_Interfaces_Summary" },
{ "doclet.Enum_Summary", "doclet.Enum_Class_Summary" },
{ "doclet.Enums", "doclet.EnumClasses" },
{ "doclet.AnnotationType", "doclet.AnnotationInterface" },
{ "doclet.AnnotationTypes", "doclet.AnnotationInterfaces" },

@ -42,6 +42,7 @@ import javax.lang.model.util.SimpleTypeVisitor9;
import jdk.javadoc.internal.doclets.formats.html.markup.HtmlId;
import jdk.javadoc.internal.doclets.toolkit.util.SummaryAPIListBuilder;
import jdk.javadoc.internal.doclets.toolkit.util.Utils;
import jdk.javadoc.internal.doclets.toolkit.util.VisibleMemberTable;
/**
* Centralized constants and factory methods for HTML ids.
@ -72,6 +73,7 @@ public class HtmlIds {
static final HtmlId ANNOTATION_TYPE_OPTIONAL_ELEMENT_SUMMARY = HtmlId.of("annotation-interface-optional-element-summary");
static final HtmlId ANNOTATION_TYPE_REQUIRED_ELEMENT_SUMMARY = HtmlId.of("annotation-interface-required-element-summary");
static final HtmlId CLASS_DESCRIPTION = HtmlId.of("class-description");
static final HtmlId CLASS_SUMMARY = HtmlId.of("class-summary");
static final HtmlId CONSTRUCTOR_DETAIL = HtmlId.of("constructor-detail");
static final HtmlId CONSTRUCTOR_SUMMARY = HtmlId.of("constructor-summary");
static final HtmlId ENUM_CONSTANT_DETAIL = HtmlId.of("enum-constant-detail");
@ -95,6 +97,7 @@ public class HtmlIds {
static final HtmlId PACKAGE_SUMMARY_TABLE = HtmlId.of("package-summary-table");
static final HtmlId PROPERTY_DETAIL = HtmlId.of("property-detail");
static final HtmlId PROPERTY_SUMMARY = HtmlId.of("property-summary");
static final HtmlId RELATED_PACKAGE_SUMMARY = HtmlId.of("related-package-summary");
static final HtmlId RESET_BUTTON = HtmlId.of("reset-button");
static final HtmlId SEARCH_INPUT = HtmlId.of("search-input");
static final HtmlId SERVICES = HtmlId.of("services-summary");
@ -424,6 +427,26 @@ public class HtmlIds {
});
}
/**
* Returns an id for the member summary table of the given {@code kind} in a class page.
*
* @param kind the kind of member
*
* @return the id
*/
static HtmlId forMemberSummary(VisibleMemberTable.Kind kind) {
return switch (kind) {
case NESTED_CLASSES -> NESTED_CLASS_SUMMARY;
case ENUM_CONSTANTS -> ENUM_CONSTANT_SUMMARY;
case FIELDS -> FIELD_SUMMARY;
case CONSTRUCTORS -> CONSTRUCTOR_SUMMARY;
case METHODS -> METHOD_SUMMARY;
case ANNOTATION_TYPE_MEMBER_OPTIONAL -> ANNOTATION_TYPE_OPTIONAL_ELEMENT_SUMMARY;
case ANNOTATION_TYPE_MEMBER_REQUIRED -> ANNOTATION_TYPE_REQUIRED_ELEMENT_SUMMARY;
case PROPERTIES -> PROPERTY_SUMMARY;
};
}
/**
* Returns an id for a "tab" in a table.
*

@ -197,11 +197,16 @@ public class ModuleWriterImpl extends HtmlDocletWriter implements ModuleSummaryW
@Override
protected Navigation getNavBar(PageMode pageMode, Element element) {
return super.getNavBar(pageMode, element)
.setDisplaySummaryModuleDescLink(!utils.getFullBody(mdle).isEmpty() && !options.noComment())
.setDisplaySummaryModulesLink(display(requires) || display(indirectModules))
.setDisplaySummaryPackagesLink(display(packages) || display(indirectPackages)
|| display(indirectOpenPackages))
.setDisplaySummaryServicesLink(displayServices(uses, usesTrees) || displayServices(provides.keySet(), providesTrees));
.setSubNavLinks(() -> List.of(
links.createLink(HtmlIds.MODULE_DESCRIPTION, contents.navDescription,
!utils.getFullBody(mdle).isEmpty() && !options.noComment()),
links.createLink(HtmlIds.MODULES, contents.navModules,
display(requires) || display(indirectModules)),
links.createLink(HtmlIds.PACKAGES, contents.navPackages,
display(packages) || display(indirectPackages) || display(indirectOpenPackages)),
links.createLink(HtmlIds.SERVICES, contents.navServices,
displayServices(uses, usesTrees) || displayServices(provides.keySet(), providesTrees))
));
}
/**

@ -27,7 +27,6 @@ package jdk.javadoc.internal.doclets.formats.html;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.SortedSet;
import javax.lang.model.element.Element;
import javax.lang.model.element.ElementKind;
@ -35,7 +34,6 @@ import javax.lang.model.element.ModuleElement;
import javax.lang.model.element.PackageElement;
import javax.lang.model.element.TypeElement;
import jdk.javadoc.internal.doclets.formats.html.markup.Comment;
import jdk.javadoc.internal.doclets.formats.html.markup.ContentBuilder;
import jdk.javadoc.internal.doclets.formats.html.markup.Entity;
import jdk.javadoc.internal.doclets.formats.html.markup.HtmlAttr;
@ -43,8 +41,8 @@ import jdk.javadoc.internal.doclets.formats.html.markup.HtmlStyle;
import jdk.javadoc.internal.doclets.formats.html.markup.TagName;
import jdk.javadoc.internal.doclets.formats.html.markup.HtmlTree;
import jdk.javadoc.internal.doclets.formats.html.markup.Links;
import jdk.javadoc.internal.doclets.formats.html.markup.Text;
import jdk.javadoc.internal.doclets.toolkit.Content;
import jdk.javadoc.internal.doclets.toolkit.builders.MemberSummaryBuilder;
import jdk.javadoc.internal.doclets.toolkit.util.DocFile;
import jdk.javadoc.internal.doclets.toolkit.util.DocLink;
import jdk.javadoc.internal.doclets.toolkit.util.DocPath;
@ -75,14 +73,10 @@ public class Navigation {
private Content navLinkModule;
private Content navLinkPackage;
private Content navLinkClass;
private MemberSummaryBuilder memberSummaryBuilder;
private boolean displaySummaryModuleDescLink;
private boolean displaySummaryModulesLink;
private boolean displaySummaryPackagesLink;
private boolean displaySummaryServicesLink;
private Content userHeader;
private final String rowListTitle;
private final Content searchLabel;
private SubNavLinks subNavLinks;
public enum PageMode {
ALL_CLASSES,
@ -103,6 +97,18 @@ public class Navigation {
USE;
}
/**
* An interface to provide links for the sub-navigation area.
*/
public interface SubNavLinks {
/**
* {@return a list of links to display in the sub-navigation area}
* Links should be wrapped in {@code HtmlTree.LI} elements as they are
* displayed within an unordered list.
*/
List<Content> getSubNavLinks();
}
/**
* Creates a {@code Navigation} object for a specific file, to be written in a specific HTML
* version.
@ -141,36 +147,16 @@ public class Navigation {
return this;
}
public Navigation setMemberSummaryBuilder(MemberSummaryBuilder memberSummaryBuilder) {
this.memberSummaryBuilder = memberSummaryBuilder;
return this;
}
public Navigation setDisplaySummaryModuleDescLink(boolean displaySummaryModuleDescLink) {
this.displaySummaryModuleDescLink = displaySummaryModuleDescLink;
return this;
}
public Navigation setDisplaySummaryModulesLink(boolean displaySummaryModulesLink) {
this.displaySummaryModulesLink = displaySummaryModulesLink;
return this;
}
public Navigation setDisplaySummaryPackagesLink(boolean displaySummaryPackagesLink) {
this.displaySummaryPackagesLink = displaySummaryPackagesLink;
return this;
}
public Navigation setDisplaySummaryServicesLink(boolean displaySummaryServicesLink) {
this.displaySummaryServicesLink = displaySummaryServicesLink;
return this;
}
public Navigation setUserHeader(Content userHeader) {
this.userHeader = userHeader;
return this;
}
public Navigation setSubNavLinks(SubNavLinks subNavLinks) {
this.subNavLinks = subNavLinks;
return this;
}
/**
* Adds the links for the main navigation.
*
@ -350,250 +336,20 @@ public class Navigation {
* @param tree the content tree to which the sub-navigation will added
*/
private void addSummaryLinks(Content tree) {
List<Content> listContents = new ArrayList<>();
switch (documentedPage) {
case CLASS:
if (element.getKind() == ElementKind.ANNOTATION_TYPE) {
addAnnotationTypeSummaryLink("doclet.navField",
FIELDS, listContents);
addAnnotationTypeSummaryLink("doclet.navAnnotationTypeRequiredMember",
ANNOTATION_TYPE_MEMBER_REQUIRED, listContents);
addAnnotationTypeSummaryLink("doclet.navAnnotationTypeOptionalMember",
ANNOTATION_TYPE_MEMBER_OPTIONAL, listContents);
} else {
TypeElement typeElement = (TypeElement) element;
for (VisibleMemberTable.Kind kind : summarySet) {
if (kind == ENUM_CONSTANTS && !configuration.utils.isEnum(typeElement)) {
continue;
}
if (kind == CONSTRUCTORS && configuration.utils.isEnum(typeElement)) {
continue;
}
AbstractMemberWriter writer
= ((AbstractMemberWriter) memberSummaryBuilder.getMemberSummaryWriter(kind));
if (writer == null) {
addContentToList(listContents, contents.getNavLinkLabelContent(kind));
} else {
addTypeSummaryLink(memberSummaryBuilder.members(kind),
memberSummaryBuilder.getVisibleMemberTable(),
kind, listContents);
}
}
}
case MODULE, PACKAGE, CLASS, HELP -> {
List<? extends Content> listContents = subNavLinks.getSubNavLinks()
.stream().map(HtmlTree::LI).toList();
if (!listContents.isEmpty()) {
Content li = HtmlTree.LI(contents.summaryLabel);
li.add(Entity.NO_BREAK_SPACE);
tree.add(li);
tree.add(HtmlTree.LI(switch (documentedPage) {
case MODULE -> contents.moduleSubNavLabel;
case PACKAGE -> contents.packageSubNavLabel;
case CLASS -> contents.summaryLabel;
case HELP -> contents.helpSubNavLabel;
default -> Text.EMPTY;
}).add(Entity.NO_BREAK_SPACE));
addListToNav(listContents, tree);
}
break;
case MODULE:
if (displaySummaryModuleDescLink) {
addContentToList(listContents,
links.createLink(HtmlIds.MODULE_DESCRIPTION, contents.navModuleDescription));
} else {
addContentToList(listContents, contents.navModuleDescription);
}
if (displaySummaryModulesLink) {
addContentToList(listContents,
links.createLink(HtmlIds.MODULES, contents.navModules));
} else {
addContentToList(listContents, contents.navModules);
}
if (displaySummaryPackagesLink) {
addContentToList(listContents,
links.createLink(HtmlIds.PACKAGES, contents.navPackages));
} else {
addContentToList(listContents, contents.navPackages);
}
if (displaySummaryServicesLink) {
addContentToList(listContents,
links.createLink(HtmlIds.SERVICES, contents.navServices));
} else {
addContentToList(listContents, contents.navServices);
}
if (!listContents.isEmpty()) {
Content li = HtmlTree.LI(contents.moduleSubNavLabel);
li.add(Entity.NO_BREAK_SPACE);
tree.add(li);
addListToNav(listContents, tree);
}
break;
case HELP:
addContentToList(listContents,
links.createLink(HtmlIds.HELP_NAVIGATION, contents.navHelpNavigation));
addContentToList(listContents,
links.createLink(HtmlIds.HELP_PAGES, contents.navHelpPages));
Content li = HtmlTree.LI(contents.helpSubNavLabel);
li.add(Entity.NO_BREAK_SPACE);
tree.add(li);
addListToNav(listContents, tree);
break;
default:
break;
}
}
/**
* Adds the navigation summary link.
*
* @param members members to be linked
* @param vmt the visible member table
* @param kind the visible member kind
* @param listContents the list of contents
*/
private void addTypeSummaryLink(SortedSet<? extends Element> members,
VisibleMemberTable vmt,
VisibleMemberTable.Kind kind, List<Content> listContents) {
if (!members.isEmpty()) {
addTypeSummaryLink(null, kind, true, listContents);
return;
}
Set<TypeElement> visibleClasses = vmt.getVisibleTypeElements();
for (TypeElement t : visibleClasses) {
if (configuration.getVisibleMemberTable(t).hasVisibleMembers(kind)) {
addTypeSummaryLink(null, kind, true, listContents);
return;
}
}
addTypeSummaryLink(null, kind, false, listContents);
}
/**
* Adds the navigation Type summary link.
*
* @param typeElement the Type being documented
* @param kind the kind of member being documented
* @param link true if the members are listed and need to be linked
* @param listContents the list of contents to which the summary will be added
*/
private void addTypeSummaryLink(TypeElement typeElement, VisibleMemberTable.Kind kind, boolean link,
List<Content> listContents) {
switch (kind) {
case CONSTRUCTORS:
if (link) {
addContentToList(listContents,
links.createLink(HtmlIds.CONSTRUCTOR_SUMMARY, contents.navConstructor));
} else {
addContentToList(listContents, contents.navConstructor);
}
break;
case ENUM_CONSTANTS:
if (link) {
if (typeElement == null) {
addContentToList(listContents,
links.createLink(HtmlIds.ENUM_CONSTANT_SUMMARY, contents.navEnum));
} else {
addContentToList(listContents,
links.createLink( htmlIds.forInheritedEnumConstants(typeElement), contents.navEnum));
}
} else {
addContentToList(listContents, contents.navEnum);
}
break;
case FIELDS:
if (link) {
if (typeElement == null) {
addContentToList(listContents,
links.createLink(HtmlIds.FIELD_SUMMARY, contents.navField));
} else {
addContentToList(listContents,
links.createLink(htmlIds.forInheritedFields(typeElement), contents.navField));
}
} else {
addContentToList(listContents, contents.navField);
}
break;
case METHODS:
if (link) {
if (typeElement == null) {
addContentToList(listContents,
links.createLink(HtmlIds.METHOD_SUMMARY, contents.navMethod));
} else {
addContentToList(listContents,
links.createLink(htmlIds.forInheritedMethods(typeElement), contents.navMethod));
}
} else {
addContentToList(listContents, contents.navMethod);
}
break;
case INNER_CLASSES:
if (link) {
if (typeElement == null) {
addContentToList(listContents,
links.createLink(HtmlIds.NESTED_CLASS_SUMMARY, contents.navNested));
} else {
addContentToList(listContents,
links.createLink(htmlIds.forInheritedClasses(typeElement), contents.navNested));
}
} else {
addContentToList(listContents, contents.navNested);
}
break;
case PROPERTIES:
if (link) {
if (typeElement == null) {
addContentToList(listContents,
links.createLink(HtmlIds.PROPERTY_SUMMARY, contents.navProperty));
} else {
addContentToList(listContents,
links.createLink(htmlIds.forInheritedProperties(typeElement), contents.navProperty));
}
} else {
addContentToList(listContents, contents.navProperty);
}
break;
default:
break;
}
}
/**
* Adds the navigation Type summary link.
*
* @param label the label to be added
* @param kind the kind of member being documented
* @param listContents the list of contents to which the summary will be added
*/
private void addAnnotationTypeSummaryLink(String label, VisibleMemberTable.Kind kind, List<Content> listContents) {
AbstractMemberWriter writer = ((AbstractMemberWriter) memberSummaryBuilder.
getMemberSummaryWriter(kind));
if (writer == null) {
addContentToList(listContents, contents.getContent(label));
} else {
boolean link = memberSummaryBuilder.getVisibleMemberTable().hasVisibleMembers(kind);
switch (kind) {
case FIELDS:
if (link) {
addContentToList(listContents, links.createLink(HtmlIds.FIELD_SUMMARY,
contents.navField));
} else {
addContentToList(listContents, contents.navField);
}
break;
case ANNOTATION_TYPE_MEMBER_REQUIRED:
if (link) {
addContentToList(listContents, links.createLink(
HtmlIds.ANNOTATION_TYPE_REQUIRED_ELEMENT_SUMMARY,
contents.navAnnotationTypeRequiredMember));
} else {
addContentToList(listContents, contents.navAnnotationTypeRequiredMember);
}
break;
case ANNOTATION_TYPE_MEMBER_OPTIONAL:
if (link) {
addContentToList(listContents, links.createLink(
HtmlIds.ANNOTATION_TYPE_OPTIONAL_ELEMENT_SUMMARY,
contents.navAnnotationTypeOptionalMember));
} else {
addContentToList(listContents, contents.navAnnotationTypeOptionalMember);
}
break;
default:
break;
}
}
}
@ -604,39 +360,29 @@ public class Navigation {
* @param tree the content tree to which the links will be added
*/
private void addDetailLinks(Content tree) {
switch (documentedPage) {
case CLASS:
List<Content> listContents = new ArrayList<>();
if (element.getKind() == ElementKind.ANNOTATION_TYPE) {
addAnnotationTypeDetailLink(listContents);
} else {
TypeElement typeElement = (TypeElement) element;
for (VisibleMemberTable.Kind kind : detailSet) {
AbstractMemberWriter writer
= ((AbstractMemberWriter) memberSummaryBuilder.
getMemberSummaryWriter(kind));
if (kind == ENUM_CONSTANTS && !configuration.utils.isEnum(typeElement)) {
continue;
}
if (kind == CONSTRUCTORS && configuration.utils.isEnum(typeElement)) {
continue;
}
if (writer == null) {
addContentToList(listContents, contents.getNavLinkLabelContent(kind));
} else {
addTypeDetailLink(kind, memberSummaryBuilder.hasMembers(kind), listContents);
}
}
if (documentedPage == PageMode.CLASS) {
List<Content> listContents = new ArrayList<>();
VisibleMemberTable vmt = configuration.getVisibleMemberTable((TypeElement) element);
if (element.getKind() == ElementKind.ANNOTATION_TYPE) {
// Handle annotation interfaces separately as required and optional elements
// share a combined details section.
addTypeDetailLink(FIELDS, !vmt.getVisibleMembers(FIELDS).isEmpty(), listContents);
boolean hasAnnotationElements =
!vmt.getVisibleMembers(ANNOTATION_TYPE_MEMBER_OPTIONAL).isEmpty()
|| !vmt.getVisibleMembers(ANNOTATION_TYPE_MEMBER_REQUIRED).isEmpty();
addTypeDetailLink(ANNOTATION_TYPE_MEMBER_REQUIRED, hasAnnotationElements, listContents);
} else {
Set<VisibleMemberTable.Kind> detailSet = VisibleMemberTable.Kind.forDetailsOf(element.getKind());
for (VisibleMemberTable.Kind kind : detailSet) {
addTypeDetailLink(kind, !vmt.getVisibleMembers(kind).isEmpty(), listContents);
}
if (!listContents.isEmpty()) {
Content li = HtmlTree.LI(contents.detailLabel);
li.add(Entity.NO_BREAK_SPACE);
tree.add(li);
addListToNav(listContents, tree);
}
break;
default:
break;
}
if (!listContents.isEmpty()) {
Content li = HtmlTree.LI(contents.detailLabel);
li.add(Entity.NO_BREAK_SPACE);
tree.add(li);
addListToNav(listContents, tree);
}
}
}
@ -648,110 +394,18 @@ public class Navigation {
* @param listContents the list of contents to which the detail will be added.
*/
protected void addTypeDetailLink(VisibleMemberTable.Kind kind, boolean link, List<Content> listContents) {
switch (kind) {
case CONSTRUCTORS:
if (link) {
addContentToList(listContents, links.createLink(HtmlIds.CONSTRUCTOR_DETAIL, contents.navConstructor));
} else {
addContentToList(listContents, contents.navConstructor);
}
break;
case ENUM_CONSTANTS:
if (link) {
addContentToList(listContents, links.createLink(HtmlIds.ENUM_CONSTANT_DETAIL, contents.navEnum));
} else {
addContentToList(listContents, contents.navEnum);
}
break;
case FIELDS:
if (link) {
addContentToList(listContents, links.createLink(HtmlIds.FIELD_DETAIL, contents.navField));
} else {
addContentToList(listContents, contents.navField);
}
break;
case METHODS:
if (link) {
addContentToList(listContents, links.createLink(HtmlIds.METHOD_DETAIL, contents.navMethod));
} else {
addContentToList(listContents, contents.navMethod);
}
break;
case PROPERTIES:
if (link) {
addContentToList(listContents, links.createLink(HtmlIds.PROPERTY_DETAIL, contents.navProperty));
} else {
addContentToList(listContents, contents.navProperty);
}
break;
default:
break;
}
}
/**
* Adds the navigation Annotation Type detail link.
*
* @param listContents the list of contents to which the annotation detail will be added.
*/
protected void addAnnotationTypeDetailLink(List<Content> listContents) {
TypeElement annotationType = (TypeElement) element;
AbstractMemberWriter writerField
= ((AbstractMemberWriter) memberSummaryBuilder.
getMemberSummaryWriter(FIELDS));
AbstractMemberWriter writerOptional
= ((AbstractMemberWriter) memberSummaryBuilder.
getMemberSummaryWriter(ANNOTATION_TYPE_MEMBER_OPTIONAL));
AbstractMemberWriter writerRequired
= ((AbstractMemberWriter) memberSummaryBuilder.
getMemberSummaryWriter(ANNOTATION_TYPE_MEMBER_REQUIRED));
if (writerField != null) {
addAnnotationTypeDetailLink(FIELDS,
!configuration.utils.getFields(annotationType).isEmpty(),
listContents);
} else {
addContentToList(listContents, contents.navField);
}
if (writerOptional != null) {
addAnnotationTypeDetailLink(ANNOTATION_TYPE_MEMBER_OPTIONAL,
!annotationType.getAnnotationMirrors().isEmpty(), listContents);
} else if (writerRequired != null) {
addAnnotationTypeDetailLink(ANNOTATION_TYPE_MEMBER_REQUIRED,
!annotationType.getAnnotationMirrors().isEmpty(), listContents);
} else {
addContentToList(listContents, contents.navAnnotationTypeMember);
}
}
/**
* Adds the navigation Annotation Type detail link.
*
* @param type the kind of member being documented
* @param link true if the member details need to be linked
* @param listContents the list of contents to which the annotation detail will be added.
*/
protected void addAnnotationTypeDetailLink(VisibleMemberTable.Kind type, boolean link, List<Content> listContents) {
switch (type) {
case FIELDS:
if (link) {
addContentToList(listContents,
links.createLink(HtmlIds.FIELD_DETAIL, contents.navField));
} else {
addContentToList(listContents, contents.navField);
}
break;
case ANNOTATION_TYPE_MEMBER_REQUIRED:
case ANNOTATION_TYPE_MEMBER_OPTIONAL:
if (link) {
addContentToList(listContents, links.createLink(HtmlIds.ANNOTATION_TYPE_ELEMENT_DETAIL,
contents.navAnnotationTypeMember));
} else {
addContentToList(listContents, contents.navAnnotationTypeMember);
}
break;
default:
break;
}
addContentToList(listContents, switch (kind) {
case CONSTRUCTORS -> links.createLink(HtmlIds.CONSTRUCTOR_DETAIL, contents.navConstructor, link);
case ENUM_CONSTANTS -> links.createLink(HtmlIds.ENUM_CONSTANT_DETAIL, contents.navEnum, link);
case FIELDS -> links.createLink(HtmlIds.FIELD_DETAIL, contents.navField, link);
case METHODS -> links.createLink(HtmlIds.METHOD_DETAIL, contents.navMethod, link);
case PROPERTIES -> links.createLink(HtmlIds.PROPERTY_DETAIL, contents.navProperty, link);
case ANNOTATION_TYPE_MEMBER_REQUIRED,
ANNOTATION_TYPE_MEMBER_OPTIONAL ->
links.createLink(HtmlIds.ANNOTATION_TYPE_ELEMENT_DETAIL,
contents.navAnnotationTypeMember, link);
default -> Text.EMPTY;
});
}
private void addContentToList(List<Content> listContents, Content tree) {
@ -762,7 +416,7 @@ public class Navigation {
tree.add(HtmlTree.LI(content));
}
private void addListToNav(List<Content> listContents, Content tree) {
private void addListToNav(List<? extends Content> listContents, Content tree) {
int count = 0;
for (Content liContent : listContents) {
if (count < listContents.size() - 1) {

@ -25,8 +25,13 @@
package jdk.javadoc.internal.doclets.formats.html;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.SortedSet;
import java.util.function.Predicate;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
import javax.lang.model.element.Element;
import javax.lang.model.element.ModuleElement;
@ -68,6 +73,9 @@ public class PackageWriterImpl extends HtmlDocletWriter
*/
protected PackageElement packageElement;
private List<PackageElement> relatedPackages;
private SortedSet<TypeElement> allClasses;
/**
* The HTML tree for section tag.
*/
@ -75,6 +83,11 @@ public class PackageWriterImpl extends HtmlDocletWriter
private final BodyContents bodyContents = new BodyContents();
// Maximum number of subpackages and sibling packages to list in related packages table
private final static int MAX_SUBPACKAGES = 20;
private final static int MAX_SIBLING_PACKAGES = 5;
/**
* Constructor to construct PackageWriter object and to generate
* "package-summary.html" file in the respective package directory.
@ -91,6 +104,7 @@ public class PackageWriterImpl extends HtmlDocletWriter
configuration.docPaths.forPackage(packageElement)
.resolve(DocPaths.PACKAGE_SUMMARY));
this.packageElement = packageElement;
computePackageData();
}
@Override
@ -126,12 +140,67 @@ public class PackageWriterImpl extends HtmlDocletWriter
return new ContentBuilder();
}
private void computePackageData() {
relatedPackages = findRelatedPackages();
boolean isSpecified = utils.isSpecified(packageElement);
allClasses = filterClasses(isSpecified
? utils.getAllClasses(packageElement)
: configuration.typeElementCatalog.allClasses(packageElement));
}
private SortedSet<TypeElement> filterClasses(SortedSet<TypeElement> types) {
List<TypeElement> typeList = types
.stream()
.filter(te -> utils.isCoreClass(te) && configuration.isGeneratedDoc(te))
.collect(Collectors.toList());
return utils.filterOutPrivateClasses(typeList, options.javafx());
}
private List<PackageElement> findRelatedPackages() {
String pkgName = packageElement.getQualifiedName().toString();
// always add super package
int lastdot = pkgName.lastIndexOf('.');
String pkgPrefix = lastdot > 0 ? pkgName.substring(0, lastdot) : null;
List<PackageElement> packages = new ArrayList<>(
filterPackages(p -> p.getQualifiedName().toString().equals(pkgPrefix)));
boolean hasSuperPackage = !packages.isEmpty();
// add subpackages unless there are very many of them
Pattern subPattern = Pattern.compile(pkgName.replace(".", "\\.") + "\\.\\w+");
List<PackageElement> subpackages = filterPackages(
p -> subPattern.matcher(p.getQualifiedName().toString()).matches());
if (subpackages.size() <= MAX_SUBPACKAGES) {
packages.addAll(subpackages);
}
// only add sibling packages if there is a non-empty super package, we are beneath threshold,
// and number of siblings is beneath threshold as well
if (hasSuperPackage && pkgPrefix != null && packages.size() <= MAX_SIBLING_PACKAGES) {
Pattern siblingPattern = Pattern.compile(pkgPrefix.replace(".", "\\.") + "\\.\\w+");
List<PackageElement> siblings = filterPackages(
p -> siblingPattern.matcher(p.getQualifiedName().toString()).matches());
if (siblings.size() <= MAX_SIBLING_PACKAGES) {
packages.addAll(siblings);
}
}
return packages;
}
@Override
protected Navigation getNavBar(PageMode pageMode, Element element) {
Content linkContent = getModuleLink(utils.elementUtils.getModuleOf(packageElement),
contents.moduleLabel);
return super.getNavBar(pageMode, element)
.setNavLinkModule(linkContent);
.setNavLinkModule(linkContent)
.setSubNavLinks(() -> List.of(
links.createLink(HtmlIds.PACKAGE_DESCRIPTION, contents.navDescription,
!utils.getFullBody(packageElement).isEmpty() && !options.noComment()),
links.createLink(HtmlIds.RELATED_PACKAGE_SUMMARY, contents.relatedPackages,
relatedPackages != null && !relatedPackages.isEmpty()),
links.createLink(HtmlIds.CLASS_SUMMARY, contents.navClassesAndInterfaces,
allClasses != null && !allClasses.isEmpty())));
}
/**
@ -163,7 +232,7 @@ public class PackageWriterImpl extends HtmlDocletWriter
}
@Override
public void addRelatedPackagesSummary(List<PackageElement> relatedPackages, Content summaryContentTree) {
public void addRelatedPackagesSummary(Content summaryContentTree) {
boolean showModules = configuration.showModules && hasRelatedPackagesInOtherModules(relatedPackages);
TableHeader tableHeader= showModules
? new TableHeader(contents.moduleLabel, contents.packageLabel, contents.descriptionLabel)
@ -172,76 +241,48 @@ public class PackageWriterImpl extends HtmlDocletWriter
summaryContentTree, showModules);
}
@Override
public void addInterfaceSummary(SortedSet<TypeElement> interfaces, Content summaryContentTree) {
TableHeader tableHeader= new TableHeader(contents.interfaceLabel, contents.descriptionLabel);
addClassesSummary(interfaces, contents.interfaceSummary, tableHeader, summaryContentTree);
}
@Override
public void addClassSummary(SortedSet<TypeElement> classes, Content summaryContentTree) {
TableHeader tableHeader= new TableHeader(contents.classLabel, contents.descriptionLabel);
addClassesSummary(classes, contents.classSummary, tableHeader, summaryContentTree);
}
@Override
public void addEnumSummary(SortedSet<TypeElement> enums, Content summaryContentTree) {
TableHeader tableHeader= new TableHeader(contents.enum_, contents.descriptionLabel);
addClassesSummary(enums, contents.enumSummary, tableHeader, summaryContentTree);
}
@Override
public void addRecordSummary(SortedSet<TypeElement> records, Content summaryContentTree) {
TableHeader tableHeader= new TableHeader(contents.record, contents.descriptionLabel);
addClassesSummary(records, contents.recordSummary, tableHeader, summaryContentTree);
}
@Override
public void addExceptionSummary(SortedSet<TypeElement> exceptions, Content summaryContentTree) {
TableHeader tableHeader= new TableHeader(contents.exception, contents.descriptionLabel);
addClassesSummary(exceptions, contents.exceptionSummary, tableHeader, summaryContentTree);
}
@Override
public void addErrorSummary(SortedSet<TypeElement> errors, Content summaryContentTree) {
TableHeader tableHeader= new TableHeader(contents.error, contents.descriptionLabel);
addClassesSummary(errors, contents.errorSummary, tableHeader, summaryContentTree);
}
@Override
public void addAnnotationTypeSummary(SortedSet<TypeElement> annoTypes, Content summaryContentTree) {
TableHeader tableHeader= new TableHeader(contents.annotationType, contents.descriptionLabel);
addClassesSummary(annoTypes, contents.annotationTypeSummary, tableHeader, summaryContentTree);
}
public void addClassesSummary(SortedSet<TypeElement> classes, String label,
TableHeader tableHeader, Content summaryContentTree) {
if(!classes.isEmpty()) {
Table table = new Table(HtmlStyle.summaryTable)
.setCaption(Text.of(label))
.setHeader(tableHeader)
.setColumnStyles(HtmlStyle.colFirst, HtmlStyle.colLast);
for (TypeElement klass : classes) {
if (!utils.isCoreClass(klass) || !configuration.isGeneratedDoc(klass)) {
continue;
}
/**
* Add all types to the content tree.
*
* @param summaryContentTree HtmlTree content to which the links will be added
*/
public void addAllClassesAndInterfacesSummary(Content summaryContentTree) {
Table table = new Table(HtmlStyle.summaryTable)
.setHeader(new TableHeader(contents.classLabel, contents.descriptionLabel))
.setColumnStyles(HtmlStyle.colFirst, HtmlStyle.colLast)
.setId(HtmlIds.CLASS_SUMMARY)
.setDefaultTab(contents.allClassesAndInterfacesLabel.toString())
.addTab(contents.interfaces.toString(), utils::isInterface)
.addTab(contents.classes.toString(), e -> utils.isOrdinaryClass((TypeElement)e))
.addTab(contents.enums.toString(), utils::isEnum)
.addTab(contents.records.toString(), e -> utils.isRecord((TypeElement)e))
.addTab(contents.exceptions.toString(), e -> utils.isException((TypeElement)e))
.addTab(contents.errors.toString(), e -> utils.isError((TypeElement)e))
.addTab(contents.annotationTypes.toString(), utils::isAnnotationType);
for (TypeElement typeElement : allClasses) {
if (typeElement != null && utils.isCoreClass(typeElement)) {
Content classLink = getLink(new HtmlLinkInfo(
configuration, HtmlLinkInfo.Kind.PACKAGE, klass));
configuration, HtmlLinkInfo.Kind.PACKAGE, typeElement));
ContentBuilder description = new ContentBuilder();
addPreviewSummary(klass, description);
if (utils.isDeprecated(klass)) {
description.add(getDeprecatedPhrase(klass));
List<? extends DeprecatedTree> tags = utils.getDeprecatedTrees(klass);
addPreviewSummary(typeElement, description);
if (utils.isDeprecated(typeElement)) {
description.add(getDeprecatedPhrase(typeElement));
List<? extends DeprecatedTree> tags = utils.getDeprecatedTrees(typeElement);
if (!tags.isEmpty()) {
addSummaryDeprecatedComment(klass, tags.get(0), description);
addSummaryDeprecatedComment(typeElement, tags.get(0), description);
}
} else {
addSummaryComment(klass, description);
addSummaryComment(typeElement, description);
}
table.addRow(classLink, description);
table.addRow(typeElement, Arrays.asList(classLink, description));
}
}
if (!table.isEmpty()) {
summaryContentTree.add(HtmlTree.LI(table));
if (table.needsScript()) {
getMainBodyScript().append(table.getScript());
}
}
}
@ -250,6 +291,7 @@ public class PackageWriterImpl extends HtmlDocletWriter
boolean showModules) {
if (!packages.isEmpty()) {
Table table = new Table(HtmlStyle.summaryTable)
.setId(HtmlIds.RELATED_PACKAGE_SUMMARY)
.setCaption(label)
.setHeader(tableHeader);
if (showModules) {
@ -340,4 +382,10 @@ public class PackageWriterImpl extends HtmlDocletWriter
final ModuleElement module = (ModuleElement) packageElement.getEnclosingElement();
return relatedPackages.stream().anyMatch(pkg -> module != pkg.getEnclosingElement());
}
private List<PackageElement> filterPackages(Predicate<? super PackageElement> filter) {
return configuration.packages.stream()
.filter(p -> p != packageElement && filter.test(p))
.collect(Collectors.toList());
}
}

@ -141,7 +141,7 @@ public class WriterFactoryImpl implements WriterFactory {
return getFieldWriter(classWriter);
case PROPERTIES:
return getPropertyWriter(classWriter);
case INNER_CLASSES:
case NESTED_CLASSES:
return new NestedClassWriterImpl((SubWriterHolderWriter)
classWriter, classWriter.getTypeElement());
case METHODS:

@ -54,8 +54,8 @@ public class Links {
/**
* Creates a link of the form {@code <a href="#id">label</a>}.
*
* @param id the position of the link in the file
* @param label the content for the link
* @param id the position of the link in the file
* @param label the content for the link
* @return a content tree for the link
*/
public Content createLink(HtmlId id, Content label) {
@ -63,6 +63,19 @@ public class Links {
return createLink(l, label, "");
}
/**
* Creates a link of the form {@code <a href="#id">label</a>} if {@code link}
* is {@code true}, or else just returns {@code label}.
*
* @param id the position of the link in the file
* @param label the content for the link
* @param link whether to create a link or just return the label
* @return a content tree for the link or just the label
*/
public Content createLink(HtmlId id, Content label, boolean link) {
return link ? createLink(id, label) : label;
}
/**
* Creates a link of the form {@code <a href="#id" title="title">label</a>}.
*

@ -55,7 +55,9 @@ doclet.Summary=Summary:
doclet.Detail=Detail:
doclet.Module_Sub_Nav=Module:
doclet.Help_Sub_Nav=Help:
doclet.navModuleDescription=Description
doclet.Package_Sub_Nav=Package:
doclet.navClassesAndInterfaces=Classes and Interfaces
doclet.navDescription=Description
doclet.navModules=Modules
doclet.navPackages=Packages
doclet.navServices=Services

@ -68,66 +68,16 @@ public interface PackageSummaryWriter {
/**
* Adds the table of related packages to the documentation tree.
*
* @param relatedPackages the interfaces to document.
* @param summaryContentTree the content tree to which the summaries will be added
*/
void addRelatedPackagesSummary(List<PackageElement> relatedPackages, Content summaryContentTree);
void addRelatedPackagesSummary(Content summaryContentTree);
/**
* Adds the table of interfaces to the documentation tree.
* Adds the table of all classes and interfaces to the documentation tree.
*
* @param interfaces the interfaces to document.
* @param summaryContentTree the content tree to which the summaries will be added
*/
void addInterfaceSummary(SortedSet<TypeElement> interfaces, Content summaryContentTree);
/**
* Adds the table of classes to the documentation tree.
*
* @param classes the classes to document.
* @param summaryContentTree the content tree to which the summaries will be added
*/
void addClassSummary(SortedSet<TypeElement> classes, Content summaryContentTree);
/**
* Adds the table of enums to the documentation tree.
*
* @param enums the enums to document.
* @param summaryContentTree the content tree to which the summaries will be added
*/
void addEnumSummary(SortedSet<TypeElement> enums, Content summaryContentTree);
/**
* Adds the table of records to the documentation tree.
*
* @param records the records to document.
* @param summaryContentTree the content tree to which the summaries will be added
*/
void addRecordSummary(SortedSet<TypeElement> records, Content summaryContentTree);
/**
* Adds the table of exceptions to the documentation tree.
*
* @param exceptions the exceptions to document.
* @param summaryContentTree the content tree to which the summaries will be added
*/
void addExceptionSummary(SortedSet<TypeElement> exceptions, Content summaryContentTree);
/**
* Adds the table of errors to the documentation tree.
*
* @param errors the errors to document.
* @param summaryContentTree the content tree to which the summaries will be added
*/
void addErrorSummary(SortedSet<TypeElement> errors, Content summaryContentTree);
/**
* Adds the table of annotation types to the documentation tree.
*
* @param annoTypes the annotation types to document.
* @param summaryContentTree the content tree to which the summaries will be added
*/
void addAnnotationTypeSummary(SortedSet<TypeElement> annoTypes, Content summaryContentTree);
void addAllClassesAndInterfacesSummary(Content summaryContentTree);
/**
* Adds the package description from the "packages.html" file to the documentation

@ -27,7 +27,6 @@ package jdk.javadoc.internal.doclets.toolkit.builders;
import java.text.MessageFormat;
import java.util.*;
import java.util.stream.Collectors;
import javax.lang.model.element.Element;
import javax.lang.model.element.ExecutableElement;
@ -166,15 +165,6 @@ public abstract class MemberSummaryBuilder extends AbstractMemberBuilder {
return out;
}
/**
* Returns true if there are members of the given kind, false otherwise.
* @param kind
* @return true if there are members of the given kind, false otherwise
*/
public boolean hasMembers(VisibleMemberTable.Kind kind) {
return !getVisibleMembers(kind).isEmpty();
}
/**
* Builds the summary for any optional members of an annotation type.
*
@ -231,8 +221,8 @@ public abstract class MemberSummaryBuilder extends AbstractMemberBuilder {
* @param summariesList the list of summaries to which the summary will be added
*/
protected void buildNestedClassesSummary(Content summariesList) {
MemberSummaryWriter writer = memberSummaryWriters.get(INNER_CLASSES);
addSummary(writer, INNER_CLASSES, true, summariesList);
MemberSummaryWriter writer = memberSummaryWriters.get(NESTED_CLASSES);
addSummary(writer, NESTED_CLASSES, true, summariesList);
}
/**

@ -25,16 +25,7 @@
package jdk.javadoc.internal.doclets.toolkit.builders;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.SortedSet;
import java.util.function.Predicate;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
import javax.lang.model.element.PackageElement;
import javax.lang.model.element.TypeElement;
import jdk.javadoc.internal.doclets.toolkit.Content;
import jdk.javadoc.internal.doclets.toolkit.DocFilesHandler;
@ -62,10 +53,6 @@ public class PackageSummaryBuilder extends AbstractBuilder {
*/
private final PackageSummaryWriter packageWriter;
// Maximum number of subpackages and sibling packages to list in related packages table
private final static int MAX_SUBPACKAGES = 20;
private final static int MAX_SIBLING_PACKAGES = 5;
/**
* Construct a new PackageSummaryBuilder.
*
@ -156,13 +143,7 @@ public class PackageSummaryBuilder extends AbstractBuilder {
Content summariesList = packageWriter.getSummariesList();
buildRelatedPackagesSummary(summariesList);
buildInterfaceSummary(summariesList);
buildClassSummary(summariesList);
buildEnumSummary(summariesList);
buildRecordSummary(summariesList);
buildExceptionSummary(summariesList);
buildErrorSummary(summariesList);
buildAnnotationTypeSummary(summariesList);
buildAllClassesAndInterfacesSummary(summariesList);
packageContentTree.add(packageWriter.getPackageSummary(summariesList));
}
@ -173,121 +154,18 @@ public class PackageSummaryBuilder extends AbstractBuilder {
* @param summariesList the list of summaries to which the summary will be added
*/
protected void buildRelatedPackagesSummary(Content summariesList) {
List<PackageElement> packages = findRelatedPackages();
if (!packages.isEmpty()) {
packageWriter.addRelatedPackagesSummary(packages, summariesList);
}
packageWriter.addRelatedPackagesSummary(summariesList);
}
/**
* Builds the summary for any interfaces in this package.
* Builds the summary for all classes and interfaces in this package.
*
* @param summariesList the list of summaries to which the summary will be added
*/
protected void buildInterfaceSummary(Content summariesList) {
SortedSet<TypeElement> ilist = utils.isSpecified(packageElement)
? utils.getTypeElementsAsSortedSet(utils.getInterfaces(packageElement))
: configuration.typeElementCatalog.interfaces(packageElement);
SortedSet<TypeElement> interfaces = utils.filterOutPrivateClasses(ilist, options.javafx());
if (!interfaces.isEmpty()) {
packageWriter.addInterfaceSummary(interfaces, summariesList);
}
protected void buildAllClassesAndInterfacesSummary(Content summariesList) {
packageWriter.addAllClassesAndInterfacesSummary(summariesList);
}
/**
* Builds the summary for any classes in this package.
*
* @param summariesList the list of summaries to which the summary will be added
*/
protected void buildClassSummary(Content summariesList) {
SortedSet<TypeElement> clist = utils.isSpecified(packageElement)
? utils.getTypeElementsAsSortedSet(utils.getOrdinaryClasses(packageElement))
: configuration.typeElementCatalog.ordinaryClasses(packageElement);
SortedSet<TypeElement> classes = utils.filterOutPrivateClasses(clist, options.javafx());
if (!classes.isEmpty()) {
packageWriter.addClassSummary(classes, summariesList);
}
}
/**
* Builds the summary for the enum types in this package.
*
* @param summariesList the list of summaries to which the summary will be added
*/
protected void buildEnumSummary(Content summariesList) {
SortedSet<TypeElement> elist = utils.isSpecified(packageElement)
? utils.getTypeElementsAsSortedSet(utils.getEnums(packageElement))
: configuration.typeElementCatalog.enums(packageElement);
SortedSet<TypeElement> enums = utils.filterOutPrivateClasses(elist, options.javafx());
if (!enums.isEmpty()) {
packageWriter.addEnumSummary(enums, summariesList);
}
}
/**
* Builds the summary for any record types in this package.
*
* @param summariesList the list of summaries to which the summary will be added
*/
protected void buildRecordSummary(Content summariesList) {
SortedSet<TypeElement> rlist = utils.isSpecified(packageElement)
? utils.getTypeElementsAsSortedSet(utils.getRecords(packageElement))
: configuration.typeElementCatalog.records(packageElement);
SortedSet<TypeElement> records = utils.filterOutPrivateClasses(rlist, options.javafx());
if (!records.isEmpty()) {
packageWriter.addRecordSummary(records, summariesList);
}
}
/**
* Builds the summary for any exception types in this package.
*
* @param summariesList the list of summaries to which the summary will be added
*/
protected void buildExceptionSummary(Content summariesList) {
Set<TypeElement> iexceptions =
utils.isSpecified(packageElement)
? utils.getTypeElementsAsSortedSet(utils.getExceptions(packageElement))
: configuration.typeElementCatalog.exceptions(packageElement);
SortedSet<TypeElement> exceptions = utils.filterOutPrivateClasses(iexceptions,
options.javafx());
if (!exceptions.isEmpty()) {
packageWriter.addExceptionSummary(exceptions, summariesList);
}
}
/**
* Builds the summary for any error types in this package.
*
* @param summariesList the list of summaries to which the summary will be added
*/
protected void buildErrorSummary(Content summariesList) {
Set<TypeElement> ierrors =
utils.isSpecified(packageElement)
? utils.getTypeElementsAsSortedSet(utils.getErrors(packageElement))
: configuration.typeElementCatalog.errors(packageElement);
SortedSet<TypeElement> errors = utils.filterOutPrivateClasses(ierrors, options.javafx());
if (!errors.isEmpty()) {
packageWriter.addErrorSummary(errors, summariesList);
}
}
/**
* Builds the summary for any annotation types in this package.
*
* @param summariesList the list of summaries to which the summary will be added
*/
protected void buildAnnotationTypeSummary(Content summariesList) {
SortedSet<TypeElement> iannotationTypes =
utils.isSpecified(packageElement)
? utils.getTypeElementsAsSortedSet(utils.getAnnotationTypes(packageElement))
: configuration.typeElementCatalog.annotationTypes(packageElement);
SortedSet<TypeElement> annotationTypes = utils.filterOutPrivateClasses(iannotationTypes,
options.javafx());
if (!annotationTypes.isEmpty()) {
packageWriter.addAnnotationTypeSummary(annotationTypes, summariesList);
}
}
/**
* Build the description of the summary.
@ -313,42 +191,4 @@ public class PackageSummaryBuilder extends AbstractBuilder {
}
packageWriter.addPackageTags(packageContentTree);
}
private List<PackageElement> findRelatedPackages() {
String pkgName = packageElement.getQualifiedName().toString();
// always add super package
int lastdot = pkgName.lastIndexOf('.');
String pkgPrefix = lastdot > 0 ? pkgName.substring(0, lastdot) : null;
List<PackageElement> packages = new ArrayList<>(
filterPackages(p -> p.getQualifiedName().toString().equals(pkgPrefix)));
boolean hasSuperPackage = !packages.isEmpty();
// add subpackages unless there are very many of them
Pattern subPattern = Pattern.compile(pkgName.replace(".", "\\.") + "\\.\\w+");
List<PackageElement> subpackages = filterPackages(
p -> subPattern.matcher(p.getQualifiedName().toString()).matches());
if (subpackages.size() <= MAX_SUBPACKAGES) {
packages.addAll(subpackages);
}
// only add sibling packages if there is a non-empty super package, we are beneath threshold,
// and number of siblings is beneath threshold as well
if (hasSuperPackage && pkgPrefix != null && packages.size() <= MAX_SIBLING_PACKAGES) {
Pattern siblingPattern = Pattern.compile(pkgPrefix.replace(".", "\\.") + "\\.\\w+");
List<PackageElement> siblings = filterPackages(
p -> siblingPattern.matcher(p.getQualifiedName().toString()).matches());
if (siblings.size() <= MAX_SIBLING_PACKAGES) {
packages.addAll(siblings);
}
}
return packages;
}
private List<PackageElement> filterPackages(Predicate<? super PackageElement> filter) {
return configuration.packages.stream()
.filter(p -> p != packageElement && filter.test(p))
.toList();
}
}

@ -124,16 +124,7 @@ doclet.Concealed_Packages_Summary=Concealed
doclet.From=From
doclet.Uses_Summary=Uses
doclet.Provides_Summary=Provides
doclet.Interface_Summary=Interface Summary
doclet.Annotation_Types_Summary=Annotation Types Summary
doclet.Annotation_Interfaces_Summary=Annotation Interfaces Summary
doclet.Enum_Summary=Enum Summary
doclet.Enum_Class_Summary=Enum Class Summary
doclet.Exception_Summary=Exception Summary
doclet.Error_Summary=Error Summary
doclet.Class_Summary=Class Summary
doclet.Nested_Class_Summary=Nested Class Summary
doclet.Related_Packages=Related Packages
doclet.Annotation_Type_Optional_Member_Summary=Optional Element Summary
doclet.Annotation_Type_Required_Member_Summary=Required Element Summary
doclet.Field_Summary=Field Summary
@ -141,17 +132,18 @@ doclet.Property_Summary=Property Summary
doclet.Enum_Constant_Summary=Enum Constant Summary
doclet.Constructor_Summary=Constructor Summary
doclet.Method_Summary=Method Summary
doclet.Record_Class_Summary=Record Class Summary
doclet.Interfaces=Interfaces
doclet.Enums=Enums
doclet.EnumClasses=Enum Classes
doclet.RecordClasses=Record Classes
doclet.Related_Packages=Related Packages
doclet.AnnotationTypes=Annotation Types
doclet.AnnotationInterfaces=Annotation Interfaces
doclet.Exceptions=Exceptions
doclet.Errors=Errors
doclet.Classes=Classes
doclet.All_Classes=All Classes
doclet.All_Classes_And_Interfaces=All Classes and Interfaces
doclet.All_Superinterfaces=All Superinterfaces:
doclet.All_Implemented_Interfaces=All Implemented Interfaces:
doclet.Interface=Interface

@ -353,10 +353,10 @@ ul.summary-list > li {
font-weight:bold;
clear:none;
overflow:hidden;
padding:0px;
padding:0;
padding-top:10px;
padding-left:1px;
margin:0px;
margin:0;
white-space:pre;
}
.caption a:link, .caption a:visited {
@ -378,7 +378,10 @@ ul.summary-list > li {
border: none;
height:16px;
}
div.table-tabs {
padding:10px 0 0 1px;
margin:0;
}
div.table-tabs > button {
border: none;
cursor: pointer;

@ -603,7 +603,7 @@ public class Utils {
}
public boolean isOrdinaryClass(TypeElement te) {
if (isEnum(te) || isInterface(te) || isAnnotationType(te)) {
if (isEnum(te) || isInterface(te) || isAnnotationType(te) || isRecord(te)) {
return false;
}
if (isError(te) || isException(te)) {

@ -27,6 +27,7 @@ package jdk.javadoc.internal.doclets.toolkit.util;
import javax.lang.model.element.AnnotationMirror;
import javax.lang.model.element.Element;
import javax.lang.model.element.ElementKind;
import javax.lang.model.element.ExecutableElement;
import javax.lang.model.element.Modifier;
import javax.lang.model.element.TypeElement;
@ -53,7 +54,6 @@ import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.function.Predicate;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import jdk.javadoc.internal.doclets.toolkit.BaseConfiguration;
@ -98,7 +98,7 @@ import jdk.javadoc.internal.doclets.toolkit.PropertyUtils;
public class VisibleMemberTable {
public enum Kind {
INNER_CLASSES,
NESTED_CLASSES,
ENUM_CONSTANTS,
FIELDS,
CONSTRUCTORS,
@ -107,8 +107,38 @@ public class VisibleMemberTable {
ANNOTATION_TYPE_MEMBER_REQUIRED,
PROPERTIES;
public static final EnumSet<Kind> summarySet = EnumSet.range(INNER_CLASSES, METHODS);
public static final EnumSet<Kind> detailSet = EnumSet.range(ENUM_CONSTANTS, METHODS);
private static final EnumSet<Kind> defaultSummarySet = EnumSet.of(
NESTED_CLASSES, FIELDS, CONSTRUCTORS, METHODS);
private static final EnumSet<Kind> enumSummarySet = EnumSet.of(
NESTED_CLASSES, ENUM_CONSTANTS, FIELDS, METHODS);
private static final EnumSet<Kind> annotationSummarySet = EnumSet.of(
FIELDS, ANNOTATION_TYPE_MEMBER_OPTIONAL, ANNOTATION_TYPE_MEMBER_REQUIRED);
private static final EnumSet<Kind> defaultDetailSet = EnumSet.of(
FIELDS, CONSTRUCTORS, METHODS);
private static final EnumSet<Kind> enumDetailSet = EnumSet.of(
ENUM_CONSTANTS, FIELDS, METHODS);
/**
* {@return the set of possible member kinds for the summaries section of a type element}
* @param kind the kind of type element being documented
*/
public static Set<Kind> forSummariesOf(ElementKind kind) {
return switch (kind) {
case ANNOTATION_TYPE -> annotationSummarySet;
case ENUM -> enumSummarySet;
default -> defaultSummarySet;
};
}
/**
* {@return the set of possible member kinds for the details section of a type element}
* @param kind the kind of type element being documented
*/
public static Set<Kind> forDetailsOf(ElementKind kind) {
return kind == ElementKind.ENUM
? enumDetailSet
: defaultDetailSet;
}
}
final TypeElement te;
@ -119,12 +149,12 @@ public class VisibleMemberTable {
final Utils utils;
final VisibleMemberCache mcache;
private List<VisibleMemberTable> allSuperclasses;
private List<VisibleMemberTable> allSuperinterfaces;
private List<VisibleMemberTable> parents;
private final List<VisibleMemberTable> allSuperclasses;
private final List<VisibleMemberTable> allSuperinterfaces;
private final List<VisibleMemberTable> parents;
private Map<Kind, List<Element>> visibleMembers = null;
private Map<ExecutableElement, PropertyMembers> propertyMap = new HashMap<>();
private final Map<ExecutableElement, PropertyMembers> propertyMap = new HashMap<>();
// Keeps track of method overrides
Map<ExecutableElement, OverriddenMethodInfo> overriddenMethodTable
@ -295,7 +325,8 @@ public class VisibleMemberTable {
}
/**
* Returns true if this table contains visible members.
* Returns true if this table contains visible members of
* any kind, including inherited members.
*
* @return true if visible members are present.
*/
@ -394,7 +425,7 @@ public class VisibleMemberTable {
void computeVisibleMembers(LocalMemberTable lmt, Kind kind) {
switch (kind) {
case FIELDS: case INNER_CLASSES:
case FIELDS: case NESTED_CLASSES:
computeVisibleFieldsAndInnerClasses(lmt, kind);
return;
@ -719,7 +750,7 @@ public class VisibleMemberTable {
case ENUM:
case ANNOTATION_TYPE:
case RECORD:
addMember(e, Kind.INNER_CLASSES);
addMember(e, Kind.NESTED_CLASSES);
break;
case FIELD:
addMember(e, Kind.FIELDS);

@ -69,7 +69,7 @@ public class TestHtmlTableStyles extends JavadocTester {
checkOutput("pkg1/package-summary.html", true,
"""
<div class="caption"><span>Class Summary</span></div>
<div class="caption"><span>Classes</span></div>
<div class="summary-table two-column-summary">""");
checkOutput("pkg1/class-use/TestTable.html", true,

@ -84,15 +84,11 @@ public class TestHtmlTableTags extends JavadocTester {
//Package summary
checkOutput("pkg1/package-summary.html", true,
"""
<div class="summary-table two-column-summary">""",
"""
<div class="summary-table two-column-summary">""");
<div class="summary-table two-column-summary" aria-labelledby="class-summary-tab0">""");
checkOutput("pkg2/package-summary.html", true,
"""
<div class="summary-table two-column-summary">""",
"""
<div class="summary-table two-column-summary">""");
<div class="summary-table two-column-summary" aria-labelledby="class-summary-tab0">""");
// Class documentation
checkOutput("pkg1/C1.html", true,
@ -306,15 +302,38 @@ public class TestHtmlTableTags extends JavadocTester {
//Package summary
checkOutput("pkg1/package-summary.html", true,
"""
<div class="caption"><span>Class Summary</span></div>""",
"""
<div class="caption"><span>Interface Summary</span></div>""");
<div class="table-tabs" role="tablist" aria-orientation="horizontal"><button id=\
"class-summary-tab0" role="tab" aria-selected="true" aria-controls="class-summar\
y.tabpanel" tabindex="0" onkeydown="switchTab(event)" onclick="show('class-summa\
ry', 'class-summary', 2)" class="active-table-tab">All Classes and Interfaces</b\
utton>\
<button id="class-summary-tab1" role="tab" aria-selected="false" aria-controls="\
class-summary.tabpanel" tabindex="-1" onkeydown="switchTab(event)" onclick="show\
('class-summary', 'class-summary-tab1', 2)" class="table-tab">Interfaces</button\
>\
<button id="class-summary-tab2" role="tab" aria-selected="false" aria-controls="\
class-summary.tabpanel" tabindex="-1" onkeydown="switchTab(event)" onclick="show\
('class-summary', 'class-summary-tab2', 2)" class="table-tab">Classes</button></\
div>""");
checkOutput("pkg2/package-summary.html", true,
"""
<div class="caption"><span>Enum Class Summary</span></div>""",
"""
<div class="caption"><span>Annotation Interfaces Summary</span></div>""");
<div class="table-tabs" role="tablist" aria-orientation="horizontal"><button id=\
"class-summary-tab0" role="tab" aria-selected="true" aria-controls="class-summar\
y.tabpanel" tabindex="0" onkeydown="switchTab(event)" onclick="show('class-summa\
ry', 'class-summary', 2)" class="active-table-tab">All Classes and Interfaces</b\
utton>\
<button id="class-summary-tab2" role="tab" aria-selected="false" aria-controls="\
class-summary.tabpanel" tabindex="-1" onkeydown="switchTab(event)" onclick="show\
('class-summary', 'class-summary-tab2', 2)" class="table-tab">Classes</button>\
<button id="class-summary-tab3" role="tab" aria-selected="false" aria-controls="\
class-summary.tabpanel" tabindex="-1" onkeydown="switchTab(event)" onclick="show\
('class-summary', 'class-summary-tab3', 2)" class="table-tab">Enum Classes</butt\
on>\
<button id="class-summary-tab7" role="tab" aria-selected="false" aria-controls="\
class-summary.tabpanel" tabindex="-1" onkeydown="switchTab(event)" onclick="show\
('class-summary', 'class-summary-tab7', 2)" class="table-tab">Annotation Interfa\
ces</button></div>""");
// Class documentation
checkOutput("pkg1/C1.html", true,
@ -427,17 +446,11 @@ public class TestHtmlTableTags extends JavadocTester {
checkOutput("pkg1/package-summary.html", true,
"""
<div class="table-header col-first">Class</div>
<div class="table-header col-last">Description</div>""",
"""
<div class="table-header col-first">Interface</div>
<div class="table-header col-last">Description</div>""");
checkOutput("pkg2/package-summary.html", true,
"""
<div class="table-header col-first">Enum Class</div>
<div class="table-header col-last">Description</div>""",
"""
<div class="table-header col-first">Annotation Interface</div>
<div class="table-header col-first">Class</div>
<div class="table-header col-last">Description</div>""");
// Class documentation
@ -559,26 +572,29 @@ public class TestHtmlTableTags extends JavadocTester {
//Package summary
checkOutput("pkg1/package-summary.html", true,
"""
<div class="col-first even-row-color"><a href="I1.html" title="interface in pkg1">I1</a></div>
<div class="col-last even-row-color">
<div class="col-first odd-row-color class-summary class-summary-tab1"><a \
href="I1.html" title="interface in pkg1">I1</a></div>
<div class="col-last odd-row-color class-summary class-summary-tab1">
<div class="block">A sample interface used to test table tags.</div>
</div>""",
"""
<div class="col-first even-row-color"><a href="C1.html" title="class in pkg1">C1</a></div>
<div class="col-last even-row-color">
<div class="col-first even-row-color class-summary class-summary-tab2"><a\
href="C1.html" title="class in pkg1">C1</a></div>
<div class="col-last even-row-color class-summary class-summary-tab2">
<div class="block">A test class.</div>
</div>""");
checkOutput("pkg2/package-summary.html", true,
"""
<div class="col-first even-row-color"><a href="C2.ModalExclusionType.html" title\
="enum class in pkg2">C2.ModalExclusionType</a></div>
<div class="col-last even-row-color">
<div class="col-first odd-row-color class-summary class-summary-tab3"><a \
href="C2.ModalExclusionType.html" title="enum class in pkg2">C2.ModalExclusionType</a></div>
<div class="col-last odd-row-color class-summary class-summary-tab3">
<div class="block">A sample enum.</div>
</div>""",
"""
<div class="col-first even-row-color"><a href="C3.html" title="annotation interface in pkg2">C3</a></div>
<div class="col-last even-row-color">
<div class="col-first even-row-color class-summary class-summary-tab7"><a\
href="C3.html" title="annotation interface in pkg2">C3</a></div>
<div class="col-last even-row-color class-summary class-summary-tab7">
<div class="block">Test Annotation class.</div>
</div>""");
@ -723,20 +739,24 @@ public class TestHtmlTableTags extends JavadocTester {
//Package summary
checkOutput("pkg1/package-summary.html", true,
"""
<div class="col-first even-row-color"><a href="I1.html" title="interface in pkg1">I1</a></div>
<div class="col-last even-row-color"></div>""",
<div class="col-first odd-row-color class-summary class-summary-tab1"><a \
href="I1.html" title="interface in pkg1">I1</a></div>
<div class="col-last odd-row-color class-summary class-summary-tab1"></div>""",
"""
<div class="col-first even-row-color"><a href="C1.html" title="class in pkg1">C1</a></div>
<div class="col-last even-row-color"></div>""");
<div class="col-first even-row-color class-summary class-summary-tab2"><a\
href="C1.html" title="class in pkg1">C1</a></div>
<div class="col-last even-row-color class-summary class-summary-tab2"></div>""");
checkOutput("pkg2/package-summary.html", true,
"""
<div class="col-first even-row-color"><a href="C2.ModalExclusionType.html" title\
="enum class in pkg2">C2.ModalExclusionType</a></div>
<div class="col-last even-row-color"></div>""",
<div class="col-first odd-row-color class-summary class-summary-tab3"><a \
href="C2.ModalExclusionType.html" title="enum class in pkg2">C2.ModalExclusionTyp\
e</a></div>
<div class="col-last odd-row-color class-summary class-summary-tab3"></div>""",
"""
<div class="col-first even-row-color"><a href="C3.html" title="annotation interface in pkg2">C3</a></div>
<div class="col-last even-row-color"></div>""");
<div class="col-first even-row-color class-summary class-summary-tab7"><a\
href="C3.html" title="annotation interface in pkg2">C3</a></div>
<div class="col-last even-row-color class-summary class-summary-tab7"></div>""");
// Class documentation
checkOutput("pkg1/C1.html", true,

@ -97,7 +97,7 @@ public class TestHtmlVersion extends JavadocTester {
<ul id="navbar-top-firstrow" class="nav-list" title="Navigation">
""",
"""
<div class="summary-table two-column-summary">""",
<div class="summary-table two-column-summary" aria-labelledby="class-summary-tab0">""",
"""
<header role="banner" class="flex-header">
<nav role="navigation">
@ -118,7 +118,8 @@ public class TestHtmlVersion extends JavadocTester {
<section class="summary">
<ul class="summary-list">
<li>
<div class="caption"><span>Class Summary</span></div>
<div id="class-summary">
<div class="caption"><span>Classes</span></div>
<div class="summary-table two-column-summary">""");
// Test for package-tree page

@ -1392,20 +1392,19 @@ public class TestModules extends JavadocTester {
void checkAllPkgsAllClasses(boolean found) {
checkOutput("allclasses-index.html", true,
"""
<div class="table-tabs" role="tablist" aria-orientation="horizontal">\
<button id="all-classes-table-tab0" role="tab" aria-selected="true" aria-control\
s="all-classes-table.tabpanel" tabindex="0" onkeydown="switchTab(event)" onclick\
="show('all-classes-table', 'all-classes-table', 2)" class="active-table-tab">Al\
l Classes</button>\
<div class="table-tabs" role="tablist" aria-orientation="horizontal"><button id=\
"all-classes-table-tab0" role="tab" aria-selected="true" aria-controls="all-clas\
ses-table.tabpanel" tabindex="0" onkeydown="switchTab(event)" onclick="show('all\
-classes-table', 'all-classes-table', 2)" class="active-table-tab">All Classes a\
nd Interfaces</button>\
<button id="all-classes-table-tab2" role="tab" aria-selected="false" aria-contro\
ls="all-classes-table.tabpanel" tabindex="-1" onkeydown="switchTab(event)" oncli\
ck="show('all-classes-table', 'all-classes-table-tab2', 2)" class="table-tab">Cl\
ass Summary</button>\
<button id="all-classes-table-tab6" role="tab" aria-selected="false" aria-contro\
asses</button>\
<button id="all-classes-table-tab7" role="tab" aria-selected="false" aria-contro\
ls="all-classes-table.tabpanel" tabindex="-1" onkeydown="switchTab(event)" oncli\
ck="show('all-classes-table', 'all-classes-table-tab6', 2)" class="table-tab">An\
notation Interfaces Summary</button>\
</div>
ck="show('all-classes-table', 'all-classes-table-tab7', 2)" class="table-tab">An\
notation Interfaces</button></div>
""",
"""
<div class="table-header col-first">Class</div>

@ -87,7 +87,7 @@ public class TestPackagePage extends JavadocTester {
checkOutput("allclasses-index.html", true,
"""
<div id="all-classes-table">
<div class="caption"><span>Class Summary</span></div>
<div class="caption"><span>Classes</span></div>
<div class="summary-table two-column-summary">
<div class="table-header col-first">Class</div>
<div class="table-header col-last">Description</div>

@ -1,5 +1,5 @@
/*
* Copyright (c) 2017, 2020, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2017, 2021, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -24,8 +24,9 @@
/*
* @test
* @bug 8189841 8253117
* @bug 8189841 8253117 8263507
* @summary Error in alternate row coloring in package-summary files
* @summary Improve structure of package summary pages
* @library ../../lib/
* @modules jdk.javadoc/jdk.javadoc.internal.tool
* @build javadoc.tester.* TestPackageSummary
@ -41,25 +42,67 @@ public class TestPackageSummary extends JavadocTester {
tester.runTests();
}
@Test
public void testSummaryLinks() {
javadoc("-d", "out-links",
"-sourcepath", testSrc,
"-subpackages", "pkg:pkg1");
checkExit(Exit.OK);
checkOutput("pkg/package-summary.html", true,
"""
<div class="sub-nav">
<div>
<ul class="sub-nav-list">
<li>Package:&nbsp;</li>
<li>Description&nbsp;|&nbsp;</li>
<li>Related Packages&nbsp;|&nbsp;</li>
<li><a href="#class-summary">Classes and Interfaces</a></li>
</ul>
</div>""");
checkOutput("pkg1/package-summary.html", true,
"""
<div class="sub-nav">
<div>
<ul class="sub-nav-list">
<li>Package:&nbsp;</li>
<li><a href="#package-description">Description</a>&nbsp;|&nbsp;</li>
<li><a href="#related-package-summary">Related Packages</a>&nbsp;|&nbsp;</li>
<li><a href="#class-summary">Classes and Interfaces</a></li>
</ul>
</div>""");
checkOutput("pkg1/sub/package-summary.html", true,
"""
<div class="sub-nav">
<div>
<ul class="sub-nav-list">
<li>Package:&nbsp;</li>
<li>Description&nbsp;|&nbsp;</li>
<li><a href="#related-package-summary">Related Packages</a>&nbsp;|&nbsp;</li>
<li><a href="#class-summary">Classes and Interfaces</a></li>
</ul>
</div>""");
}
@Test
public void testStripes() {
javadoc("-d", "out",
javadoc("-d", "out-stripes",
"-sourcepath", testSrc,
"pkg");
checkExit(Exit.OK);
checkOutput("pkg/package-summary.html", true,
"""
<div class="col-first even-row-color"><a href="C0.html" title="class in pkg">C0</a></div>
<div class="col-last even-row-color">&nbsp;</div>
<div class="col-first odd-row-color"><a href="C1.html" title="class in pkg">C1</a></div>
<div class="col-last odd-row-color">&nbsp;</div>
<div class="col-first even-row-color"><a href="C2.html" title="class in pkg">C2</a></div>
<div class="col-last even-row-color">&nbsp;</div>
<div class="col-first odd-row-color"><a href="C3.html" title="class in pkg">C3</a></div>
<div class="col-last odd-row-color">&nbsp;</div>
<div class="col-first even-row-color"><a href="C4.html" title="class in pkg">C4</a></div>
<div class="col-last even-row-color">&nbsp;</div>
<div class="col-first even-row-color class-summary class-summary-tab2"><a href="C0.html" title="class in pkg">C0</a></div>
<div class="col-last even-row-color class-summary class-summary-tab2">&nbsp;</div>
<div class="col-first odd-row-color class-summary class-summary-tab2"><a href="C1.html" title="class in pkg">C1</a></div>
<div class="col-last odd-row-color class-summary class-summary-tab2">&nbsp;</div>
<div class="col-first even-row-color class-summary class-summary-tab2"><a href="C2.html" title="class in pkg">C2</a></div>
<div class="col-last even-row-color class-summary class-summary-tab2">&nbsp;</div>
<div class="col-first odd-row-color class-summary class-summary-tab2"><a href="C3.html" title="class in pkg">C3</a></div>
<div class="col-last odd-row-color class-summary class-summary-tab2">&nbsp;</div>
<div class="col-first even-row-color class-summary class-summary-tab2"><a href="C4.html" title="class in pkg">C4</a></div>
<div class="col-last even-row-color class-summary class-summary-tab2">&nbsp;</div>
"""
);
}

@ -0,0 +1,27 @@
/*
* Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package pkg1;
public @interface Annotation0 {
}

@ -0,0 +1,27 @@
/*
* Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package pkg1;
public class Class0 {
}

@ -0,0 +1,27 @@
/*
* Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package pkg1;
public enum Enum0 {
}

@ -0,0 +1,27 @@
/*
* Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package pkg1;
public class Error0 extends Error {
}

@ -0,0 +1,27 @@
/*
* Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package pkg1;
public class Exception0 extends Exception {
}

@ -0,0 +1,27 @@
/*
* Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package pkg1;
public interface Interface0 {
}

@ -0,0 +1,27 @@
/*
* Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package pkg1;
public record Record0() {
}

@ -0,0 +1,5 @@
<html>
<body>
Test package
</body>
</html>

@ -0,0 +1,27 @@
/*
* Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package pkg1.sub;
public class Sub0 {
}

@ -142,7 +142,9 @@ public class TestRelatedPackages extends JavadocTester {
<div class="col-first odd-row-color"><a href="../t1/package-summary.html">t.p1.s3.t1</a></div>
<div class="col-last odd-row-color">&nbsp;</div>
</div>""");
checkOutput("t/p2/package-summary.html", false, "Related Packages");
checkOutput("t/p2/package-summary.html", false,
"""
<div class="caption"><span>Related Packages</span></div>""");
}
@Test

@ -806,31 +806,31 @@ public class TestSearch extends JavadocTester {
<button id="all-classes-table-tab0" role="tab" aria-selected="true" aria-control\
s="all-classes-table.tabpanel" tabindex="0" onkeydown="switchTab(event)" onclick\
="show('all-classes-table', 'all-classes-table', 2)" class="active-table-tab">Al\
l Classes</button>\
l Classes and Interfaces</button>\
<button id="all-classes-table-tab1" role="tab" aria-selected="false" aria-contro\
ls="all-classes-table.tabpanel" tabindex="-1" onkeydown="switchTab(event)" oncli\
ck="show('all-classes-table', 'all-classes-table-tab1', 2)" class="table-tab">In\
terface Summary</button>\
terfaces</button>\
<button id="all-classes-table-tab2" role="tab" aria-selected="false" aria-contro\
ls="all-classes-table.tabpanel" tabindex="-1" onkeydown="switchTab(event)" oncli\
ck="show('all-classes-table', 'all-classes-table-tab2', 2)" class="table-tab">Cl\
ass Summary</button>\
asses</button>\
<button id="all-classes-table-tab3" role="tab" aria-selected="false" aria-contro\
ls="all-classes-table.tabpanel" tabindex="-1" onkeydown="switchTab(event)" oncli\
ck="show('all-classes-table', 'all-classes-table-tab3', 2)" class="table-tab">En\
um Class Summary</button>\
<button id="all-classes-table-tab4" role="tab" aria-selected="false" aria-contro\
ls="all-classes-table.tabpanel" tabindex="-1" onkeydown="switchTab(event)" oncli\
ck="show('all-classes-table', 'all-classes-table-tab4', 2)" class="table-tab">Ex\
ception Summary</button>\
um Classes</button>\
<button id="all-classes-table-tab5" role="tab" aria-selected="false" aria-contro\
ls="all-classes-table.tabpanel" tabindex="-1" onkeydown="switchTab(event)" oncli\
ck="show('all-classes-table', 'all-classes-table-tab5', 2)" class="table-tab">Er\
ror Summary</button>\
ck="show('all-classes-table', 'all-classes-table-tab5', 2)" class="table-tab">Ex\
ceptions</button>\
<button id="all-classes-table-tab6" role="tab" aria-selected="false" aria-contro\
ls="all-classes-table.tabpanel" tabindex="-1" onkeydown="switchTab(event)" oncli\
ck="show('all-classes-table', 'all-classes-table-tab6', 2)" class="table-tab">An\
notation Interfaces Summary</button>\
ck="show('all-classes-table', 'all-classes-table-tab6', 2)" class="table-tab">Er\
rors</button>\
<button id="all-classes-table-tab7" role="tab" aria-selected="false" aria-contro\
ls="all-classes-table.tabpanel" tabindex="-1" onkeydown="switchTab(event)" oncli\
ck="show('all-classes-table', 'all-classes-table-tab7', 2)" class="table-tab">An\
notation Interfaces</button>\
</div>
<div id="all-classes-table.tabpanel" role="tabpanel">
<div class="summary-table two-column-summary" aria-labelledby="all-classes-table-tab0">

@ -233,6 +233,7 @@ public class TestSingletonLists extends JavadocTester {
private boolean inheritanceClass;
private List<String> excludeFiles = List.of(
"overview-tree.html",
"package-summary.html",
"package-tree.html",
"module-summary.html",
"help-doc.html");

@ -98,10 +98,10 @@ public class TestStylesheet extends JavadocTester {
font-weight:bold;
clear:none;
overflow:hidden;
padding:0px;
padding:0;
padding-top:10px;
padding-left:1px;
margin:0px;
margin:0;
white-space:pre;
}""",
"""
@ -209,7 +209,7 @@ public class TestStylesheet extends JavadocTester {
checkOutput("pkg/package-summary.html", true,
"""
<div class="col-last even-row-color">
<div class="col-last even-row-color class-summary class-summary-tab2">
<div class="block">Test comment for a class which has an <a name="named_anchor">anchor_with_name</a> and
an <a id="named_anchor1">anchor_with_id</a>.</div>
</div>""");

@ -71,7 +71,7 @@ public class TestUnnamedPackage extends JavadocTester {
checkOutput("allclasses-index.html", true,
"""
<div id="all-classes-table">
<div class="caption"><span>Class Summary</span></div>
<div class="caption"><span>Classes</span></div>
<div class="summary-table two-column-summary">
<div class="table-header col-first">Class</div>
<div class="table-header col-last">Description</div>