All Downloads are FREE. Search and download functionalities are using the official Maven repository.

jdk.javadoc.internal.doclets.formats.html.IndexWriter Maven / Gradle / Ivy

There is a newer version: 21.0.0
Show newest version
/*
 * Copyright (c) 1998, 2020, 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.  Oracle designates this
 * particular file as subject to the "Classpath" exception as provided
 * by Oracle in the LICENSE file that accompanied this code.
 *
 * 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 jdk.javadoc.internal.doclets.formats.html;

import java.util.List;
import java.util.ListIterator;
import java.util.SortedSet;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import javax.lang.model.element.Element;
import javax.lang.model.element.ElementKind;
import javax.lang.model.element.ModuleElement;
import javax.lang.model.element.PackageElement;
import javax.lang.model.element.TypeElement;

import com.sun.source.doctree.DeprecatedTree;

import jdk.javadoc.internal.doclets.formats.html.markup.BodyContents;
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.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.Navigation.PageMode;
import jdk.javadoc.internal.doclets.formats.html.markup.StringContent;
import jdk.javadoc.internal.doclets.toolkit.Content;
import jdk.javadoc.internal.doclets.toolkit.util.DocFileIOException;
import jdk.javadoc.internal.doclets.toolkit.util.DocPath;
import jdk.javadoc.internal.doclets.toolkit.util.DocPaths;
import jdk.javadoc.internal.doclets.toolkit.util.IndexBuilder;
import jdk.javadoc.internal.doclets.toolkit.util.IndexItem;
import org.frgaal.CollectionShims;

/**
 * Generator for either a single index or split index for all
 * documented elements, terms defined in some documentation comments,
 * and summary pages.
 *
 *  

This is NOT part of any supported API. * If you write code that depends on this, you do so at your own risk. * This code and its internal interfaces are subject to change or * deletion without notice. * * @see IndexBuilder */ public class IndexWriter extends HtmlDocletWriter { protected final IndexBuilder mainIndex; protected final boolean splitIndex; /** * Generates the main index of all documented elements, terms defined in some documentation * comments, and summary pages. * * If {@link HtmlOptions#splitIndex()} is true, a separate page is generated for each * initial letter; otherwise, a single page is generated for all items in the index. * * @param configuration the configuration * @throws DocFileIOException if an error occurs while writing the files */ public static void generate(HtmlConfiguration configuration) throws DocFileIOException { IndexBuilder mainIndex = configuration.mainIndex; List firstCharacters = mainIndex.getFirstCharacters(); if (configuration.getOptions().splitIndex()) { ListIterator iter = firstCharacters.listIterator(); while (iter.hasNext()) { Character ch = iter.next(); DocPath file = DocPaths.INDEX_FILES.resolve(DocPaths.indexN(iter.nextIndex())); IndexWriter writer = new IndexWriter(configuration, file); writer.generateIndexFile(firstCharacters, CollectionShims.list(ch)); } } else { IndexWriter writer = new IndexWriter(configuration, DocPaths.INDEX_ALL); writer.generateIndexFile(firstCharacters, firstCharacters); } } /** * Creates a writer that can write a page containing some or all of the overall index. * * @param configuration the current configuration * @param path the file to be generated */ protected IndexWriter(HtmlConfiguration configuration, DocPath path) { super(configuration, path); this.mainIndex = configuration.mainIndex; this.splitIndex = configuration.getOptions().splitIndex(); } /** * Generates a page containing some or all of the overall index. * * @param allFirstCharacters the initial characters of all index items * @param displayFirstCharacters the initial characters of the index items to appear on this page * @throws DocFileIOException if an error occurs while writing the page */ protected void generateIndexFile(List allFirstCharacters, List displayFirstCharacters) throws DocFileIOException { String title = splitIndex ? resources.getText("doclet.Window_Split_Index", displayFirstCharacters.get(0)) : resources.getText("doclet.Window_Single_Index"); HtmlTree body = getBody(getWindowTitle(title)); Content mainContent = new ContentBuilder(); addLinksForIndexes(allFirstCharacters, mainContent); for (Character ch : displayFirstCharacters) { addContents(ch, mainIndex.getItems(ch), mainContent); } addLinksForIndexes(allFirstCharacters, mainContent); body.add(new BodyContents() .setHeader(getHeader(PageMode.INDEX)) .addMainContent(HtmlTree.DIV(HtmlStyle.header, HtmlTree.HEADING(Headings.PAGE_TITLE_HEADING, contents.getContent("doclet.Index")))) .addMainContent(mainContent) .setFooter(getFooter())); String description = splitIndex ? "index: " + displayFirstCharacters.get(0) : "index"; printHtmlDocument(null, description, body); } /** * Adds a set of items to the page. * * @param ch the first character of the names of the items * @param items the items * @param contentTree the tree to which to add the items */ protected void addContents(char ch, SortedSet items, Content contentTree) { addHeading(ch, contentTree); HtmlTree dl = HtmlTree.DL(HtmlStyle.index); for (IndexItem item : items) { addDescription(item, dl); } contentTree.add(dl); } /** * Adds a heading containing the first character for a set of items. * * @param ch the first character of the names of the items * @param contentTree the tree to which to add the items */ protected void addHeading(char ch, Content contentTree) { Content headContent = new StringContent(String.valueOf(ch)); HtmlTree heading = HtmlTree.HEADING(Headings.CONTENT_HEADING, HtmlStyle.title, headContent) .setId(getNameForIndex(ch)); contentTree.add(heading); } /** * Adds the description for an index item into a list. * * @param indexItem the item * @param dl the list */ protected void addDescription(IndexItem indexItem, Content dl) { if (indexItem.isTagItem()) { addTagDescription(indexItem, dl); } else if (indexItem.isElementItem()) { addElementDescription(indexItem, dl); } } /** * Add one line summary comment for the item. * * @param item the item to be documented * @param dlTree the content tree to which the description will be added */ protected void addElementDescription(IndexItem item, Content dlTree) { Content dt; Element element = item.getElement(); String label = item.getLabel(); switch (element.getKind()) { case MODULE: dt = HtmlTree.DT(getModuleLink((ModuleElement) element, new StringContent(label))); dt.add(" - ").add(contents.module_).add(" " + label); break; case PACKAGE: dt = HtmlTree.DT(getPackageLink((PackageElement) element, new StringContent(label))); if (configuration.showModules) { item.setContainingModule(utils.getFullyQualifiedName(utils.containingModule(element))); } dt.add(" - ").add(contents.package_).add(" " + label); break; case CLASS: case ENUM: case RECORD: case ANNOTATION_TYPE: case INTERFACE: dt = HtmlTree.DT(getLink(new LinkInfoImpl(configuration, LinkInfoImpl.Kind.INDEX, (TypeElement) element).strong(true))); dt.add(" - "); addClassInfo((TypeElement) element, dt); break; case CONSTRUCTOR: case METHOD: case FIELD: case ENUM_CONSTANT: TypeElement containingType = item.getContainingTypeElement(); dt = HtmlTree.DT(HtmlTree.SPAN(HtmlStyle.memberNameLink, getDocLink(LinkInfoImpl.Kind.INDEX, containingType, element, new StringContent(label)))); dt.add(" - "); addMemberDesc(element, containingType, dt); break; default: throw new Error(); } dlTree.add(dt); Content dd = new HtmlTree(TagName.DD); if (element.getKind() == ElementKind.MODULE || element.getKind() == ElementKind.PACKAGE) { addSummaryComment(element, dd); } else { addComment(element, dd); } dlTree.add(dd); } /** * Adds information for the given type element. * * @param te the element * @param contentTree the content tree to which the class info will be added */ protected void addClassInfo(TypeElement te, Content contentTree) { contentTree.add(contents.getContent("doclet.in", utils.getTypeElementKindName(te, false), getPackageLink(utils.containingPackage(te), utils.getPackageName(utils.containingPackage(te))) )); } /** * Adds a description for an item found in a documentation comment. * * @param item the item * @param dlTree the list to which to add the description */ protected void addTagDescription(IndexItem item, Content dlTree) { String itemPath = pathToRoot.isEmpty() ? "" : pathToRoot.getPath() + "/"; itemPath += item.getUrl(); HtmlTree labelLink = HtmlTree.A(itemPath, new StringContent(item.getLabel())); Content dt = HtmlTree.DT(HtmlTree.SPAN(HtmlStyle.searchTagLink, labelLink)); dt.add(" - "); dt.add(contents.getContent("doclet.Search_tag_in", item.getHolder())); dlTree.add(dt); Content dd = new HtmlTree(TagName.DD); if (item.getDescription().isEmpty()) { dd.add(Entity.NO_BREAK_SPACE); } else { dd.add(item.getDescription()); } dlTree.add(dd); } /** * Adds a comment for an element in the index. If the element is deprecated * and it has a @deprecated tag, use that comment; otherwise, if the containing * class for this element is deprecated, then add the word "Deprecated." at * the start and then print the normal comment. * * @param element the element * @param contentTree the content tree to which the comment will be added */ protected void addComment(Element element, Content contentTree) { Content span = HtmlTree.SPAN(HtmlStyle.deprecatedLabel, getDeprecatedPhrase(element)); HtmlTree div = new HtmlTree(TagName.DIV); div.setStyle(HtmlStyle.deprecationBlock); if (utils.isDeprecated(element)) { div.add(span); List tags = utils.getDeprecatedTrees(element); if (!tags.isEmpty()) addInlineDeprecatedComment(element, tags.get(0), div); contentTree.add(div); } else { TypeElement encl = utils.getEnclosingTypeElement(element); while (encl != null) { if (utils.isDeprecated(encl)) { div.add(span); contentTree.add(div); break; } encl = utils.getEnclosingTypeElement(encl); } addSummaryComment(element, contentTree); } } /** * Adds a description for a member element. * * @param member the element * @param enclosing the enclosing type element * @param contentTree the content tree to which the member description will be added */ protected void addMemberDesc(Element member, TypeElement enclosing, Content contentTree) { String kindName = utils.getTypeElementKindName(enclosing, true); String resource = switch (member.getKind()) { case ENUM_CONSTANT -> "doclet.Enum_constant_in"; case FIELD -> utils.isStatic(member) ? "doclet.Static_variable_in" : "doclet.Variable_in"; case CONSTRUCTOR -> "doclet.Constructor_for"; case METHOD -> utils.isAnnotationType(enclosing) ? "doclet.Element_in" : utils.isStatic(member) ? "doclet.Static_method_in" : "doclet.Method_in"; case RECORD_COMPONENT -> "doclet.Record_component_in"; default -> throw new IllegalArgumentException(member.getKind().toString()); }; contentTree.add(contents.getContent(resource, kindName)).add(" "); addPreQualifiedClassLink(LinkInfoImpl.Kind.INDEX, enclosing, false, contentTree); } /** * Add links for all the index files, based on the first character of the names of the items. * * @param allFirstCharacters the list of all first characters to be linked * @param contentTree the content tree to which the links for indexes will be added */ protected void addLinksForIndexes(List allFirstCharacters, Content contentTree) { ListIterator iter = allFirstCharacters.listIterator(); while (iter.hasNext()) { char ch = iter.next(); Content label = new StringContent(Character.toString(ch)); Content link = splitIndex ? links.createLink(DocPaths.indexN(iter.nextIndex()), label) : links.createLink(getNameForIndex(ch), label); contentTree.add(link); contentTree.add(Entity.NO_BREAK_SPACE); } contentTree.add(new HtmlTree(TagName.BR)); List pageLinks = Stream.of(IndexItem.Category.values()) .flatMap(c -> mainIndex.getItems(c).stream()) .filter(i -> !(i.isElementItem() || i.isTagItem())) .sorted((i1,i2)-> utils.compareStrings(i1.getLabel(), i2.getLabel())) .map(i -> links.createLink(pathToRoot.resolve(i.getUrl()), contents.getNonBreakString(i.getLabel()))) .collect(Collectors.toList()); contentTree.add(contents.join(getVerticalSeparator(), pageLinks)); } /** * Returns the anchor name for a first character of names in the index. * * @param firstCharacter the character * @return a name */ protected String getNameForIndex(char firstCharacter) { return "I:" + links.getName(Character.toString(firstCharacter)); } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy