Package com.redhat.ceylon.ceylondoc

Source Code of com.redhat.ceylon.ceylondoc.ClassDoc$MemberSpecification

/*
* Copyright Red Hat Inc. and/or its affiliates and other contributors
* as indicated by the authors tag. All rights reserved.
*
* This copyrighted material is made available to anyone wishing to use,
* modify, copy, or redistribute it subject to the terms and conditions
* of the GNU General Public License version 2.
*
* This particular file is subject to the "Classpath" exception as provided in the
* LICENSE file that accompanied this code.
*
* This program is distributed in the hope that it will be useful, but WITHOUT A
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
* PARTICULAR PURPOSE.  See the GNU General Public License for more details.
* You should have received a copy of the GNU General Public License,
* along with this distribution; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
* MA  02110-1301, USA.
*/

package com.redhat.ceylon.ceylondoc;

import static com.redhat.ceylon.ceylondoc.Util.getAncestors;
import static com.redhat.ceylon.ceylondoc.Util.getDoc;
import static com.redhat.ceylon.ceylondoc.Util.getSuperInterfaces;
import static com.redhat.ceylon.ceylondoc.Util.isAbbreviatedType;
import static com.redhat.ceylon.ceylondoc.Util.isEmpty;

import java.io.IOException;
import java.io.Writer;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;

import com.redhat.ceylon.ceylondoc.Util.ProducedTypeComparatorByName;
import com.redhat.ceylon.ceylondoc.Util.ReferenceableComparatorByName;
import com.redhat.ceylon.compiler.typechecker.model.Class;
import com.redhat.ceylon.compiler.typechecker.model.ClassOrInterface;
import com.redhat.ceylon.compiler.typechecker.model.Declaration;
import com.redhat.ceylon.compiler.typechecker.model.Interface;
import com.redhat.ceylon.compiler.typechecker.model.Method;
import com.redhat.ceylon.compiler.typechecker.model.MethodOrValue;
import com.redhat.ceylon.compiler.typechecker.model.Package;
import com.redhat.ceylon.compiler.typechecker.model.ProducedType;
import com.redhat.ceylon.compiler.typechecker.model.TypeAlias;
import com.redhat.ceylon.compiler.typechecker.model.TypeDeclaration;
import com.redhat.ceylon.compiler.typechecker.model.TypedDeclaration;
import com.redhat.ceylon.compiler.typechecker.model.Value;

public class ClassDoc extends ClassOrPackageDoc {

    private TypeDeclaration klass;
    private List<Method> methods;
    private List<TypedDeclaration> attributes;
    private List<Interface> innerInterfaces;
    private List<Class> innerClasses;
    private List<Class> innerExceptions;
    private List<TypeAlias> innerAliases;
    private List<ProducedType> superInterfaces;
    private List<TypeDeclaration> superClasses;
    private Map<MemberSpecification, Map<TypeDeclaration, List<Declaration>>> superclassInheritedMembers = new HashMap<ClassDoc.MemberSpecification, Map<TypeDeclaration,List<Declaration>>>(2);
    private Map<MemberSpecification, Map<TypeDeclaration, List<Declaration>>> interfaceInheritedMembers = new HashMap<ClassDoc.MemberSpecification, Map<TypeDeclaration,List<Declaration>>>(2);

    private interface MemberSpecification {
        boolean isSatisfiedBy(Declaration decl);
    }

    private MemberSpecification attributeSpecification = new MemberSpecification() {
        @Override
        public boolean isSatisfiedBy(Declaration decl) {
            return decl instanceof Value;
        }
    };

    private MemberSpecification methodSpecification = new MemberSpecification() {
        @Override
        public boolean isSatisfiedBy(Declaration decl) {
            return decl instanceof Method;
        }
    };

    public ClassDoc(CeylonDocTool tool, Writer writer, TypeDeclaration klass) throws IOException {
        super(tool.getModule(klass), tool, writer);
        this.klass = klass;
        loadMembers();
    }

    private void loadMembers() {
        methods = new ArrayList<Method>();
        attributes = new ArrayList<TypedDeclaration>();
        innerInterfaces = new ArrayList<Interface>();
        innerClasses = new ArrayList<Class>();
        innerExceptions = new ArrayList<Class>();
        innerAliases = new ArrayList<TypeAlias>();
        superClasses = getAncestors(klass);
        superInterfaces = getSuperInterfaces(klass);
       
        for (Declaration m : klass.getMembers()) {
            if (tool.shouldInclude(m)) {
                if (m instanceof Value) {
                    attributes.add((Value) m);
                } else if (m instanceof Method) {
                    methods.add((Method) m);
                } else if (m instanceof Interface) {
                    innerInterfaces.add((Interface) m);
                } else if (m instanceof Class) {
                    Class c = (Class) m;
                    if (Util.isThrowable(c)) {
                        innerExceptions.add(c);
                    } else {
                        innerClasses.add(c);
                    }
                } else if (m instanceof TypeAlias) {
                    innerAliases.add((TypeAlias) m);
                }
            }
        }

        Collections.sort(methods, ReferenceableComparatorByName.INSTANCE);
        Collections.sort(attributes, ReferenceableComparatorByName.INSTANCE);
        Collections.sort(superInterfaces, ProducedTypeComparatorByName.INSTANCE);
        Collections.sort(innerInterfaces, ReferenceableComparatorByName.INSTANCE);
        Collections.sort(innerClasses, ReferenceableComparatorByName.INSTANCE);
        Collections.sort(innerExceptions, ReferenceableComparatorByName.INSTANCE);
        Collections.sort(innerAliases, ReferenceableComparatorByName.INSTANCE);
       
        loadSuperclassInheritedMembers(attributeSpecification);
        loadSuperclassInheritedMembers(methodSpecification);
        loadInterfaceInheritedMembers(attributeSpecification);
        loadInterfaceInheritedMembers(methodSpecification);
    }

    private void loadSuperclassInheritedMembers(MemberSpecification specification) {
        LinkedHashMap<TypeDeclaration, List<Declaration>> inheritedMembers = new LinkedHashMap<TypeDeclaration, List<Declaration>>();
        TypeDeclaration subclass = klass;
        for (TypeDeclaration superClass : superClasses) {
            List<Declaration> methods = getInheritedMembers(superClass, specification);
            if (methods.isEmpty())
                continue;
            List<Declaration> notRefined = new ArrayList<Declaration>();
            // clean already listed methods (refined in subclasses)
            // done in 2 phases to avoid empty tables
            for (Declaration method : methods) {
                if (subclass.getDirectMember(method.getName(), null, false) == null) {
                    notRefined.add(method);
                }
            }
            if (notRefined.isEmpty())
                continue;
            inheritedMembers.put(superClass, notRefined);
        }
        superclassInheritedMembers.put(specification, inheritedMembers);
    }

    private void loadInterfaceInheritedMembers(MemberSpecification memberSpecification) {
        LinkedHashMap<TypeDeclaration, List<Declaration>> result = new LinkedHashMap<TypeDeclaration, List<Declaration>>();
        for (ProducedType superInterface : superInterfaces) {
            TypeDeclaration decl = superInterface.getDeclaration();
            List<Declaration> members = getInheritedMembers(decl, memberSpecification);
            for (Declaration member : members) {
               
                Declaration refined = member.getRefinedDeclaration();
                if (refined == null
                        || refined == member
                        || (refined.getContainer() instanceof Class && refined.getContainer() != klass)) {
                    List<Declaration> r = result.get(member.getContainer());
                    if (r == null) {
                        r = new ArrayList<Declaration>();
                        result.put((TypeDeclaration)member.getContainer(), r);
                    }
                    r.add(member);
                }
            }
        }
        interfaceInheritedMembers.put(memberSpecification, result);
    }

    private List<Declaration> getInheritedMembers(TypeDeclaration decl, MemberSpecification specification) {
        List<Declaration> members = new ArrayList<Declaration>();
        for (Declaration m : decl.getMembers())
            if (tool.shouldInclude(m) && specification.isSatisfiedBy(m)) {
                members.add((MethodOrValue) m);
            }
        return members;
    }
   
