blob: 92b7224d5051b8feb938d78c689b080fe2118a56 [file] [log] [blame]
/*
* Copyright (c) 1997, 2013, 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 com.sun.tools.doclets.formats.html;
import java.util.*;
import com.sun.javadoc.*;
import com.sun.tools.javac.jvm.Profile;
import com.sun.tools.doclets.formats.html.markup.*;
import com.sun.tools.doclets.internal.toolkit.*;
import com.sun.tools.doclets.internal.toolkit.builders.*;
import com.sun.tools.doclets.internal.toolkit.taglets.*;
import com.sun.tools.doclets.internal.toolkit.util.*;
import java.io.IOException;
/**
* Generate the Class Information Page.
*
* <p><b>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.</b>
*
* @see com.sun.javadoc.ClassDoc
* @see java.util.Collections
* @see java.util.List
* @see java.util.ArrayList
* @see java.util.HashMap
*
* @author Atul M Dambalkar
* @author Robert Field
* @author Bhavesh Patel (Modified)
*/
public class ClassWriterImpl extends SubWriterHolderWriter
implements ClassWriter {
protected final ClassDoc classDoc;
protected final ClassTree classtree;
protected final ClassDoc prev;
protected final ClassDoc next;
/**
* @param configuration the configuration data for the doclet
* @param classDoc the class being documented.
* @param prevClass the previous class that was documented.
* @param nextClass the next class being documented.
* @param classTree the class tree for the given class.
*/
public ClassWriterImpl (ConfigurationImpl configuration, ClassDoc classDoc,
ClassDoc prevClass, ClassDoc nextClass, ClassTree classTree)
throws IOException {
super(configuration, DocPath.forClass(classDoc));
this.classDoc = classDoc;
configuration.currentcd = classDoc;
this.classtree = classTree;
this.prev = prevClass;
this.next = nextClass;
}
/**
* Get this package link.
*
* @return a content tree for the package link
*/
protected Content getNavLinkPackage() {
Content linkContent = getHyperLink(DocPaths.PACKAGE_SUMMARY,
packageLabel);
Content li = HtmlTree.LI(linkContent);
return li;
}
/**
* Get the class link.
*
* @return a content tree for the class link
*/
protected Content getNavLinkClass() {
Content li = HtmlTree.LI(HtmlStyle.navBarCell1Rev, classLabel);
return li;
}
/**
* Get the class use link.
*
* @return a content tree for the class use link
*/
protected Content getNavLinkClassUse() {
Content linkContent = getHyperLink(DocPaths.CLASS_USE.resolve(filename), useLabel);
Content li = HtmlTree.LI(linkContent);
return li;
}
/**
* Get link to previous class.
*
* @return a content tree for the previous class link
*/
public Content getNavLinkPrevious() {
Content li;
if (prev != null) {
Content prevLink = getLink(new LinkInfoImpl(configuration,
LinkInfoImpl.Kind.CLASS, prev)
.label(prevclassLabel).strong(true));
li = HtmlTree.LI(prevLink);
}
else
li = HtmlTree.LI(prevclassLabel);
return li;
}
/**
* Get link to next class.
*
* @return a content tree for the next class link
*/
public Content getNavLinkNext() {
Content li;
if (next != null) {
Content nextLink = getLink(new LinkInfoImpl(configuration,
LinkInfoImpl.Kind.CLASS, next)
.label(nextclassLabel).strong(true));
li = HtmlTree.LI(nextLink);
}
else
li = HtmlTree.LI(nextclassLabel);
return li;
}
/**
* {@inheritDoc}
*/
public Content getHeader(String header) {
String pkgname = (classDoc.containingPackage() != null)?
classDoc.containingPackage().name(): "";
String clname = classDoc.name();
Content bodyTree = getBody(true, getWindowTitle(clname));
addTop(bodyTree);
addNavLinks(true, bodyTree);
bodyTree.addContent(HtmlConstants.START_OF_CLASS_DATA);
HtmlTree div = new HtmlTree(HtmlTag.DIV);
div.addStyle(HtmlStyle.header);
if (configuration.showProfiles) {
String sep = "";
int profile = configuration.profiles.getProfile(getTypeNameForProfile(classDoc));
if (profile > 0) {
Content profNameContent = new StringContent();
for (int i = profile; i < configuration.profiles.getProfileCount(); i++) {
profNameContent.addContent(sep);
profNameContent.addContent(Profile.lookup(i).name);
sep = ", ";
}
Content profileNameDiv = HtmlTree.DIV(HtmlStyle.subTitle, profNameContent);
div.addContent(profileNameDiv);
}
}
if (pkgname.length() > 0) {
Content pkgNameContent = new StringContent(pkgname);
Content pkgNameDiv = HtmlTree.DIV(HtmlStyle.subTitle, pkgNameContent);
div.addContent(pkgNameDiv);
}
LinkInfoImpl linkInfo = new LinkInfoImpl(configuration,
LinkInfoImpl.Kind.CLASS_HEADER, classDoc);
//Let's not link to ourselves in the header.
linkInfo.linkToSelf = false;
Content headerContent = new StringContent(header);
Content heading = HtmlTree.HEADING(HtmlConstants.CLASS_PAGE_HEADING, true,
HtmlStyle.title, headerContent);
heading.addContent(getTypeParameterLinks(linkInfo));
div.addContent(heading);
bodyTree.addContent(div);
return bodyTree;
}
/**
* {@inheritDoc}
*/
public Content getClassContentHeader() {
return getContentHeader();
}
/**
* {@inheritDoc}
*/
public void addFooter(Content contentTree) {
contentTree.addContent(HtmlConstants.END_OF_CLASS_DATA);
addNavLinks(false, contentTree);
addBottom(contentTree);
}
/**
* {@inheritDoc}
*/
public void printDocument(Content contentTree) throws IOException {
printHtmlDocument(configuration.metakeywords.getMetaKeywords(classDoc),
true, contentTree);
}
/**
* {@inheritDoc}
*/
public Content getClassInfoTreeHeader() {
return getMemberTreeHeader();
}
/**
* {@inheritDoc}
*/
public Content getClassInfo(Content classInfoTree) {
return getMemberTree(HtmlStyle.description, classInfoTree);
}
/**
* {@inheritDoc}
*/
public void addClassSignature(String modifiers, Content classInfoTree) {
boolean isInterface = classDoc.isInterface();
classInfoTree.addContent(new HtmlTree(HtmlTag.BR));
Content pre = new HtmlTree(HtmlTag.PRE);
addAnnotationInfo(classDoc, pre);
pre.addContent(modifiers);
LinkInfoImpl linkInfo = new LinkInfoImpl(configuration,
LinkInfoImpl.Kind.CLASS_SIGNATURE, classDoc);
//Let's not link to ourselves in the signature.
linkInfo.linkToSelf = false;
Content className = new StringContent(classDoc.name());
Content parameterLinks = getTypeParameterLinks(linkInfo);
if (configuration.linksource) {
addSrcLink(classDoc, className, pre);
pre.addContent(parameterLinks);
} else {
Content span = HtmlTree.SPAN(HtmlStyle.typeNameLabel, className);
span.addContent(parameterLinks);
pre.addContent(span);
}
if (!isInterface) {
Type superclass = Util.getFirstVisibleSuperClass(classDoc,
configuration);
if (superclass != null) {
pre.addContent(DocletConstants.NL);
pre.addContent("extends ");
Content link = getLink(new LinkInfoImpl(configuration,
LinkInfoImpl.Kind.CLASS_SIGNATURE_PARENT_NAME,
superclass));
pre.addContent(link);
}
}
Type[] implIntfacs = classDoc.interfaceTypes();
if (implIntfacs != null && implIntfacs.length > 0) {
int counter = 0;
for (int i = 0; i < implIntfacs.length; i++) {
ClassDoc classDoc = implIntfacs[i].asClassDoc();
if (! (classDoc.isPublic() ||
Util.isLinkable(classDoc, configuration))) {
continue;
}
if (counter == 0) {
pre.addContent(DocletConstants.NL);
pre.addContent(isInterface? "extends " : "implements ");
} else {
pre.addContent(", ");
}
Content link = getLink(new LinkInfoImpl(configuration,
LinkInfoImpl.Kind.CLASS_SIGNATURE_PARENT_NAME,
implIntfacs[i]));
pre.addContent(link);
counter++;
}
}
classInfoTree.addContent(pre);
}
/**
* {@inheritDoc}
*/
public void addClassDescription(Content classInfoTree) {
if(!configuration.nocomment) {
// generate documentation for the class.
if (classDoc.inlineTags().length > 0) {
addInlineComment(classDoc, classInfoTree);
}
}
}
/**
* {@inheritDoc}
*/
public void addClassTagInfo(Content classInfoTree) {
if(!configuration.nocomment) {
// Print Information about all the tags here
addTagsInfo(classDoc, classInfoTree);
}
}
/**
* Get the class hierarchy tree for the given class.
*
* @param type the class to print the hierarchy for
* @return a content tree for class inheritence
*/
private Content getClassInheritenceTree(Type type) {
Type sup;
HtmlTree classTreeUl = new HtmlTree(HtmlTag.UL);
classTreeUl.addStyle(HtmlStyle.inheritance);
Content liTree = null;
do {
sup = Util.getFirstVisibleSuperClass(
type instanceof ClassDoc ? (ClassDoc) type : type.asClassDoc(),
configuration);
if (sup != null) {
HtmlTree ul = new HtmlTree(HtmlTag.UL);
ul.addStyle(HtmlStyle.inheritance);
ul.addContent(getTreeForClassHelper(type));
if (liTree != null)
ul.addContent(liTree);
Content li = HtmlTree.LI(ul);
liTree = li;
type = sup;
}
else
classTreeUl.addContent(getTreeForClassHelper(type));
}
while (sup != null);
if (liTree != null)
classTreeUl.addContent(liTree);
return classTreeUl;
}
/**
* Get the class helper tree for the given class.
*
* @param type the class to print the helper for
* @return a content tree for class helper
*/
private Content getTreeForClassHelper(Type type) {
Content li = new HtmlTree(HtmlTag.LI);
if (type.equals(classDoc)) {
Content typeParameters = getTypeParameterLinks(
new LinkInfoImpl(configuration, LinkInfoImpl.Kind.TREE,
classDoc));
if (configuration.shouldExcludeQualifier(
classDoc.containingPackage().name())) {
li.addContent(type.asClassDoc().name());
li.addContent(typeParameters);
} else {
li.addContent(type.asClassDoc().qualifiedName());
li.addContent(typeParameters);
}
} else {
Content link = getLink(new LinkInfoImpl(configuration,
LinkInfoImpl.Kind.CLASS_TREE_PARENT, type)
.label(configuration.getClassName(type.asClassDoc())));
li.addContent(link);
}
return li;
}
/**
* {@inheritDoc}
*/
public void addClassTree(Content classContentTree) {
if (!classDoc.isClass()) {
return;
}
classContentTree.addContent(getClassInheritenceTree(classDoc));
}
/**
* {@inheritDoc}
*/
public void addTypeParamInfo(Content classInfoTree) {
if (classDoc.typeParamTags().length > 0) {
Content typeParam = (new ParamTaglet()).getTagletOutput(classDoc,
getTagletWriterInstance(false));
Content dl = HtmlTree.DL(typeParam);
classInfoTree.addContent(dl);
}
}
/**
* {@inheritDoc}
*/
public void addSubClassInfo(Content classInfoTree) {
if (classDoc.isClass()) {
if (classDoc.qualifiedName().equals("java.lang.Object") ||
classDoc.qualifiedName().equals("org.omg.CORBA.Object")) {
return; // Don't generate the list, too huge
}
List<ClassDoc> subclasses = classtree.subs(classDoc, false);
if (subclasses.size() > 0) {
Content label = getResource(
"doclet.Subclasses");
Content dt = HtmlTree.DT(label);
Content dl = HtmlTree.DL(dt);
dl.addContent(getClassLinks(LinkInfoImpl.Kind.SUBCLASSES,
subclasses));
classInfoTree.addContent(dl);
}
}
}
/**
* {@inheritDoc}
*/
public void addSubInterfacesInfo(Content classInfoTree) {
if (classDoc.isInterface()) {
List<ClassDoc> subInterfaces = classtree.allSubs(classDoc, false);
if (subInterfaces.size() > 0) {
Content label = getResource(
"doclet.Subinterfaces");
Content dt = HtmlTree.DT(label);
Content dl = HtmlTree.DL(dt);
dl.addContent(getClassLinks(LinkInfoImpl.Kind.SUBINTERFACES,
subInterfaces));
classInfoTree.addContent(dl);
}
}
}
/**
* {@inheritDoc}
*/
public void addInterfaceUsageInfo (Content classInfoTree) {
if (! classDoc.isInterface()) {
return;
}
if (classDoc.qualifiedName().equals("java.lang.Cloneable") ||
classDoc.qualifiedName().equals("java.io.Serializable")) {
return; // Don't generate the list, too big
}
List<ClassDoc> implcl = classtree.implementingclasses(classDoc);
if (implcl.size() > 0) {
Content label = getResource(
"doclet.Implementing_Classes");
Content dt = HtmlTree.DT(label);
Content dl = HtmlTree.DL(dt);
dl.addContent(getClassLinks(LinkInfoImpl.Kind.IMPLEMENTED_CLASSES,
implcl));
classInfoTree.addContent(dl);
}
}
/**
* {@inheritDoc}
*/
public void addImplementedInterfacesInfo(Content classInfoTree) {
//NOTE: we really should be using ClassDoc.interfaceTypes() here, but
// it doesn't walk up the tree like we want it to.
List<Type> interfaceArray = Util.getAllInterfaces(classDoc, configuration);
if (classDoc.isClass() && interfaceArray.size() > 0) {
Content label = getResource(
"doclet.All_Implemented_Interfaces");
Content dt = HtmlTree.DT(label);
Content dl = HtmlTree.DL(dt);
dl.addContent(getClassLinks(LinkInfoImpl.Kind.IMPLEMENTED_INTERFACES,
interfaceArray));
classInfoTree.addContent(dl);
}
}
/**
* {@inheritDoc}
*/
public void addSuperInterfacesInfo(Content classInfoTree) {
//NOTE: we really should be using ClassDoc.interfaceTypes() here, but
// it doesn't walk up the tree like we want it to.
List<Type> interfaceArray = Util.getAllInterfaces(classDoc, configuration);
if (classDoc.isInterface() && interfaceArray.size() > 0) {
Content label = getResource(
"doclet.All_Superinterfaces");
Content dt = HtmlTree.DT(label);
Content dl = HtmlTree.DL(dt);
dl.addContent(getClassLinks(LinkInfoImpl.Kind.SUPER_INTERFACES,
interfaceArray));
classInfoTree.addContent(dl);
}
}
/**
* {@inheritDoc}
*/
public void addNestedClassInfo(Content classInfoTree) {
ClassDoc outerClass = classDoc.containingClass();
if (outerClass != null) {
Content label;
if (outerClass.isInterface()) {
label = getResource(
"doclet.Enclosing_Interface");
} else {
label = getResource(
"doclet.Enclosing_Class");
}
Content dt = HtmlTree.DT(label);
Content dl = HtmlTree.DL(dt);
Content dd = new HtmlTree(HtmlTag.DD);
dd.addContent(getLink(new LinkInfoImpl(configuration,
LinkInfoImpl.Kind.CLASS, outerClass)));
dl.addContent(dd);
classInfoTree.addContent(dl);
}
}
/**
* {@inheritDoc}
*/
public void addFunctionalInterfaceInfo (Content classInfoTree) {
if (classDoc.isFunctionalInterface()) {
Content dt = HtmlTree.DT(getResource("doclet.Functional_Interface"));
Content dl = HtmlTree.DL(dt);
Content dd = new HtmlTree(HtmlTag.DD);
dd.addContent(getResource("doclet.Functional_Interface_Message"));
dl.addContent(dd);
classInfoTree.addContent(dl);
}
}
/**
* {@inheritDoc}
*/
public void addClassDeprecationInfo(Content classInfoTree) {
Content hr = new HtmlTree(HtmlTag.HR);
classInfoTree.addContent(hr);
Tag[] deprs = classDoc.tags("deprecated");
if (Util.isDeprecated(classDoc)) {
Content deprLabel = HtmlTree.SPAN(HtmlStyle.deprecatedLabel, deprecatedPhrase);
Content div = HtmlTree.DIV(HtmlStyle.block, deprLabel);
if (deprs.length > 0) {
Tag[] commentTags = deprs[0].inlineTags();
if (commentTags.length > 0) {
div.addContent(getSpace());
addInlineDeprecatedComment(classDoc, deprs[0], div);
}
}
classInfoTree.addContent(div);
}
}
/**
* Get links to the given classes.
*
* @param context the id of the context where the link will be printed
* @param list the list of classes
* @return a content tree for the class list
*/
private Content getClassLinks(LinkInfoImpl.Kind context, List<?> list) {
Object[] typeList = list.toArray();
Content dd = new HtmlTree(HtmlTag.DD);
for (int i = 0; i < list.size(); i++) {
if (i > 0) {
Content separator = new StringContent(", ");
dd.addContent(separator);
}
if (typeList[i] instanceof ClassDoc) {
Content link = getLink(
new LinkInfoImpl(configuration, context, (ClassDoc)(typeList[i])));
dd.addContent(link);
} else {
Content link = getLink(
new LinkInfoImpl(configuration, context, (Type)(typeList[i])));
dd.addContent(link);
}
}
return dd;
}
/**
* {@inheritDoc}
*/
protected Content getNavLinkTree() {
Content treeLinkContent = getHyperLink(DocPaths.PACKAGE_TREE,
treeLabel, "", "");
Content li = HtmlTree.LI(treeLinkContent);
return li;
}
/**
* Add summary details to the navigation bar.
*
* @param subDiv the content tree to which the summary detail links will be added
*/
protected void addSummaryDetailLinks(Content subDiv) {
try {
Content div = HtmlTree.DIV(getNavSummaryLinks());
div.addContent(getNavDetailLinks());
subDiv.addContent(div);
} catch (Exception e) {
e.printStackTrace();
throw new DocletAbortException(e);
}
}
/**
* Get summary links for navigation bar.
*
* @return the content tree for the navigation summary links
*/
protected Content getNavSummaryLinks() throws Exception {
Content li = HtmlTree.LI(summaryLabel);
li.addContent(getSpace());
Content ulNav = HtmlTree.UL(HtmlStyle.subNavList, li);
MemberSummaryBuilder memberSummaryBuilder = (MemberSummaryBuilder)
configuration.getBuilderFactory().getMemberSummaryBuilder(this);
String[] navLinkLabels = new String[] {
"doclet.navNested", "doclet.navEnum", "doclet.navField", "doclet.navConstructor",
"doclet.navMethod"
};
for (int i = 0; i < navLinkLabels.length; i++ ) {
Content liNav = new HtmlTree(HtmlTag.LI);
if (i == VisibleMemberMap.ENUM_CONSTANTS && ! classDoc.isEnum()) {
continue;
}
if (i == VisibleMemberMap.CONSTRUCTORS && classDoc.isEnum()) {
continue;
}
AbstractMemberWriter writer =
((AbstractMemberWriter) memberSummaryBuilder.
getMemberSummaryWriter(i));
if (writer == null) {
liNav.addContent(getResource(navLinkLabels[i]));
} else {
writer.addNavSummaryLink(
memberSummaryBuilder.members(i),
memberSummaryBuilder.getVisibleMemberMap(i), liNav);
}
if (i < navLinkLabels.length-1) {
addNavGap(liNav);
}
ulNav.addContent(liNav);
}
return ulNav;
}
/**
* Get detail links for the navigation bar.
*
* @return the content tree for the detail links
*/
protected Content getNavDetailLinks() throws Exception {
Content li = HtmlTree.LI(detailLabel);
li.addContent(getSpace());
Content ulNav = HtmlTree.UL(HtmlStyle.subNavList, li);
MemberSummaryBuilder memberSummaryBuilder = (MemberSummaryBuilder)
configuration.getBuilderFactory().getMemberSummaryBuilder(this);
String[] navLinkLabels = new String[] {
"doclet.navNested", "doclet.navEnum", "doclet.navField", "doclet.navConstructor",
"doclet.navMethod"
};
for (int i = 1; i < navLinkLabels.length; i++ ) {
Content liNav = new HtmlTree(HtmlTag.LI);
AbstractMemberWriter writer =
((AbstractMemberWriter) memberSummaryBuilder.
getMemberSummaryWriter(i));
if (i == VisibleMemberMap.ENUM_CONSTANTS && ! classDoc.isEnum()) {
continue;
}
if (i == VisibleMemberMap.CONSTRUCTORS && classDoc.isEnum()) {
continue;
}
if (writer == null) {
liNav.addContent(getResource(navLinkLabels[i]));
} else {
writer.addNavDetailLink(memberSummaryBuilder.members(i), liNav);
}
if (i < navLinkLabels.length - 1) {
addNavGap(liNav);
}
ulNav.addContent(liNav);
}
return ulNav;
}
/**
* Add gap between navigation bar elements.
*
* @param liNav the content tree to which the gap will be added
*/
protected void addNavGap(Content liNav) {
liNav.addContent(getSpace());
liNav.addContent("|");
liNav.addContent(getSpace());
}
/**
* Return the classDoc being documented.
*
* @return the classDoc being documented.
*/
public ClassDoc getClassDoc() {
return classDoc;
}
}