/*
* Copyright (c) 1997, 2005, 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 com.sun.tools.doclets.internal.toolkit.*;
import com.sun.tools.doclets.internal.toolkit.util.*;
import com.sun.tools.doclets.internal.toolkit.builders.*;
import com.sun.javadoc.*;
import java.util.*;
import com.sun.tools.doclets.internal.toolkit.taglets.*;
/**
* Generate the Class Information Page.
* @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
*/
public class ClassWriterImpl extends SubWriterHolderWriter
implements ClassWriter {
protected ClassDoc classDoc;
protected ClassTree classtree;
protected ClassDoc prev;
protected ClassDoc next;
/**
* @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 (ClassDoc classDoc,
ClassDoc prevClass, ClassDoc nextClass, ClassTree classTree)
throws Exception {
super(ConfigurationImpl.getInstance(),
DirectoryManager.getDirectoryPath(classDoc.containingPackage()),
classDoc.name() + ".html",
DirectoryManager.getRelativePath(classDoc.containingPackage().name()));
this.classDoc = classDoc;
configuration.currentcd = classDoc;
this.classtree = classTree;
this.prev = prevClass;
this.next = nextClass;
}
/**
* Print this package link
*/
protected void navLinkPackage() {
navCellStart();
printHyperLink("package-summary.html", "",
configuration.getText("doclet.Package"), true, "NavBarFont1");
navCellEnd();
}
/**
* Print class page indicator
*/
protected void navLinkClass() {
navCellRevStart();
fontStyle("NavBarFont1Rev");
boldText("doclet.Class");
fontEnd();
navCellEnd();
}
/**
* Print class use link
*/
protected void navLinkClassUse() {
navCellStart();
printHyperLink("class-use/" + filename, "",
configuration.getText("doclet.navClassUse"), true, "NavBarFont1");
navCellEnd();
}
/**
* Print previous package link
*/
protected void navLinkPrevious() {
if (prev == null) {
printText("doclet.Prev_Class");
} else {
printLink(new LinkInfoImpl(LinkInfoImpl.CONTEXT_CLASS, prev, "",
configuration.getText("doclet.Prev_Class"), true));
}
}
/**
* Print next package link
*/
protected void navLinkNext() {
if (next == null) {
printText("doclet.Next_Class");
} else {
printLink(new LinkInfoImpl(LinkInfoImpl.CONTEXT_CLASS, next, "",
configuration.getText("doclet.Next_Class"), true));
}
}
/**
* {@inheritDoc}
*/
public void writeHeader(String header) {
String pkgname = (classDoc.containingPackage() != null)?
classDoc.containingPackage().name(): "";
String clname = classDoc.name();
printHtmlHeader(clname,
configuration.metakeywords.getMetaKeywords(classDoc), true);
printTop();
navLinks(true);
hr();
println("<!-- ======== START OF CLASS DATA ======== -->");
h2();
if (pkgname.length() > 0) {
font("-1"); print(pkgname); fontEnd(); br();
}
LinkInfoImpl linkInfo = new LinkInfoImpl( LinkInfoImpl.CONTEXT_CLASS_HEADER,
classDoc, false);
//Let's not link to ourselves in the header.
linkInfo.linkToSelf = false;
print(header + getTypeParameterLinks(linkInfo));
h2End();
}
/**
* {@inheritDoc}
*/
public void writeFooter() {
println("<!-- ========= END OF CLASS DATA ========= -->");
hr();
navLinks(false);
printBottom();
printBodyHtmlEnd();
}
/**
* {@inheritDoc}
*/
public void writeClassSignature(String modifiers) {
boolean isInterface = classDoc.isInterface();
dl();
dt();
preNoNewLine();
writeAnnotationInfo(classDoc);
print(modifiers);
LinkInfoImpl linkInfo = new LinkInfoImpl(
LinkInfoImpl.CONTEXT_CLASS_SIGNATURE, classDoc, false);
//Let's not link to ourselves in the signature.
linkInfo.linkToSelf = false;
String name = classDoc.name() +
getTypeParameterLinks(linkInfo);
if (configuration().linksource) {
printSrcLink(classDoc, name);
} else {
bold(name);
}
if (!isInterface) {
Type superclass = Util.getFirstVisibleSuperClass(classDoc,
configuration());
if (superclass != null) {
dt();
print("extends ");
printLink(new LinkInfoImpl(
LinkInfoImpl.CONTEXT_CLASS_SIGNATURE_PARENT_NAME,
superclass));
}
}
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) {
dt();
print(isInterface? "extends " : "implements ");
} else {
print(", ");
}
printLink(new LinkInfoImpl(
LinkInfoImpl.CONTEXT_CLASS_SIGNATURE_PARENT_NAME,
implIntfacs[i]));
counter++;
}
}
dlEnd();
preEnd();
p();
}
/**
* {@inheritDoc}
*/
public void writeClassDescription() {
if(!configuration.nocomment) {
// generate documentation for the class.
if (classDoc.inlineTags().length > 0) {
printInlineComment(classDoc);
p();
}
}
}
/**
* {@inheritDoc}
*/
public void writeClassTagInfo() {
if(!configuration.nocomment) {
// Print Information about all the tags here
printTags(classDoc);
hr();
p();
} else {
hr();
}
}
/**
* {@inheritDoc}
*/
public void writeClassDeprecationInfo() {
hr();
Tag[] deprs = classDoc.tags("deprecated");
if (Util.isDeprecated(classDoc)) {
boldText("doclet.Deprecated");
if (deprs.length > 0) {
Tag[] commentTags = deprs[0].inlineTags();
if (commentTags.length > 0) {
space();
printInlineDeprecatedComment(classDoc, deprs[0]);
}
}
p();
}
}
/**
* Generate the indent and get the line image for the class tree.
* For user accessibility, the image includes the alt attribute
* "extended by". (This method is not intended for a class
* implementing an interface, where "implemented by" would be required.)
*
* indent integer indicating the number of spaces to indent
*/
private void writeStep(int indent) {
print(spaces(4 * indent - 2));
print("<IMG SRC=\"" + relativepathNoSlash + "/resources/inherit.gif\" " +
"ALT=\"" + configuration.getText("doclet.extended_by") + " \">");
}
/**
* Print the class hierarchy tree for the given class.
* @param type the class to print the hierarchy for.
* @return return the amount that should be indented in
* the next level of the tree.
*/
private int writeTreeForClassHelper(Type type) {
Type sup = Util.getFirstVisibleSuperClass(
type instanceof ClassDoc ? (ClassDoc) type : type.asClassDoc(),
configuration());
int indent = 0;
if (sup != null) {
indent = writeTreeForClassHelper(sup);
writeStep(indent);
}
if (type.equals(classDoc)) {
String typeParameters = getTypeParameterLinks(
new LinkInfoImpl(
LinkInfoImpl.CONTEXT_TREE,
classDoc, false));
if (configuration.shouldExcludeQualifier(
classDoc.containingPackage().name())) {
bold(type.asClassDoc().name() + typeParameters);
} else {
bold(type.asClassDoc().qualifiedName() + typeParameters);
}
} else {
print(getLink(new LinkInfoImpl(LinkInfoImpl.CONTEXT_CLASS_TREE_PARENT,
type instanceof ClassDoc ? (ClassDoc) type : type,
configuration.getClassName(type.asClassDoc()), false)));
}
println();
return indent + 1;
}
/**
* Print the class hierarchy tree for this class only.
*/
public void writeClassTree() {
if (! classDoc.isClass()) {
return;
}
pre();
writeTreeForClassHelper(classDoc);
preEnd();
}
/**
* Write the type parameter information.
*/
public void writeTypeParamInfo() {
if (classDoc.typeParamTags().length > 0) {
dl();
dt();
TagletOutput output = (new ParamTaglet()).getTagletOutput(classDoc,
getTagletWriterInstance(false));
print(output.toString());
dlEnd();
}
}
/**
* {@inheritDoc}
*/
public void writeSubClassInfo() {
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 subclasses = classtree.subs(classDoc, false);
if (subclasses.size() > 0) {
dl();
dt();
boldText("doclet.Subclasses");
writeClassLinks(LinkInfoImpl.CONTEXT_SUBCLASSES,
subclasses);
}
}
}
/**
* {@inheritDoc}
*/
public void writeSubInterfacesInfo() {
if (classDoc.isInterface()) {
List subInterfaces = classtree.allSubs(classDoc, false);
if (subInterfaces.size() > 0) {
dl();
dt();
boldText("doclet.Subinterfaces");
writeClassLinks(LinkInfoImpl.CONTEXT_SUBINTERFACES,
subInterfaces);
}
}
}
/**
* If this is the interface which are the classes, that implement this?
*/
public void writeInterfaceUsageInfo () {
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 implcl = classtree.implementingclasses(classDoc);
if (implcl.size() > 0) {
dl();
dt();
boldText("doclet.Implementing_Classes");
writeClassLinks(LinkInfoImpl.CONTEXT_IMPLEMENTED_CLASSES,
implcl);
}
}
/**
* {@inheritDoc}
*/
public void writeImplementedInterfacesInfo() {
//NOTE: we really should be using ClassDoc.interfaceTypes() here, but
// it doesn't walk up the tree like we want it to.
List interfaceArray = Util.getAllInterfaces(classDoc, configuration);
if (classDoc.isClass() && interfaceArray.size() > 0) {
dl();
dt();
boldText("doclet.All_Implemented_Interfaces");
writeClassLinks(LinkInfoImpl.CONTEXT_IMPLEMENTED_INTERFACES,
interfaceArray);
}
}
/**
* {@inheritDoc}
*/
public void writeSuperInterfacesInfo() {
//NOTE: we really should be using ClassDoc.interfaceTypes() here, but
// it doesn't walk up the tree like we want it to.
List interfaceArray = Util.getAllInterfaces(classDoc, configuration);
if (classDoc.isInterface() && interfaceArray.size() > 0) {
dl();
dt();
boldText("doclet.All_Superinterfaces");
writeClassLinks(LinkInfoImpl.CONTEXT_SUPER_INTERFACES,
interfaceArray);
}
}
/**
* Generate links to the given classes.
*/
private void writeClassLinks(int context, List list) {
Object[] typeList = list.toArray();
//Sort the list to be printed.
print(' ');
dd();
for (int i = 0; i < list.size(); i++) {
if (i > 0) {
print(", ");
}
if (typeList[i] instanceof ClassDoc) {
printLink(new LinkInfoImpl(context, (ClassDoc)(typeList[i])));
} else {
printLink(new LinkInfoImpl(context, (Type)(typeList[i])));
}
}
ddEnd();
dlEnd();
}
protected void navLinkTree() {
navCellStart();
printHyperLink("package-tree.html", "",
configuration.getText("doclet.Tree"), true, "NavBarFont1");
navCellEnd();
}
protected void printSummaryDetailLinks() {
try {
tr();
tdVAlignClass("top", "NavBarCell3");
font("-2");
print(" ");
navSummaryLinks();
fontEnd();
tdEnd();
tdVAlignClass("top", "NavBarCell3");
font("-2");
navDetailLinks();
fontEnd();
tdEnd();
trEnd();
} catch (Exception e) {
e.printStackTrace();
throw new DocletAbortException();
}
}
protected void navSummaryLinks() throws Exception {
printText("doclet.Summary");
space();
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++ ) {
if (i == VisibleMemberMap.ENUM_CONSTANTS && ! classDoc.isEnum()) {
continue;
}
if (i == VisibleMemberMap.CONSTRUCTORS && classDoc.isEnum()) {
continue;
}
AbstractMemberWriter writer =
((AbstractMemberWriter) memberSummaryBuilder.
getMemberSummaryWriter(i));
if (writer == null) {
printText(navLinkLabels[i]);
} else {
writer.navSummaryLink(
memberSummaryBuilder.members(i),
memberSummaryBuilder.getVisibleMemberMap(i));
}
if (i < navLinkLabels.length-1) {
navGap();
}
}
}
/**
* Method navDetailLinks
*
* @throws Exception
*
*/
protected void navDetailLinks() throws Exception {
printText("doclet.Detail");
space();
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++ ) {
AbstractMemberWriter writer =
((AbstractMemberWriter) memberSummaryBuilder.
getMemberSummaryWriter(i));
if (i == VisibleMemberMap.ENUM_CONSTANTS && ! classDoc.isEnum()) {
continue;
}
if (i == VisibleMemberMap.CONSTRUCTORS && classDoc.isEnum()) {
continue;
}
if (writer == null) {
printText(navLinkLabels[i]);
} else {
writer.navDetailLink(memberSummaryBuilder.members(i));
}
if (i < navLinkLabels.length - 1) {
navGap();
}
}
}
protected void navGap() {
space();
print('|');
space();
}
/**
* If this is an inner class or interface, write the enclosing class or
* interface.
*/
public void writeNestedClassInfo() {
ClassDoc outerClass = classDoc.containingClass();
if (outerClass != null) {
dl();
dt();
if (outerClass.isInterface()) {
boldText("doclet.Enclosing_Interface");
} else {
boldText("doclet.Enclosing_Class");
}
dd();
printLink(new LinkInfoImpl(LinkInfoImpl.CONTEXT_CLASS, outerClass,
false));
ddEnd();
dlEnd();
}
}
/**
* Return the classDoc being documented.
*
* @return the classDoc being documented.
*/
public ClassDoc getClassDoc() {
return classDoc;
}
/**
* {@inheritDoc}
*/
public void completeMemberSummaryBuild() {
p();
}
}