    private boolean isObject() {
        return klass instanceof Class && klass.isAnonymous();
    }

    private boolean hasInitializer() {
        return klass instanceof Class && !isObject();
    }

    /**
     * Determines whether the type has any attributes (include any inherited from superclasses or superinterfaces).
     * @return true if the type has any attributes.
     */
    private boolean hasAnyAttributes() {
        return !(attributes.isEmpty()
                    && interfaceInheritedMembers.get(attributeSpecification).isEmpty()
                    && superclassInheritedMembers.get(attributeSpecification).isEmpty());
    }

    /**
     * Determines whether the type has any methods (include any inherited from superclasses or superinterfaces).
     * @return true if the type has any methods.
     */
    private boolean hasAnyMethods() {
        return !(methods.isEmpty()
                    && interfaceInheritedMembers.get(methodSpecification).isEmpty()
                    && superclassInheritedMembers.get(methodSpecification).isEmpty());
    }
   
    private String getClassLabel() {
        if (klass instanceof Interface) {
            return "interface";
        } else if (klass.isAnnotation()) {
            return "annotation";
        } else if (isObject()) {
            return "object";
        } else {
            return "class";
        }
    }

    public void generate() throws IOException {
        writeHeader(Util.capitalize(getClassLabel()) + " " + klass.getName());
        writeNavBar();
        writeSubNavBar();
       
        open("div class='container-fluid'");
       
        writeDescription();
       
        if (hasInitializer()) {
            writeInitializer((Class) klass);
        }

        if (hasAnyAttributes()) {
            open("div id='section-attributes'");
            writeAttributes();
            writeInheritedMembers(attributeSpecification, "Inherited Attributes", "Attributes inherited from: ");
            close("div");
        }

        if (hasAnyMethods()) {
            open("div id='section-methods'");
            writeMethods();
            writeInheritedMembers(methodSpecification, "Inherited Methods", "Methods inherited from: ");
            close("div");
        }

        // Nested types at the end
        writeInnerTypes(innerAliases, "section-nested-aliases", "Nested Aliases");
        writeInnerTypes(innerInterfaces, "section-nested-interfaces", "Nested Interfaces");
        writeInnerTypes(innerClasses, "section-nested-classes", "Nested Classes");
        writeInnerTypes(innerExceptions, "section-nested-exceptions", "Nested Exceptions");

        close("div");
       
        writeFooter();
    }

    private void writeSubNavBar() throws IOException {
        Package pkg = tool.getPackage(klass);
       
        open("div class='sub-navbar'");
       
        writeLinkSourceCode(klass);
       
        open("div class='sub-navbar-inner'");
       
        open("span class='sub-navbar-package'");
        writeIcon(pkg);
        writePackageNavigation(pkg);
        close("span");
       
        write("<br/>");
        writeClassSignature();
        close("div"); // sub-navbar-inner
       
        open("div class='sub-navbar-menu'");
        writeSubNavBarLink(linkRenderer().to(module).getUrl(), "Overview", 'O', "Jump to module documentation");
        writeSubNavBarLink(linkRenderer().to(pkg).getUrl(), "Package", 'P', "Jump to package documentation");
        if (hasAnyAttributes()) {
            writeSubNavBarLink("#section-attributes", "Attributes", 'A', "Jump to attributes");
        }
        if (hasInitializer()) {
            writeSubNavBarLink("#section-initializer", "Initializer", 'z', "Jump to initializer");
        }
        if (hasAnyMethods()) {
            writeSubNavBarLink("#section-methods", "Methods", 'M', "Jump to methods");
        }
        if (!innerAliases.isEmpty()) {
            writeSubNavBarLink("#section-nested-aliases", "Nested Aliases", 'l', "Jump to nested aliases");
        }
        if (!innerInterfaces.isEmpty()) {
            writeSubNavBarLink("#section-nested-interfaces", "Nested Interfaces", 'I', "Jump to nested interfaces");
        }
        if (!innerClasses.isEmpty()) {
            writeSubNavBarLink("#section-nested-classes", "Nested Classes", 'C', "Jump to nested classes");
        }
        if (!innerExceptions.isEmpty()) {
            writeSubNavBarLink("#section-nested-exceptions", "Nested Exceptions", 'E', "Jump to nested exceptions");
        }
        if( isObject() ) {
            writeSubNavBarLink(linkRenderer().to(klass.getContainer()).useAnchor(klass).getUrl(), "Singleton object declaration", '\0', "Jump to singleton object declaration");
        }
       
        close("div"); // sub-navbar-menu
       
        close("div"); // sub-navbar
    }
   
