/* gnu.classpath.tools.doclets.htmldoclet.HtmlDoclet Copyright (C) 2004 Free Software Foundation, Inc. This file is part of GNU Classpath. GNU Classpath is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. GNU Classpath 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 for more details. You should have received a copy of the GNU General Public License along with GNU Classpath; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ package gnu.classpath.tools.doclets.htmldoclet; import gnu.classpath.tools.IOToolkit; import gnu.classpath.tools.doclets.AbstractDoclet; import gnu.classpath.tools.doclets.DocletOption; import gnu.classpath.tools.doclets.DocletOptionFile; import gnu.classpath.tools.doclets.DocletOptionFlag; import gnu.classpath.tools.doclets.DocletOptionString; import gnu.classpath.tools.doclets.PackageGroup; import gnu.classpath.tools.doclets.TagletPrinter; import gnu.classpath.tools.taglets.TagletContext; import gnu.classpath.tools.java2xhtml.Java2xhtml; import com.sun.javadoc.*; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.FileReader; import java.io.FileWriter; import java.io.InputStream; import java.io.IOException; import java.io.StringWriter; import java.util.HashMap; import java.util.Iterator; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Properties; import java.util.Set; import java.util.SortedSet; import java.util.TreeSet; public class HtmlDoclet extends AbstractDoclet { private static String filenameExtension = ".html"; private void printNavBar(HtmlPage output, String currentPage, ClassDoc currentClass) { output.beginDiv(CssClass.NAVBAR_TOP); boolean overviewLevel = ("overview".equals(currentPage) || "full-tree".equals(currentPage) || "alpha-index".equals(currentPage)); if ("overview".equals(currentPage)) { output.beginSpan(CssClass.NAVBAR_ITEM_ACTIVE); output.print("Overview"); output.endSpan(CssClass.NAVBAR_ITEM_ACTIVE); } else { output.beginSpan(CssClass.NAVBAR_ITEM_ENABLED); output.beginAnchor(output.getPathToRoot() + "index-noframes" + filenameExtension); output.print("Overview"); output.endAnchor(); output.endSpan(CssClass.NAVBAR_ITEM_ENABLED); } output.print(" "); if (!overviewLevel) { if ("package".equals(currentPage)) { output.beginSpan(CssClass.NAVBAR_ITEM_ACTIVE); output.print("Package"); output.endSpan(CssClass.NAVBAR_ITEM_ACTIVE); } else { output.beginSpan(CssClass.NAVBAR_ITEM_ENABLED); output.beginAnchor("index" + filenameExtension); output.print("Package"); output.endAnchor(); output.endSpan(CssClass.NAVBAR_ITEM_ENABLED); } } else { output.beginSpan(CssClass.NAVBAR_ITEM_DISABLED); output.print("Package"); output.endSpan(CssClass.NAVBAR_ITEM_DISABLED); } if (optionUse.getValue() || optionLinkSource.getValue()) { output.print(" "); if (null != currentClass) { if ("class".equals(currentPage)) { output.beginSpan(CssClass.NAVBAR_ITEM_ACTIVE); output.print("Class"); output.endSpan(CssClass.NAVBAR_ITEM_ACTIVE); } else { output.beginSpan(CssClass.NAVBAR_ITEM_ENABLED); output.beginAnchor(currentClass.name() + filenameExtension); output.print("Class"); output.endAnchor(); output.endSpan(CssClass.NAVBAR_ITEM_ENABLED); } } else { output.beginSpan(CssClass.NAVBAR_ITEM_DISABLED); output.print("Class"); output.endSpan(CssClass.NAVBAR_ITEM_DISABLED); } if (optionUse.getValue()) { output.print(" "); if (null != currentClass) { output.beginSpan(CssClass.NAVBAR_ITEM_ENABLED); output.beginAnchor(currentClass.name() + "-uses" + filenameExtension); output.print("Use"); output.endAnchor(); output.endSpan(CssClass.NAVBAR_ITEM_ENABLED); } else { output.beginSpan(CssClass.NAVBAR_ITEM_DISABLED); output.print("Use"); output.endSpan(CssClass.NAVBAR_ITEM_DISABLED); } } if (optionLinkSource.getValue()) { output.print(" "); if (null != currentClass) { output.beginSpan(CssClass.NAVBAR_ITEM_ENABLED); String targetClassName = currentClass.name(); String targetAnchor = ""; if (null != currentClass.containingClass()) { targetClassName = getOuterClassDoc(currentClass).name(); targetAnchor = "#line." + currentClass.position().line(); } output.beginAnchor(targetClassName + "-source" + filenameExtension + targetAnchor); output.print("Source"); output.endAnchor(); output.endSpan(CssClass.NAVBAR_ITEM_ENABLED); } else { output.beginSpan(CssClass.NAVBAR_ITEM_DISABLED); output.print("Source"); output.endSpan(CssClass.NAVBAR_ITEM_DISABLED); } } } if (!optionNoTree.getValue()) { output.print(" "); if ("tree".equals(currentPage) || "package-tree".equals(currentPage)) { output.beginSpan(CssClass.NAVBAR_ITEM_ACTIVE); output.print("Tree"); output.endSpan(CssClass.NAVBAR_ITEM_ACTIVE); } else { output.beginSpan(CssClass.NAVBAR_ITEM_ENABLED); output.beginAnchor("tree" + filenameExtension); output.print("Tree"); output.endAnchor(); output.endSpan(CssClass.NAVBAR_ITEM_ENABLED); } } output.print(" "); String indexName; if (optionSplitIndex.getValue()) { indexName = "alphaindex-1"; } else { indexName = "alphaindex"; } output.beginAnchor(output.getPathToRoot() + indexName + filenameExtension); output.print("Index"); output.endAnchor(); if (!optionNoDeprecatedList.getValue()) { output.print(" "); output.beginAnchor(output.getPathToRoot() + "deprecated" + filenameExtension); output.print("Deprecated"); output.endAnchor(); } if (!optionNoHelp.getValue()) { output.print(" "); output.beginAnchor(output.getPathToRoot() + "help" + filenameExtension); output.print("Help"); output.endAnchor(); } output.print(" "); output.beginAnchor(output.getPathToRoot() + "about" + filenameExtension); output.print("About"); output.endAnchor(); output.endDiv(CssClass.NAVBAR_TOP); } private void printNavBarTop(HtmlPage output, String currentPage) { printNavBarTop(output, currentPage, null); } private void printNavBarTop(HtmlPage output, String currentPage, ClassDoc currentClass) { if (!optionNoNavBar.getValue()) { output.beginTable(CssClass.NAVBAR_TOP); output.beginRow(); output.beginCell(); printNavBar(output, currentPage, currentClass); output.endCell(); if (null != optionHeader.getValue()) { output.beginCell(); output.print(optionHeader.getValue()); output.endCell(); } output.endRow(); output.endTable(); } } private void printNavBarBottom(HtmlPage output, String currentPage) { printNavBarBottom(output, currentPage, null); } private void printNavBarBottom(HtmlPage output, String currentPage, ClassDoc currentClass) { if (!optionNoNavBar.getValue()) { output.beginDiv(CssClass.NAVBAR_BOTTOM_SPACER); output.print(" "); output.endDiv(CssClass.NAVBAR_BOTTOM_SPACER); output.beginTable(CssClass.NAVBAR_BOTTOM); output.beginRow(); output.beginCell(); printNavBar(output, currentPage, currentClass); output.endCell(); if (null != optionFooter.getValue()) { output.beginCell(); output.print(optionFooter.getValue()); output.endCell(); } output.endRow(); output.endTable(); } if (null != optionBottom.getValue()) { output.hr(); output.print(optionBottom.getValue()); } } private void printPackagePageClasses(HtmlPage output, ClassDoc[] classDocs, String header) { if (classDocs.length > 0) { output.beginTable(CssClass.PACKAGE_SUMMARY); output.rowDiv(CssClass.TABLE_HEADER, header); for (int i=0; i 0) { for (int i=0; i"); if (null == rootNode) { rootNode = new TreeNode(null); treeMap.put("", rootNode); } rootNode.children.add(node); } } return node; } private void printPackageTreeRec(HtmlPage output, TreeNode node) { output.beginElement("li"); if (node.classDoc.isIncluded()) { output.print(node.classDoc.containingPackage().name()); output.print("."); printType(output, node.classDoc); } else { output.print(node.classDoc.qualifiedName()); } output.endElement("li"); output.beginElement("ul"); Iterator it = node.children.iterator(); while (it.hasNext()) { TreeNode child = (TreeNode)it.next(); printPackageTreeRec(output, child); } output.endElement("ul"); } private void printClassTree(HtmlPage output, ClassDoc[] classDocs) { Map classTreeMap = new HashMap(); for (int i=0; i"); if (null != interfaceRoot) { Iterator it = interfaceRoot.children.iterator(); if (it.hasNext()) { output.div(CssClass.PACKAGE_TREE_SECTION_TITLE, "Interface Hierarchy"); output.beginElement("ul"); while (it.hasNext()) { TreeNode node = (TreeNode)it.next(); printPackageTreeRec(output, node); } output.endElement("ul"); } } } private void printPackageTreePage(File packageDir, String pathToRoot, PackageDoc packageDoc) throws IOException { HtmlPage output = new HtmlPage(new File(packageDir, "tree" + filenameExtension), pathToRoot); output.beginPage(packageDoc.name() + " Hierarchy"); output.beginBody(); printNavBarTop(output, "package-tree"); output.div(CssClass.PACKAGE_TREE_TITLE, "Hierarchy for Package " + packageDoc.name()); ClassDoc[] classDocs = packageDoc.allClasses(); printClassTree(output, classDocs); printInterfaceTree(output, classDocs); printNavBarBottom(output, "package-tree"); output.endBody(); output.endPage(); output.close(); } private void printFullTreePage() throws IOException { HtmlPage output = new HtmlPage(new File(getTargetDirectory(), "tree" + filenameExtension), ""); output.beginPage("Hierarchy"); output.beginBody(); printNavBarTop(output, "full-tree"); output.div(CssClass.PACKAGE_TREE_TITLE, "Hierarchy"); ClassDoc[] classDocs = getRootDoc().classes(); printClassTree(output, classDocs); printInterfaceTree(output, classDocs); printNavBarBottom(output, "full-tree"); output.endBody(); output.endPage(); output.close(); } private void printIndexEntry(HtmlPage output, Doc entry) { output.beginDiv(CssClass.INDEX_ENTRY); String anchor = null; String description = null; if (entry instanceof PackageDoc) { output.beginAnchor(getPackageURL((PackageDoc)entry) + "index" + filenameExtension); output.print(entry.name()); output.endAnchor(); output.print(" - package"); } else if (entry instanceof ClassDoc) { ClassDoc classDoc = (ClassDoc)entry; output.beginAnchor(getClassURL(classDoc)); output.print(entry.name()); output.endAnchor(); output.print(" - "); if (entry.isInterface()) { output.print("interface "); } else if (entry.isException()) { output.print("exception "); } else if (entry.isError()) { output.print("error "); } else { output.print("class "); } output.print(classDoc.containingPackage().name()); output.print("."); printType(output, classDoc); } else { ProgramElementDoc memberDoc = (ProgramElementDoc)entry; output.beginAnchor(getMemberDocURL(output, memberDoc)); output.print(entry.name()); if (memberDoc instanceof ExecutableMemberDoc) { output.print(((ExecutableMemberDoc)memberDoc).signature()); } output.endAnchor(); output.print(" - "); if (memberDoc.isStatic()) { output.print("static "); } if (entry.isConstructor()) { output.print("constructor for class "); } else if (entry.isMethod()) { output.print("method in class "); } else if (entry.isField()) { output.print("field in class "); } ClassDoc containingClass = memberDoc.containingClass(); output.print(containingClass.containingPackage().name()); output.print("."); printType(output, containingClass); } output.beginDiv(CssClass.INDEX_ENTRY_DESCRIPTION); printTags(output, entry.firstSentenceTags()); output.endDiv(CssClass.INDEX_ENTRY_DESCRIPTION); output.endDiv(CssClass.INDEX_ENTRY); } private void printFrameSetPage() throws IOException { HtmlPage output = new HtmlPage(new File(getTargetDirectory(), "index" + filenameExtension), "", HtmlPage.DOCTYPE_FRAMESET); String title; if (null == optionWindowTitle.getValue()) { title = "Generated API Documentation"; } else { title = optionWindowTitle.getValue(); } output.beginPage(title); output.beginElement("frameset", "cols", "20%,80%"); output.beginElement("frameset", "rows", "25%,75%"); output.atomicElement("frame", new String[] { "src", "name" }, new String[] { "all-packages" + filenameExtension, "packages" }); output.atomicElement("frame", new String[] { "src", "name" }, new String[] { "all-classes" + filenameExtension, "classes" }); output.endElement("frameset"); output.atomicElement("frame", new String[] { "src", "name" }, new String[] { "index-noframes" + filenameExtension, "content" }); output.endElement("frameset"); output.endPage(); output.close(); } private void printPackagesMenuPage() throws IOException { HtmlPage output = new HtmlPage(new File(getTargetDirectory(), "all-packages" + filenameExtension), ""); output.beginPage("Package Menu"); output.beginBody(); output.div(CssClass.PACKAGE_MENU_TITLE, "Packages"); output.beginDiv(CssClass.PACKAGE_MENU_LIST); PackageDoc[] packageDocs = getRootDoc().specifiedPackages(); for (int i=0; i 0) { if (classDoc.isInterface()) { deprecatedInterfaces.add(classDoc); } else if (classDoc.isException()) { deprecatedExceptions.add(classDoc); } else if (classDoc.isError()) { deprecatedErrors.add(classDoc); } else { deprecatedClasses.add(classDoc); } } } ConstructorDoc[] constructors = classDoc.constructors(); for (int j=0; j 0) { deprecatedConstructors.add(constructors[j]); } } MethodDoc[] methods = classDoc.methods(); for (int j=0; j 0) { deprecatedMethods.add(methods[j]); } } FieldDoc[] fields = classDoc.fields(); for (int j=0; j 0) { deprecatedFields.add(fields[j]); } } } output.beginDiv(CssClass.DEPRECATION_TOC); output.div(CssClass.DEPRECATION_TOC_HEADER, "Contents"); output.beginDiv(CssClass.DEPRECATION_TOC_LIST); if (!deprecatedInterfaces.isEmpty()) { output.beginDiv(CssClass.DEPRECATION_TOC_ENTRY); output.anchor("#interfaces", "Deprecated Interfaces"); output.endDiv(CssClass.DEPRECATION_TOC_ENTRY); } if (!deprecatedClasses.isEmpty()) { output.beginDiv(CssClass.DEPRECATION_TOC_ENTRY); output.anchor("#classes", "Deprecated Classes"); output.endDiv(CssClass.DEPRECATION_TOC_ENTRY); } if (!deprecatedExceptions.isEmpty()) { output.beginDiv(CssClass.DEPRECATION_TOC_ENTRY); output.anchor("#exceptions", "Deprecated Exceptions"); output.endDiv(CssClass.DEPRECATION_TOC_ENTRY); } if (!deprecatedErrors.isEmpty()) { output.beginDiv(CssClass.DEPRECATION_TOC_ENTRY); output.anchor("#errors", "Deprecated Errors"); output.endDiv(CssClass.DEPRECATION_TOC_ENTRY); } if (!deprecatedFields.isEmpty()) { output.beginDiv(CssClass.DEPRECATION_TOC_ENTRY); output.anchor("#fields", "Deprecated Fields"); output.endDiv(CssClass.DEPRECATION_TOC_ENTRY); } if (!deprecatedFields.isEmpty()) { output.beginDiv(CssClass.DEPRECATION_TOC_ENTRY); output.anchor("#methods", "Deprecated Methods"); output.endDiv(CssClass.DEPRECATION_TOC_ENTRY); } if (!deprecatedFields.isEmpty()) { output.beginDiv(CssClass.DEPRECATION_TOC_ENTRY); output.anchor("#constructors", "Deprecated Constructors"); output.endDiv(CssClass.DEPRECATION_TOC_ENTRY); } output.endDiv(CssClass.DEPRECATION_TOC_LIST); output.endDiv(CssClass.DEPRECATION_TOC); output.anchorName("interfaces"); printDeprecationSummary(output, deprecatedInterfaces, "Deprecated Interfaces"); output.anchorName("classes"); printDeprecationSummary(output, deprecatedClasses, "Deprecated Classes"); output.anchorName("exceptions"); printDeprecationSummary(output, deprecatedExceptions, "Deprecated Exceptions"); output.anchorName("errors"); printDeprecationSummary(output, deprecatedErrors, "Deprecated Errors"); output.anchorName("fields"); printDeprecationSummary(output, deprecatedFields, "Deprecated Fields"); output.anchorName("methods"); printDeprecationSummary(output, deprecatedMethods, "Deprecated Methods"); output.anchorName("constructors"); printDeprecationSummary(output, deprecatedConstructors, "Deprecated Constructors"); printNavBarBottom(output, "deprecated"); output.endBody(); output.endPage(); output.close(); } private void printOverviewPage() throws IOException { HtmlPage output = new HtmlPage(new File(getTargetDirectory(), "index-noframes" + filenameExtension), ""); output.beginPage("Overview"); output.beginBody(); printNavBarTop(output, "overview"); String overviewHeader; if (null == optionDocTitle.getValue()) { overviewHeader = "Overview"; } else { overviewHeader = optionDocTitle.getValue(); } output.div(CssClass.OVERVIEW_TITLE, overviewHeader); /* output.beginDiv(CssClass.PACKAGE_DESCRIPTION_TOP); printTags(output, packageDoc.firstSentenceTags()); output.endDiv(CssClass.PACKAGE_DESCRIPTION_TOP); */ List packageGroups = getPackageGroups(); if (packageGroups.isEmpty()) { printOverviewPackages(output, getRootDoc().specifiedPackages(), "All Packages"); } else { Iterator it = packageGroups.iterator(); while (it.hasNext()) { PackageGroup packageGroup = (PackageGroup)it.next(); printOverviewPackages(output, (PackageDoc[])packageGroup.getPackages().toArray(new PackageDoc[0]), packageGroup.getName()); } } /* output.anchorName("description"); output.beginDiv(CssClass.PACKAGE_DESCRIPTION_FULL); printTags(output, packageDoc.inlineTags()); output.endDiv(CssClass.PACKAGE_DESCRIPTION_FULL); */ printNavBarBottom(output, "overview"); output.endBody(); output.endPage(); output.close(); } private void printOverviewPackages(HtmlPage output, PackageDoc[] packageDocs, String header) { output.beginTable(CssClass.OVERVIEW_SUMMARY); output.rowDiv(CssClass.TABLE_HEADER, header); for (int i=0; i 0) { output.beginDiv(CssClass.CLASS_SYNOPSIS_IMPLEMENTS); output.print("implements "); for (int i=0; i0) { output.print(", "); } printType(output, interfaces[i]); } output.endDiv(CssClass.CLASS_SYNOPSIS_IMPLEMENTS); } output.endDiv(CssClass.CLASS_SYNOPSIS); output.hr(); output.beginDiv(CssClass.CLASS_DESCRIPTION); printTags(output, classDoc.inlineTags()); output.endDiv(CssClass.CLASS_DESCRIPTION); printTaglets(output, classDoc.tags(), TagletContext.TYPE); printProgramElementDocs(output, classDoc.fields(), "Field Summary"); printProgramElementDocs(output, classDoc.constructors(), "Constructor Summary"); printProgramElementDocs(output, classDoc.methods(), "Method Summary"); ClassDoc superClassDoc = classDoc.superclass(); while (null != superClassDoc) { printInheritedMembers(output, superClassDoc.methods(), "Methods inherited from " + superClassDoc.qualifiedName()); superClassDoc = superClassDoc.superclass(); } printMemberDetails(output, classDoc.fields(), "Field Details"); printMemberDetails(output, classDoc.constructors(), "Constructor Details"); printMemberDetails(output, classDoc.methods(), "Method Details"); printNavBarBottom(output, "class", classDoc); output.endBody(); output.endPage(); output.close(); } private void printInheritedMembers(HtmlPage output, ProgramElementDoc[] memberDocs, String header) { if (memberDocs.length > 0) { output.beginTable(CssClass.CLASS_SUMMARY); output.rowDiv(CssClass.TABLE_HEADER, header); output.beginRow(); output.beginCell(); for (int i=0; i 0) { output.print(", "); } output.beginAnchor(getMemberDocURL(output, memberDoc)); output.print(memberDoc.name()); output.endAnchor(); } output.endCell(); output.endRow(); output.endTable(); } } private void printMemberDetails(HtmlPage output, ProgramElementDoc[] memberDocs, String header) { if (memberDocs.length > 0) { output.div(CssClass.TABLE_HEADER, header); for (int i=0; i0) { output.hr(); } ProgramElementDoc memberDoc = memberDocs[i]; output.anchorName(getMemberAnchor(memberDoc)); output.beginDiv(CssClass.MEMBER_DETAIL); output.div(CssClass.MEMBER_DETAIL_NAME, memberDoc.name()); output.beginDiv(CssClass.MEMBER_DETAIL_SYNOPSIS); output.print(getFullModifiers(memberDoc)); if (memberDoc.isMethod()) { output.print(" "); printType(output, ((MethodDoc)memberDoc).returnType()); } output.print(" "); if (optionLinkSource.getValue() && null != memberDoc.position()) { ClassDoc containingClass = memberDoc.containingClass(); while (null != containingClass.containingClass()) { containingClass = containingClass.containingClass(); } String href = containingClass.name() + "-source" + filenameExtension + "#line." + memberDoc.position().line(); output.beginAnchor(href); output.print(memberDoc.name()); output.endAnchor(); } else { output.print(memberDoc.name()); } if (memberDoc.isConstructor() || memberDoc.isMethod()) { printParameters(output, (ExecutableMemberDoc)memberDoc); } output.endDiv(CssClass.MEMBER_DETAIL_SYNOPSIS); output.beginDiv(CssClass.MEMBER_DETAIL_DESCRIPTION); printTags(output, memberDoc.inlineTags()); output.endDiv(CssClass.MEMBER_DETAIL_DESCRIPTION); if (memberDoc.isConstructor() || memberDoc.isMethod()) { ExecutableMemberDoc execMemberDoc = (ExecutableMemberDoc)memberDoc; Parameter[] parameters = execMemberDoc.parameters(); if (parameters.length > 0) { output.beginDiv(CssClass.MEMBER_DETAIL_PARAMETER_LIST); output.div(CssClass.MEMBER_DETAIL_PARAMETER_HEADER, "Parameters:"); for (int j=0; j 0) { output.beginDiv(CssClass.MEMBER_DETAIL_THROWN_LIST); output.div(CssClass.MEMBER_DETAIL_THROWN_HEADER, "Throws:"); for (int j=0; j 0) { output.print(", "); } printType(output, parameters[j].type()); output.print(" "); output.print(parameters[j].name()); } output.print(")"); } private void printProgramElementDocs(HtmlPage output, ProgramElementDoc[] memberDocs, String header) { if (memberDocs.length > 0) { output.beginTable(CssClass.CLASS_SUMMARY); output.rowDiv(CssClass.TABLE_HEADER, header); for (int i=0; i