001/*
002 * Copyright (c) 1998, 2023, Oracle and/or its affiliates. All rights reserved.
003 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
004 *
005 * This code is free software; you can redistribute it and/or modify it
006 * under the terms of the GNU General Public License version 2 only, as
007 * published by the Free Software Foundation.  Oracle designates this
008 * particular file as subject to the "Classpath" exception as provided
009 * by Oracle in the LICENSE file that accompanied this code.
010 *
011 * This code is distributed in the hope that it will be useful, but WITHOUT
012 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
013 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
014 * version 2 for more details (a copy is included in the LICENSE file that
015 * accompanied this code).
016 *
017 * You should have received a copy of the GNU General Public License version
018 * 2 along with this work; if not, write to the Free Software Foundation,
019 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
020 *
021 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
022 * or visit www.oracle.com if you need additional information or have any
023 * questions.
024 */
025
026package org.jdrupes.mdoclet.internal.doclets.formats.html;
027
028import javax.lang.model.element.TypeElement;
029
030import org.jdrupes.mdoclet.internal.doclets.formats.html.markup.HtmlStyle;
031import org.jdrupes.mdoclet.internal.doclets.formats.html.markup.HtmlTree;
032import org.jdrupes.mdoclet.internal.doclets.formats.html.markup.TagName;
033import org.jdrupes.mdoclet.internal.doclets.toolkit.Content;
034import org.jdrupes.mdoclet.internal.doclets.toolkit.util.ClassTree;
035import org.jdrupes.mdoclet.internal.doclets.toolkit.util.DocPath;
036import org.jdrupes.mdoclet.internal.doclets.toolkit.util.ClassTree.Hierarchy;
037
038import java.util.Collection;
039import java.util.SortedSet;
040import java.util.TreeSet;
041
042/**
043 * Abstract class to print the class hierarchy page for all the Classes. This
044 * is subclassed by {@link PackageTreeWriter} and {@link TreeWriter} to
045 * generate the Package Tree and global Tree(for all the classes and packages)
046 * pages.
047 */
048public abstract class AbstractTreeWriter extends HtmlDocletWriter {
049
050    /**
051     * The class and interface tree built by using {@link ClassTree}
052     */
053    protected final ClassTree classTree;
054
055    /**
056     * Constructor. This constructor will be used while generating global tree file "overview-tree.html".
057     *
058     * @param configuration  The current configuration
059     * @param filename   File to be generated.
060     * @param classTree  Tree built by {@link ClassTree}.
061     */
062    protected AbstractTreeWriter(HtmlConfiguration configuration,
063            DocPath filename, ClassTree classTree) {
064        super(configuration, filename);
065        this.classTree = classTree;
066    }
067
068    /**
069     * Add each level of the class tree. For each subclass or
070     * subinterface indents the next level information.
071     * Recurses itself to add subclasses info.
072     *
073     * @param parent the superclass or superinterface of the sset
074     * @param collection  a collection of the subclasses at this level
075     * @param hierarchy the hierarchy for which we are generating a tree
076     * @param content the content to which the level information will be added
077     */
078    protected void addLevelInfo(TypeElement parent,
079            Collection<TypeElement> collection,
080            Hierarchy hierarchy, Content content) {
081        if (!collection.isEmpty()) {
082            var ul = new HtmlTree(TagName.UL);
083            for (TypeElement local : collection) {
084                var li = new HtmlTree(TagName.LI);
085                li.setStyle(HtmlStyle.circle);
086                addPartialInfo(local, li);
087                addExtendsImplements(parent, local, li);
088                addLevelInfo(local, hierarchy.subtypes(local), hierarchy, li);   // Recurse
089                ul.add(li);
090            }
091            content.add(ul);
092        }
093    }
094
095    /**
096     * Adds a class or interface hierarchy with a given heading to given content.
097     *
098     * @param hierarchy the hierarchy to add
099     * @param heading   the heading
100     * @param content   the content to which to add the hierarchy
101     */
102    protected void addTree(Hierarchy hierarchy, String heading,
103            Content content) {
104        SortedSet<TypeElement> roots = hierarchy.roots();
105        if (!roots.isEmpty()) {
106            TypeElement firstTypeElement = roots.first();
107            Content headingContent = contents.getContent(heading);
108            var sectionHeading
109                = HtmlTree.HEADING_TITLE(Headings.CONTENT_HEADING,
110                    headingContent);
111            var section = HtmlTree.SECTION(HtmlStyle.hierarchy, sectionHeading);
112            addLevelInfo(
113                !utils.isPlainInterface(firstTypeElement) ? firstTypeElement
114                    : null,
115                roots, hierarchy, section);
116            content.add(section);
117        }
118    }
119
120    /**
121     * Add information regarding the classes which this class extends or implements.
122     *
123     * @param parent the parent class of the class being documented
124     * @param typeElement the TypeElement under consideration
125     * @param content the content to which the information will be added
126     */
127    protected void addExtendsImplements(TypeElement parent,
128            TypeElement typeElement,
129            Content content) {
130        SortedSet<TypeElement> interfaces
131            = new TreeSet<>(comparators.makeGeneralPurposeComparator());
132        typeElement.getInterfaces()
133            .forEach(t -> interfaces.add(utils.asTypeElement(t)));
134        if (interfaces.size() > (utils.isPlainInterface(typeElement) ? 1 : 0)) {
135            boolean isFirst = true;
136            for (TypeElement intf : interfaces) {
137                if (parent != intf) {
138                    if (utils.isPublic(intf) || utils.isLinkable(intf)) {
139                        if (isFirst) {
140                            isFirst = false;
141                            if (utils.isPlainInterface(typeElement)) {
142                                content.add(" (");
143                                content.add(contents.also);
144                                content.add(" extends ");
145                            } else {
146                                content.add(" (implements ");
147                            }
148                        } else {
149                            content.add(", ");
150                        }
151                        addPreQualifiedClassLink(
152                            HtmlLinkInfo.Kind.SHOW_TYPE_PARAMS, intf, content);
153                    }
154                }
155            }
156            if (!isFirst) {
157                content.add(")");
158            }
159        }
160    }
161
162    /**
163     * Add information about the class kind, if it's a "class" or "interface".
164     *
165     * @param typeElement the class being documented
166     * @param content the content to which the information will be added
167     */
168    protected void addPartialInfo(TypeElement typeElement, Content content) {
169        addPreQualifiedStrongClassLink(HtmlLinkInfo.Kind.SHOW_TYPE_PARAMS,
170            typeElement, content);
171    }
172}