    private void writeClassSignature() throws IOException {
        open("span class='sub-navbar-label'");
        write(getClassLabel());
        close("span");
        writeIcon(klass);
        open("span class='sub-navbar-name'");
        writeQualifyingType(klass);
        open("span class='type-identifier'");
        write(klass.getName());
        close("span");
        writeTypeParameters(klass.getTypeParameters());
        close("span");
        writeInheritance(klass);
        writeTypeParametersConstraints(klass.getTypeParameters());
    }

    private void writeQualifyingType(TypeDeclaration klass) throws IOException {
        if (klass.isClassOrInterfaceMember()) {
            TypeDeclaration container = (TypeDeclaration) klass.getContainer();
            writeQualifyingType(container);
            linkRenderer().to(container).write();
            write(".");
        }
    }   

    private void writeDescription() throws IOException {
        open("div class='class-description'");
       
        writeTagged(klass);
        writeTabs();
       
        close("div"); // class-description
    }

    private void writeTabs() throws IOException {
        boolean hasTypeHierarchy = klass instanceof Class;
        boolean hasSupertypeHierarchy = klass instanceof Class || !isEmpty(klass.getSatisfiedTypeDeclarations());
        boolean hasSubtypeHierarchy = !isEmpty(tool.getSubclasses(klass)) || !isEmpty(tool.getSatisfyingClassesOrInterfaces(klass));

        open("div class='type-tabs section'");
        open("div class='tabbable'");

        open("ul class='nav nav-tabs'");
        writeTabNav("tabDocumentation", "Documentation", "icon-documentation", true, true, false);
        writeTabNav("tabTypeHierarchy", "Type Hierarchy", "icon-type-hierarchy", false, hasTypeHierarchy, false);
        writeTabNav("tabSupertypeHierarchy", "Supertype Hierarchy", "icon-supertype-hierarchy", false, hasSupertypeHierarchy, false);
        writeTabNav("tabSubtypeHierarchy", "Subtype Hierarchy", "icon-subtype-hierarchy", false, hasSubtypeHierarchy, Util.isEnumerated(klass));
        close("ul"); // nav-tabs

        open("div class='tab-content'");

        open("div class='tab-pane active' id='tabDocumentation'");
        /*if (!klass.getUnit().getAnythingDeclaration().equals(klass) &&
                klass.getExtendedTypeDeclaration()!=null) {
            writeListOnSummary("extended", "Extended class: ",
                    singletonList(klass.getExtendedTypeDeclaration()));
        }
        writeListOnSummary("satisfied", "Satisfied Interfaces: ", superInterfaces);
        writeEnclosingType();*/
        writeAnnotationConstructors();

        around("div class='doc'", getDoc(klass, linkRenderer()));
        writeBy(klass);
        writeSee(klass);
        close("div");

        open("div class='tab-pane' id='tabTypeHierarchy'");
        if( hasTypeHierarchy ) {
            writeTypeHierarchy();
        } else {
            write("<p class='muted'><i>no type hierarchy</i></p>");
        }
        close("div");
       
        open("div class='tab-pane' id='tabSupertypeHierarchy'");
        if( hasSupertypeHierarchy ) {
            writeSuperTypeHierarchy(Collections.singletonList(klass), 0);
        } else {
            write("<p class='muted'><i>no supertypes hierarchy</i></p>");
        }
        close("div");

        open("div class='tab-pane' id='tabSubtypeHierarchy'");
        if( hasSubtypeHierarchy ) {
            writeSubtypesHierarchy(Collections.singletonList(klass), 0);
        } else {
            write("<p class='muted'><i>no subtypes hierarchy</i></p>");
        }
        close("div");
       
        close("div"); // tab-content
        close("div"); // tabbable
        close("div"); // typeHierarchy
    }
   
    private void writeTabNav(String id, String name, String icon, boolean isActive, boolean isEnabled, boolean isEnumerated) throws IOException {
        write("<li" + (isActive ? " class='active'" : "") + ">");
        write("<a id='" + id + "Nav' href='#" + id + "' data-toggle='tab'>");
        write("<i class='" + icon + (isEnabled ? "" : "-disabled") + "'></i>");
        if(isEnumerated){
            around("span class='label label-info' title='Enumerated type with an &quot;of&quot; clause'", "Enumerated");
            write(" ");
        }
        write("<span" + (isEnabled ? "" : " class='disabled'") + ">" + name + "</span>");
        write("</a>");
        write("</li>");
    }
   
    private void writeTypeHierarchy() throws IOException {
        LinkedList<ProducedType> superTypes = new LinkedList<ProducedType>();
        superTypes.add(klass.getType());
        ProducedType type = klass.getExtendedType();
        while (type != null) {
            superTypes.add(0, type);
            type = type.getDeclaration().getExtendedType();
        }
        int level = 0;
        for (ProducedType superType : superTypes) {
            writeTypeHierarchyLevel(superType.getDeclaration(), level < superTypes.size() - 1);
            if (!isEmpty(superType.getSatisfiedTypes())) {
                write("<a class='hint' title='Go to the Supertype Hierarchy' onClick='$(\"#tabSupertypeHierarchyNav\").tab(\"show\");'> ...and other supertypes</a>");
            }
            open("div class='subhierarchy'");
            level++;
        }
        while (level-- > 0) {
            close("div"); // subhierarchy
            close("li", "ul");
        }
    }
   
    private void writeSuperTypeHierarchy(List<TypeDeclaration> types, int level) throws IOException {
        if (types.size() > 1) {
            Collections.sort(types, ReferenceableComparatorByName.INSTANCE);
        }
        for (TypeDeclaration type : types) {
            List<TypeDeclaration> supertypes = collectSupertypes(type);
            writeTypeHierarchyLevel(type, !supertypes.isEmpty());
            open("div class='subhierarchy'");
            writeSuperTypeHierarchy(supertypes, level + 1);
            close("div"); // subhierarchy
            close("li", "ul");
        }
    }

    private void writeSubtypesHierarchy(List<TypeDeclaration> types, int level) throws IOException {
        if (types.size() > 1) {
            Collections.sort(types, ReferenceableComparatorByName.INSTANCE);
        }
        for (TypeDeclaration type : types) {
            List<TypeDeclaration> subtypes = collectSubtypes(type);
            writeTypeHierarchyLevel(type, !subtypes.isEmpty());
            if(level == 0 && Util.isEnumerated(type)){
                around("span class='keyword'", " of");
            }
            open("div class='subhierarchy'");
            writeSubtypesHierarchy(subtypes, level + 1);
            close("div"); // subhierarchy
            close("li", "ul");
        }
    }
   
    private void writeTypeHierarchyLevel(TypeDeclaration type, boolean hasSublevels) throws IOException {
        open("ul class='hierarchy-level'", "li");
        if( hasSublevels ) {
            write("<span class='hierarchy-arrow-down' title='Click for expand/collapse'></span>");
        } else {
            write("<span class='hierarchy-arrow-none'></span>");
        }
        writeIcon(type);
        linkRenderer().to(type).withinText(true).printTypeParameters(false).printAbbreviated(false).write();
    }
   
    private List<TypeDeclaration> collectSupertypes(TypeDeclaration type) {
        List<TypeDeclaration> supertypes = new ArrayList<TypeDeclaration>();
        if (type instanceof Class && type.getExtendedTypeDeclaration() != null) {
            supertypes.add(type.getExtendedTypeDeclaration());
        }
        List<TypeDeclaration> satisfiedTypes = type.getSatisfiedTypeDeclarations();
        if (satisfiedTypes != null) {
            supertypes.addAll(satisfiedTypes);
        }
        return supertypes;
    }

    private List<TypeDeclaration> collectSubtypes(TypeDeclaration type) {
        List<TypeDeclaration> subtypes = new ArrayList<TypeDeclaration>();
        List<Class> subclasses = tool.getSubclasses(type);
        if (subclasses != null) {
            subtypes.addAll(subclasses);
        }
        List<ClassOrInterface> satisfyingClassesOrInterfaces = tool.getSatisfyingClassesOrInterfaces(type);
        if (satisfyingClassesOrInterfaces != null) {
            subtypes.addAll(satisfyingClassesOrInterfaces);
        }
        return subtypes;
    }

    private void writeListOnSummary(String cssClass, String title, List<?> types) throws IOException {
        if (!isEmpty(types)) {
            open("div class='" + cssClass + " section'");
            around("span class='title'", title);
           
            boolean first = true;
            for (Object type : types) {
                if (!first) {
                    write(", ");
                } else {
                    first = false;
                }
               
                if( type instanceof TypedDeclaration ) {
                    TypedDeclaration decl = (TypedDeclaration) type;
                    linkRenderer().to(decl).write();
                } else if( type instanceof ClassOrInterface ) {
                    ClassOrInterface klass = (ClassOrInterface) type;
                    linkRenderer().to(klass).printAbbreviated(!isAbbreviatedType(klass)).write();
                } else {
                    ProducedType pt = (ProducedType) type;
                    linkRenderer().to(pt).printAbbreviated(!isAbbreviatedType(pt.getDeclaration())).write();
                }
            }
            close("div");
        }
    }

    /*private void writeEnclosingType() throws IOException {
        if (klass.isMember()) {
            ClassOrInterface enclosingType = (ClassOrInterface) klass.getContainer();
            open("div class='enclosingType section'");
            around("span class='title'", "Enclosing " + (enclosingType instanceof Class ? "class: " : "interface: "));
            writeIcon(enclosingType);
            linkToDeclaration(enclosingType);
            close("div");
        }
    }*/
   
    private void writeAnnotationConstructors() throws IOException {
        if( klass.isAnnotation() ) {
            List<Method> annotationConstructors = tool.getAnnotationConstructors(klass);
            if( annotationConstructors != null ) {
                Collections.sort(annotationConstructors, ReferenceableComparatorByName.INSTANCE);
                writeListOnSummary("annotationConstructors", "Annotation Constructors: ", annotationConstructors);
            }
        }
    }

    private void writeInheritedMembers(MemberSpecification specification, String tableTitle, String rowTitle) throws IOException {
        boolean first = true;
       
        Map<TypeDeclaration, List<Declaration>> superClassInheritedMembersMap = superclassInheritedMembers.get(specification);
        List<TypeDeclaration> superClasses = new ArrayList<TypeDeclaration>(superclassInheritedMembers.get(specification).keySet());
        Collections.sort(superClasses, ReferenceableComparatorByName.INSTANCE);
       
        for (TypeDeclaration superClass : superClasses) {
            List<Declaration> inheritedMembers = superClassInheritedMembersMap.get(superClass);
            Collections.sort(inheritedMembers, ReferenceableComparatorByName.INSTANCE);

            if (first) {
                first = false;
                openTable(null, tableTitle, 1, false);
            }
            writeInheritedMembersRow(rowTitle, superClass, inheritedMembers);
        }

        Map<TypeDeclaration, List<Declaration>> superInterfaceInheritedMembersMap = interfaceInheritedMembers.get(specification);
        List<TypeDeclaration> superInterfaces = new ArrayList<TypeDeclaration>(superInterfaceInheritedMembersMap.keySet());
        Collections.sort(superInterfaces, ReferenceableComparatorByName.INSTANCE);
       
        for (TypeDeclaration superInterface : superInterfaces) {
            List<Declaration> members = superInterfaceInheritedMembersMap.get(superInterface);
            if (members == null || members.isEmpty()) {
                continue;
            }
            Collections.sort(members, ReferenceableComparatorByName.INSTANCE);

            if (first) {
                first = false;
                openTable(null, tableTitle, 1, false);
            }
            writeInheritedMembersRow(rowTitle, superInterface, members);
        }

        if (!first) {
            closeTable();
        }
    }

    private void writeInheritedMembersRow(String title, TypeDeclaration superType, List<Declaration> members) throws IOException {
        open("tr", "td");
        write(title);
        writeIcon(superType);
        linkRenderer().to(superType).withinText(true).write();
        open("div class='inherited-members'");
       
        boolean first = true;
        for (Declaration member : members) {
            if (!first) {
                write(", ");
            } else {
                first = false;
            }
            linkRenderer().withinText(true).to(member).write();
        }
       
        close("div");
        close("td", "tr");
    }
   
    private void writeInnerTypes(List<? extends TypeDeclaration> innerTypeDeclarations, String id, String title) throws IOException {
        if (!innerTypeDeclarations.isEmpty()) {
            openTable(id, title, 2, true);
            for (TypeDeclaration innerTypeDeclaration : innerTypeDeclarations) {
                if (innerTypeDeclaration instanceof ClassOrInterface) {
                    ClassOrInterface innerClassOrInterface = (ClassOrInterface) innerTypeDeclaration;
                    tool.doc(innerClassOrInterface);
                    doc(innerClassOrInterface);
                }
                if (innerTypeDeclaration instanceof TypeAlias) {
                    TypeAlias innerAlias = (TypeAlias) innerTypeDeclaration;
                    doc(innerAlias);
                }
            }
            closeTable();
        }
    }

    private void writeInitializer(Class klass) throws IOException {
        openTable("section-initializer", "Initializer", 1, true);
        open("tr", "td");
       
        writeParameterLinksIfRequired(klass);
        writeIcon(klass);
       
        open("code class='decl-label'");
        write(klass.getName());
        writeParameterList(klass);
        close("code");
       
        open("div class='description'");
        writeParameters(klass);
        writeThrows(klass);
        close("div");
       
        close("td", "tr");
        closeTable();
    }

    private void writeAttributes() throws IOException {
        if (attributes.isEmpty()){
            return;
        }
        openTable(null, "Attributes", 2, true);
        for (TypedDeclaration attribute : attributes) {
            doc(attribute);
        }
        closeTable();
    }

    private void writeMethods() throws IOException {
        if (methods.isEmpty()){
            return;
        }
        openTable(null, "Methods", 2, true);
        for (Method m : methods) {
            doc(m);
        }
        closeTable();
    }

    @Override
    protected void registerAdditionalKeyboardShortcuts() throws IOException {
        registerKeyboardShortcut('p', "index.html");
        if (hasAnyAttributes()) {
            registerKeyboardShortcut('a', "#section-attributes");
        }
        if (hasInitializer()) {
            registerKeyboardShortcut('z', "#section-initializer");
        }
        if (hasAnyMethods()) {
            registerKeyboardShortcut('m', "#section-methods");
        }
        if (!innerAliases.isEmpty()) {
            registerKeyboardShortcut('l', "#section-nested-aliases");
        }
        if (!innerInterfaces.isEmpty()) {
            registerKeyboardShortcut('i', "#section-nested-interfaces");
        }
        if (!innerClasses.isEmpty()) {
            registerKeyboardShortcut('c', "#section-nested-classes");
        }
        if (!innerExceptions.isEmpty()) {
            registerKeyboardShortcut('e', "#section-nested-exceptions");
        }
    }

    @Override
    protected Object getFromObject() {
        return klass;
    }
   
}
TOP

Related Classes of com.redhat.ceylon.ceylondoc.ClassDoc$MemberSpecification

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.