changeset 14:9de72de14ab3

USASR-1307: customize CSS and override class template
author Dave Smith <smith@nwoca.org>
date Tue, 10 Dec 2013 23:24:56 +0000
parents a628135958e7
children e3c55e83c9a4
files src/main/groovy/org/ssdt_ohio/gradle/tasks/UserDoc.groovy src/main/groovy/org/ssdt_ohio/gradle/tasks/UserDocTemplateInfo.groovy src/main/resources/org/ssdt_ohio/gradle/userdoc/templates/classDocName.html src/main/resources/org/ssdt_ohio/gradle/userdoc/templates/stylesheet.css
diffstat 4 files changed, 903 insertions(+), 3 deletions(-) [+]
line wrap: on
line diff
--- a/src/main/groovy/org/ssdt_ohio/gradle/tasks/UserDoc.groovy	Tue Dec 10 22:53:57 2013 +0000
+++ b/src/main/groovy/org/ssdt_ohio/gradle/tasks/UserDoc.groovy	Tue Dec 10 23:24:56 2013 +0000
@@ -3,6 +3,7 @@
 import org.codehaus.groovy.tools.groovydoc.ClasspathResourceManager
 import org.codehaus.groovy.tools.groovydoc.FileOutputTool
 import org.codehaus.groovy.tools.groovydoc.GroovyDocTool
+import org.codehaus.groovy.tools.groovydoc.OutputTool
 import org.codehaus.groovy.tools.groovydoc.gstringTemplates.GroovyDocTemplateInfo
 import org.gradle.api.InvalidUserDataException
 import org.gradle.api.file.FileCollection
@@ -149,7 +150,7 @@
      * {@link GroovyDocTemplateInfo#DEFAULT_PACKAGE_TEMPLATES}.
      */
     protected String[] getPackageTemplates() {
-        return GroovyDocTemplateInfo.DEFAULT_PACKAGE_TEMPLATES;
+        return UserDocTemplateInfo.DEFAULT_PACKAGE_TEMPLATES;
     }
 
     /**
@@ -161,7 +162,7 @@
      * {@link GroovyDocTemplateInfo#DEFAULT_DOC_TEMPLATES}.
      */
     protected String[] getDocTemplates() {
-        return GroovyDocTemplateInfo.DEFAULT_DOC_TEMPLATES;
+        return UserDocTemplateInfo.DEFAULT_DOC_TEMPLATES;
     }
 
     /**
@@ -173,6 +174,6 @@
      * {@link GroovyDocTemplateInfo#DEFAULT_CLASS_TEMPLATES}.
      */
     protected String[] getClassTemplates() {
-        return GroovyDocTemplateInfo.DEFAULT_CLASS_TEMPLATES;
+        return UserDocTemplateInfo.DEFAULT_CLASS_TEMPLATES;
     }
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/groovy/org/ssdt_ohio/gradle/tasks/UserDocTemplateInfo.groovy	Tue Dec 10 23:24:56 2013 +0000
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2013.  Ohio Department of Education. - All Rights Reserved.
+ * Unauthorized copying of this file, in any medium, is strictly prohibited.
+ * Written by State Software Development Team (http://ssdt.oecn.k12.oh.us/)
+ */
+
+package org.ssdt_ohio.gradle.tasks
+
+
+class UserDocTemplateInfo {
+
+    private static final String USERDOC_BASEDIR = "org/ssdt_ohio/gradle/userdoc/templates/";
+
+    private static final String TEMPLATE_BASEDIR = "org/codehaus/groovy/tools/groovydoc/gstringTemplates/";
+    private static final String DOCGEN_BASEDIR = "org/codehaus/groovy/tools/";
+    public static final String[] DEFAULT_DOC_TEMPLATES = [ // top level templates
+            TEMPLATE_BASEDIR + "topLevel/index.html",
+            TEMPLATE_BASEDIR + "topLevel/overview-frame.html", // needs all package names
+            TEMPLATE_BASEDIR + "topLevel/allclasses-frame.html", // needs all packages / class names
+            TEMPLATE_BASEDIR + "topLevel/overview-summary.html", // needs all packages
+            TEMPLATE_BASEDIR + "topLevel/help-doc.html",
+            TEMPLATE_BASEDIR + "topLevel/index-all.html",
+            TEMPLATE_BASEDIR + "topLevel/deprecated-list.html",
+            USERDOC_BASEDIR + "stylesheet.css", // copy default one, may override later
+            TEMPLATE_BASEDIR + "topLevel/inherit.gif",
+            DOCGEN_BASEDIR + "groovy.ico",
+    ]
+
+    public static final String[] DEFAULT_PACKAGE_TEMPLATES = [ // package level templates
+            TEMPLATE_BASEDIR + "packageLevel/package-frame.html",
+            TEMPLATE_BASEDIR + "packageLevel/package-summary.html"
+    ]
+
+    public static final String[] DEFAULT_CLASS_TEMPLATES = [ // class level templates
+            USERDOC_BASEDIR + "classDocName.html"
+    ]
+
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/resources/org/ssdt_ohio/gradle/userdoc/templates/classDocName.html	Tue Dec 10 23:24:56 2013 +0000
@@ -0,0 +1,645 @@
+
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<!-- **************************************************************** -->
+<!-- *  PLEASE KEEP COMPLICATED EXPRESSIONS OUT OF THESE TEMPLATES, * -->
+<!-- *  i.e. only iterate & print data where possible. Thanks, Jez. * -->
+<!-- **************************************************************** -->
+<%
+    def title = classDoc.name() + (props.docTitle ? " (${props.docTitle})" : "")
+    def isVisible = { it.isPublic() || (it.isProtected() && props.protectedScope == 'true') || (!it.isProtected() && !it.isPrivate() && props.packageScope == 'true') || props.privateScope == 'true' }
+    def isVisibleExt = { t -> java.lang.reflect.Modifier.isPublic(t.modifiers) || java.lang.reflect.Modifier.isProtected(t.modifiers) }
+    def visibleFields = classDoc.fields().findAll(isVisible)
+    def visibleProperties = classDoc.properties() // props visible be defn
+    def visibleMethods = classDoc.methods().findAll(isVisible)
+    def visibleConstructors = classDoc.constructors().findAll(isVisible)
+    def visibleNested = classDoc.innerClasses().findAll(isVisible)
+    boolean hasFields = !classDoc.isAnnotationType() && visibleFields
+    boolean hasProperties = !classDoc.isAnnotationType() && visibleProperties
+    boolean hasElements = classDoc.isAnnotationType() && visibleFields
+    boolean methodSummaryShown = visibleMethods
+    boolean fieldSummaryShown = hasFields
+    boolean hasEnumConstants = classDoc.enumConstants()
+    def dolink = { t, boolean b ->
+        boolean isArray = false
+        if (!t || t instanceof String) {
+            return classDoc.getDocUrl(t, b)
+        }
+        if (t instanceof org.codehaus.groovy.tools.groovydoc.ArrayClassDocWrapper) {
+            t = t.delegate
+            isArray = true
+        }
+        if (t instanceof org.codehaus.groovy.tools.groovydoc.SimpleGroovyClassDoc) {
+            if (t.fullPathName == 'def') return classDoc.getDocUrl("java.lang.Object def", b)
+            return "<a href='" + classDoc.relativeRootPath + t.fullPathName + ".html'>" + (b ? t.qualifiedTypeName() : t.name()) + "</a>" + (isArray ? "[]" : "")
+        }
+        return classDoc.getDocUrl(t.qualifiedTypeName(), b) + (isArray ? "[]" : "")
+    }
+    def linkfull = { t -> dolink(t, true) }
+    def linkable = { t -> dolink(t, false) }
+    def modifiersWithIgnore = { t, boolean ignorePublic ->
+        (t.isPrivate()?"private&nbsp;":"") +
+        (t.isPublic() && !ignorePublic?"public&nbsp;":"") +
+        (t.isProtected()?"protected&nbsp;":"") +
+        (t.isStatic()?"static&nbsp;":"") +
+        (t.isFinal()?"final&nbsp;":"") +
+        (t.respondsTo('isAbstract') && t.isAbstract()?"abstract&nbsp;":"")
+    }
+    def modifiers = { t -> modifiersWithIgnore(t, classDoc.isGroovy()) }
+    def modifiersBrief = { t ->
+        (t.isPrivate()?"private&nbsp;":"") +
+        (t.isProtected()?"protected&nbsp;":"") +
+        (t.isStatic()?"static&nbsp;":"")
+    }
+    def annotations = { t, sepChar ->
+        t.annotations() ? t.annotations().collect {
+    //        it.isTypeAvailable() ? '@'+linkable(it.type().name())+(it.description()-('@'+it.type().name())): it.description()
+            it.description()
+        }.join(sepChar) + sepChar : ''
+    }
+    def elementTypes = [
+        "required":"true",
+        "optional":"false"
+    ]
+    def isRequired = { f, v -> def req = f.constantValueExpression() == null; req.toString() == v }
+    def upcase = { n -> n[0].toUpperCase() + n[1..-1] }
+    def paramsOf = { n, boolean brief -> n.parameters().collect{ param -> (brief?'':annotations(param, ' ')) + linkable(param.isTypeAvailable()?param.type():param.typeName()) + (param.vararg()?'... ':' ') + param.name() + (param.defaultValue() ? " = " + param.defaultValue():"") }.join(", ") }
+    def nameFromParams = { n -> n.name() + '(' + n.parameters().collect{ param -> param.isTypeAvailable()?param.type().qualifiedTypeName():param.typeName() }.join(', ') + ')' }
+    def nameFromJavaParams = { n -> n.name + '(' + n.parameterTypes.collect{ param -> param.name }.join(', ') + ')' }
+%>
+<html>
+<head>
+<!-- Generated by groovydoc (${GroovySystem.version}) on ${new Date()} -->
+<title>${title}</title>
+<meta name="date" content="${new Date().format('yyyy-MM-dd')}">
+<meta http-equiv="Content-Type" content="text/html; charset=${props.charset}">
+<link href="${classDoc.relativeRootPath}groovy.ico" type="image/x-icon" rel="shortcut icon">
+<link href="${classDoc.relativeRootPath}groovy.ico" type="image/x-icon" rel="icon">
+<link rel="stylesheet" type="text/css" href="${classDoc.relativeRootPath}stylesheet.css" title="Style">
+<script type="text/javascript">
+function windowTitle()
+{
+    if (location.href.indexOf('is-external=true') == -1) {
+        parent.document.title="${title}";
+    }
+}
+</script>
+<noscript>
+</noscript>
+
+</head><body onload="windowTitle();" bgcolor="white">
+<hr>
+
+<!-- ========= START OF TOP NAVBAR ======= -->
+<A NAME="navbar_top"><!-- --></A>
+<TABLE BORDER="0" WIDTH="100%" CELLPADDING="1" CELLSPACING="0" SUMMARY="">
+<TR>
+<TD COLSPAN=2 BGCOLOR="#EEEEFF" CLASS="NavBarCell1">
+<A NAME="navbar_top_firstrow"><!-- --></A>
+<TABLE BORDER="0" CELLPADDING="0" CELLSPACING="3" SUMMARY="">
+  <TR ALIGN="center" VALIGN="top">
+  <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">    <A HREF="${classDoc.relativeRootPath}overview-summary.html"><FONT CLASS="NavBarFont1"><B>Overview</B></FONT></A>&nbsp;</TD>
+
+  <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">    <A HREF="package-summary.html"><FONT CLASS="NavBarFont1"><B>Package</B></FONT></A>&nbsp;</TD>
+  <TD BGCOLOR="#FFFFFF" CLASS="NavBarCell1Rev"> &nbsp;<FONT CLASS="NavBarFont1Rev"><B>Class</B></FONT>&nbsp;</TD>
+  <!--<TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">    <A HREF="package-tree.html"><FONT CLASS="NavBarFont1"><B>Tree</B></FONT></A>&nbsp;</TD>
+  -->
+  <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">    <A HREF="${classDoc.relativeRootPath}deprecated-list.html"><FONT CLASS="NavBarFont1"><B>Deprecated</B></FONT></A>&nbsp;</TD>
+  <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">    <A HREF="${classDoc.relativeRootPath}index-all.html"><FONT CLASS="NavBarFont1"><B>Index</B></FONT></A>&nbsp;</TD>
+  <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">    <A HREF="${classDoc.relativeRootPath}help-doc.html"><FONT CLASS="NavBarFont1"><B>Help</B></FONT></A>&nbsp;</TD>
+  </TR>
+</TABLE>
+</TD>
+<TD ALIGN="right" VALIGN="top" ROWSPAN=3><EM>
+<% if (props.header) { %><b>${props.header}</b><% } %>
+</EM></TD>
+</TR>
+
+<TR>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><!--<FONT SIZE="-2">
+&nbsp;<A HREF="${classDoc.relativeRootPath}groovy/lang/ExpandoMetaClass.ExpandoMetaProperty.html" title="class in groovy.lang"><B>PREV CLASS</B></A>&nbsp;
+
+&nbsp;<A HREF="${classDoc.relativeRootPath}groovy/lang/GroovyClassLoader.html" title="class in groovy.lang"><B>NEXT CLASS</B></A></FONT>--></TD>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+  <A HREF="${classDoc.relativeRootPath}index.html?${classDoc.fullPathName}.html" target="_top"><B>FRAMES</B></A>  &nbsp;
+&nbsp;<A HREF="${classDoc.name()}.html" target="_top"><B>NO FRAMES</B></A>  &nbsp;
+&nbsp;<script type="text/javascript">
+  <!--
+  if(window==top) {
+    document.writeln('<A HREF="${classDoc.relativeRootPath}allclasses-frame.html"><B>All Classes</B></A>');
+  }
+  //-->
+</script>
+<noscript>
+  <A HREF="${classDoc.relativeRootPath}allclasses-frame.html"><B>All Classes</B></A>
+</noscript>
+
+</FONT></TD>
+
+</TR>
+<TR>
+<TD VALIGN="top" CLASS="NavBarCell3"><FONT SIZE="-2">
+SUMMARY:&nbsp;<%
+    if (classDoc.isAnnotationType()) {
+        def hasReq = classDoc.fields().any{ isRequired(it, "true") }
+        def hasOpt = classDoc.fields().any{ isRequired(it, "false") }
+        %><% if (hasReq) { %><A HREF="#required_element_summary"><% } %>REQUIRED<% if (hasReq) { %></A><% }
+        %> | <% if (hasOpt) { %><A HREF="#optional_element_summary"><% } %>OPTIONAL<% if (hasOpt) { %></A><% } %><%
+    } else {
+        if (visibleNested) { %><A HREF="#nested_summary"><% } %>NESTED<% if (visibleNested) { %></A><% }
+        if (classDoc.isEnum()) {
+            %>&nbsp;|&nbsp;<% if (hasEnumConstants) { %><A HREF="#enum_constant_summary"><% } %>ENUM CONSTANTS<% if (hasEnumConstants) { %></A><% }
+        }
+        %>&nbsp;|&nbsp;<% if (hasFields) { %><A HREF="#field_summary"><% } %>FIELD<% if (hasFields) { %></A><% }
+        if (hasProperties) { %>&nbsp;|&nbsp;<A HREF="#property_summary">PROPERTY</A><% }
+        if (classDoc.isClass()) {
+            %>&nbsp;|&nbsp;<% if (visibleConstructors) { %><A HREF="#constructor_summary"><% } %>CONSTR<% if (visibleConstructors) { %></A><% }
+        }
+        %>&nbsp;|&nbsp;<% if (visibleMethods) { %><A HREF="#method_summary"><% } %>METHOD<% if (visibleMethods) { %></A><% }
+    }
+    %></FONT></TD>
+<TD VALIGN="top" CLASS="NavBarCell3"><FONT SIZE="-2">
+DETAIL:&nbsp;<%
+    if (classDoc.isAnnotationType()) {
+        if (hasElements) { %><A HREF="#element_detail"><% } %>ELEMENT<% if (hasElements) { %></A><% }
+    } else {
+        if (classDoc.isEnum()) {
+            if (hasEnumConstants) { %><A HREF="#enum_constant_detail"><% } %>ENUM CONSTANTS<% if (hasEnumConstants) { %></A>&nbsp;|&nbsp;<% }
+        }
+        if (hasFields) { %><A HREF="#field_detail"><% } %>FIELD<% if (hasFields) { %></A><% }
+        if (hasProperties) { %>&nbsp;|&nbsp;<A HREF="#prop_detail">PROPERTY</A><% }
+        if (classDoc.isClass()) {
+            %>&nbsp;|&nbsp;<% if (visibleConstructors) { %><A HREF="#constructor_detail"><% } %>CONSTR<% if (visibleConstructors) { %></A><% }
+        }
+        %>&nbsp;|&nbsp;<% if (visibleMethods) { %><A HREF="#method_detail"><% } %>METHOD<% if (visibleMethods) { %></A><% }
+    }
+    %></FONT></TD>
+</TR>
+</TABLE>
+<!-- ========= END OF TOP NAVBAR ========= -->
+
+
+<HR>
+<!-- ======== START OF CLASS DATA ======== -->
+<H2>
+<%
+def pkg = classDoc.containingPackage().nameWithDots()
+if (pkg != "DefaultPackage") {
+%>
+<FONT SIZE="-1">
+${pkg}</FONT>
+<BR>
+<% } %>
+<span CLASS="ClassTitleFont"> ${classDoc.typeDescription} ${classDoc.name()}</span></H2>
+<%
+def parents = classDoc.isInterface() ? classDoc.parentInterfaces : classDoc.parentClasses
+if (parents.size() >= 2) {
+    %><pre><%
+    parents.eachWithIndex { p, i ->
+        %>${(i > 0 ? "  " * i + "  " * (i - 1) + "<img src='" + classDoc.relativeRootPath + "inherit.gif'>" : "") + ( i == parents.size() - 1 ? p.qualifiedTypeName() : linkfull(p))}\n<%
+    }
+    %></pre><%
+}
+if (classDoc.isInterface()) {
+    Set interfaces = classDoc.parentInterfaces
+    interfaces -= classDoc
+    if (interfaces) {
+        %><dl><dt><b>All Superinterfaces:</b> </dt><dd>${interfaces.collect{ linkable(it) }.join(', ')}</dd></dl><%
+    }
+} else {
+    // TODO follow up the tree collecting interfaces seen?
+    def interfaces = classDoc.interfaces()
+    if (interfaces) {
+        %><dl><dt><b>All Implemented Interfaces:</b> </dt><dd>${interfaces.collect{ linkable(it) }.join(', ')}</dd></dl><%
+    }
+}
+%><hr>
+<PRE>${annotations(classDoc, '\n') + modifiers(classDoc) + classDoc.typeSourceDescription + ' ' + classDoc.name()}
+<% if (classDoc.isInterface() && classDoc.interfaces()) {
+%>extends ${classDoc.interfaces().collect{ linkable(it) }.join(', ')}
+<% } else if (classDoc.superclass()) {
+%>extends ${linkable(classDoc.superclass())}
+<% } %>
+</PRE>
+<% if (classDoc.commentText()) { %>
+<P>
+${classDoc.commentText()}
+</P>
+<hr>
+<% } %>
+
+<!-- =========== NESTED CLASS SUMMARY =========== -->
+
+<A NAME="nested_summary"><!-- --></A>
+<% if (visibleNested) { %>
+    <TABLE BORDER="1" WIDTH="100%" CELLPADDING="3" CELLSPACING="0" SUMMARY="">
+    <TR BGCOLOR="#CCCCFF" CLASS="TableHeadingColor">
+    <TH ALIGN="left" COLSPAN="2"><FONT SIZE="+2">
+    <B>Nested Class Summary</B></FONT></TH>
+    </TR>
+    <% for (c in visibleNested) { %>
+        <TR BGCOLOR="white" CLASS="TableRowColor">
+        <TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+        <CODE>${modifiersBrief(c) + c.typeSourceDescription}</CODE></FONT></TD>
+        <TD>
+            <CODE>${linkable(c)}</CODE>
+            <BR>
+            <P>${c.firstSentenceCommentText()}</P>
+        </TD>
+        </TR>
+    <% } %>
+    </TABLE>
+    &nbsp;
+<% } %>
+
+<!-- =========== ENUM CONSTANT SUMMARY =========== -->
+
+<A NAME="enum_constant_summary"><!-- --></A>
+<% if (hasEnumConstants) { %>
+    <TABLE BORDER="1" WIDTH="100%" CELLPADDING="3" CELLSPACING="0" SUMMARY="">
+    <TR BGCOLOR="#CCCCFF" CLASS="TableHeadingColor">
+    <TH ALIGN="left" COLSPAN="2"><FONT SIZE="+2">
+    <B>Enum Constant Summary</B></FONT></TH>
+    </TR>
+    <% for (ec in classDoc.enumConstants()) { %>
+        <TR BGCOLOR="white" CLASS="TableRowColor">
+        <TD>
+            <CODE><B><A HREF="#${ec.name()}">${ec.name()}</A></B></CODE>
+            <BR>
+            <P>${ec.firstSentenceCommentText()}</P>
+        </TD>
+        </TR>
+    <% } %>
+    </TABLE>
+    &nbsp;
+<% } %>
+
+<!-- =========== FIELD SUMMARY =========== -->
+
+<A NAME="field_summary"><!-- --></A>
+<% if (hasFields) { %>
+    <TABLE BORDER="1" WIDTH="100%" CELLPADDING="3" CELLSPACING="0" SUMMARY="">
+    <TR BGCOLOR="#CCCCFF" CLASS="TableHeadingColor">
+    <TH ALIGN="left" COLSPAN="2"><FONT SIZE="+2">
+    <B>Field Summary</B></FONT></TH>
+    </TR>
+    <% for (field in visibleFields) { %>
+        <TR BGCOLOR="white" CLASS="TableRowColor">
+        <TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+        <CODE>${modifiersBrief(field) + linkable(field.type())}</CODE></FONT></TD>
+        <TD>
+            <CODE><B><A HREF="#${field.name()}">${field.name()}</A></B></CODE>
+            <BR>
+            <P>${field.firstSentenceCommentText()}</P>
+        </TD>
+        </TR>
+    <% } %>
+    </TABLE>
+    &nbsp;
+<% }
+    classes = []
+    if (classDoc.isInterface()) {
+        classes.addAll(classDoc.interfaces().toList())
+    } else {
+        if (classDoc.superclass()) classes += classDoc.superclass()
+        else classes += new org.codehaus.groovy.tools.groovydoc.ExternalGroovyClassDoc(Object.class)
+    }
+    visited = [classDoc] as Set
+    while (classes) {
+        Set nextLevel = []
+        classes.each { c ->
+            if (c.isInterface()) nextLevel.addAll(c.interfaces().toList())
+            else if (c.superclass() && c.qualifiedTypeName() != 'java.lang.Object') nextLevel += c.superclass()
+            nextLevel -= visited
+            visited += nextLevel
+            def list = []
+            if (c instanceof org.codehaus.groovy.tools.groovydoc.SimpleGroovyClassDoc) {
+                list = c.fields().findAll(isVisible).collect { field ->
+                    "<a href='${classDoc.relativeRootPath}${c.fullPathName}.html#${field.name()}'>${field.name()}</a>"
+                }
+            } else {
+                list = c.externalClass().fields.findAll{ isVisibleExt(it) }.collect { field ->
+                    // "<a href='${classDoc.relativeRootPath}${c.fullPathName}.html#${field.name()}'>${field.name()}</a>"
+                    field.name
+                }
+            }
+            if (list) {
+                if (!fieldSummaryShown) {
+                    fieldSummaryShown = true
+                    %><table BORDER="1" WIDTH="100%" CELLPADDING="3" CELLSPACING="0" SUMMARY="">
+                    <TR CLASS="TableHeadingColor">
+                    <TH ALIGN="left" COLSPAN="2"><FONT SIZE="+2" CLASS="ClassHeadingFont">
+                    <B>Field Summary</B></FONT></TH>
+                    </TR>
+                    </table>
+                    &nbsp;<%
+                }
+                %><table BORDER="1" WIDTH="100%" CELLPADDING="3" CELLSPACING="0" SUMMARY="">
+                <tr CLASS="TableSubHeadingColor"><th ALIGN="left" COLSPAN="2">
+                <b>Fields inherited from ${c.typeSourceDescription} ${linkable(c)}</b>
+                </th></tr>
+                <tr class="TableRowColor"><td colspan='2'>${list.join(', ')}</td></tr>
+                </table>
+                &nbsp;<%
+            }
+        }
+        classes = nextLevel
+    }
+%>
+
+<!-- =========== PROPERTY SUMMARY =========== -->
+
+<A NAME="property_summary"><!-- --></A>
+<% if (hasProperties) { %>
+    <TABLE BORDER="1" WIDTH="100%" CELLPADDING="3" CELLSPACING="0" SUMMARY="">
+    <TR BGCOLOR="#CCCCFF" CLASS="TableHeadingColor">
+    <TH ALIGN="left" COLSPAN="2"><FONT SIZE="+2">
+    <B>Property Summary</B></FONT></TH>
+    </TR>
+    <% for (prop in visibleProperties) { %>
+        <TR BGCOLOR="white" CLASS="TableRowColor">
+        <TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+        <CODE>${modifiersBrief(prop) + linkable(prop.type())}</CODE></FONT></TD>
+        <TD>
+            <CODE><B><A HREF="#${prop.name()}">${prop.name()}</A></B></CODE>
+            <BR>
+            <P>${prop.firstSentenceCommentText()}</P>
+        </TD>
+        </TR>
+    <% } %>
+    </TABLE>
+    &nbsp;
+<% } %>
+
+<!-- =========== ELEMENT SUMMARY =========== -->
+
+<% if (hasElements) { %>
+    <% elementTypes.each { k, v -> %>
+        <A NAME="${k}_element_summary"><!-- --></A>
+        <% if (visibleFields.any{ isRequired(it, v) }) {  %>
+            <TABLE BORDER="1" WIDTH="100%" CELLPADDING="3" CELLSPACING="0" SUMMARY="">
+            <TR BGCOLOR="#CCCCFF" CLASS="TableHeadingColor">
+            <TH ALIGN="left" COLSPAN="2"><FONT SIZE="+2">
+            <B>${upcase(k)} Element Summary</B></FONT></TH>
+            </TR>
+            <% for (element in visibleFields) { %>
+                <% if (isRequired(element, v)) { %>
+                <TR BGCOLOR="white" CLASS="TableRowColor">
+                <TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+                <CODE>${modifiersBrief(element) + element.type().typeName()}</CODE></FONT></TD>
+                <TD>
+                    <CODE><B><A HREF="#${element.name()}">${element.name()}</A></B></CODE>
+                    <BR>
+                    <P>${element.firstSentenceCommentText()}</P>
+                </TD>
+                </TR>
+                <% } %>
+            <% } %>
+            </TABLE>
+        <% } %>
+        &nbsp;
+    <% } %>
+<% } %>
+
+<!-- ======== CONSTRUCTOR SUMMARY ======== -->
+
+<A NAME="constructor_summary"><!-- --></A>
+<% if (visibleConstructors) { %>
+    <TABLE BORDER="1" WIDTH="100%" CELLPADDING="3" CELLSPACING="0" SUMMARY="">
+    <TR BGCOLOR="#D5D5FF" CLASS="TableHeadingColor">
+    <TD COLSPAN=2><FONT SIZE="+2">
+    <B>Constructor Summary</B></FONT></TD>
+    </TR>
+    <% for (constructor in visibleConstructors) { %>
+        <TR BGCOLOR="white" CLASS="TableRowColor">
+        <TD>
+            <CODE>${modifiersBrief(constructor)}<B><a href="#${nameFromParams(constructor)}">${constructor.name()}</a></B>(${paramsOf(constructor, true)})</CODE>
+            <BR>
+            <P>${constructor.firstSentenceCommentText()}</P>
+        </TD>
+        </TR>
+    <% } %>
+    </TABLE>
+    &nbsp;
+<% } %>
+
+<!-- ========== METHOD SUMMARY =========== -->
+
+<A NAME="method_summary"><!-- --></A>
+<% if (visibleMethods) { %>
+    <TABLE BORDER="1" WIDTH="100%" CELLPADDING="3" CELLSPACING="0" SUMMARY="">
+    <TR CLASS="TableHeadingColor">
+    <TH ALIGN="left" COLSPAN="2"><FONT SIZE="+2" CLASS="ClassHeadingFont">
+    <B>Method Summary</B></FONT></TH>
+    </TR>
+    <% for (method in visibleMethods) { %>
+        <TR BGCOLOR="white" CLASS="TableRowColor">
+        <TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1" CLASS="ClassItemFont">
+            <CODE>${modifiersBrief(method)}${linkable(method.returnType())}</CODE></FONT>
+        </TD>
+        <TD>
+            <CODE><b><a href="#${nameFromParams(method)}">${method.name()}</a></b>(${paramsOf(method, true)})</CODE>
+            <BR>
+            <P>${method.firstSentenceCommentText()}</P>
+        </TD>
+        </TR>
+    <% } %>
+    </TABLE>
+    &nbsp;
+<% }
+    Set classes = []
+    if (classDoc.isInterface()) {
+        classes.addAll(classDoc.interfaces().toList())
+    } else {
+        if (classDoc.superclass()) classes += classDoc.superclass()
+        else classes += new org.codehaus.groovy.tools.groovydoc.ExternalGroovyClassDoc(Object.class)
+    }
+    Set visited = [classDoc] as Set
+    while (classes) {
+        Set nextLevel = []
+        classes.each { c ->
+            if (c.isInterface()) nextLevel.addAll(c.interfaces().toList())
+            else if (c.superclass() && c.qualifiedTypeName() != 'java.lang.Object') nextLevel += c.superclass()
+            nextLevel -= visited
+            visited += nextLevel
+            def list = []
+            if (c instanceof org.codehaus.groovy.tools.groovydoc.SimpleGroovyClassDoc) {
+                list = c.methods().findAll(isVisible).collect { method ->
+                    "<a href='${classDoc.relativeRootPath}${c.fullPathName}.html#${nameFromParams(method)}'>${method.name()}</a>"
+                }
+            } else {
+                list = c.externalClass().methods.findAll{ isVisibleExt(it) }.collect { method ->
+                    linkable(c.externalClass().name + "#" + nameFromJavaParams(method) + " " + method.name)
+                }
+            }
+            if (list) {
+                if (!methodSummaryShown) {
+                    methodSummaryShown = true
+                    %><table BORDER="1" WIDTH="100%" CELLPADDING="3" CELLSPACING="0" SUMMARY="">
+                    <TR CLASS="TableHeadingColor">
+                    <TH ALIGN="left" COLSPAN="2"><FONT SIZE="+2" CLASS="ClassHeadingFont">
+                    <B>Method Summary</B></FONT></TH>
+                    </TR>
+                    </table>
+                    &nbsp;<%
+                }
+                %><table BORDER="1" WIDTH="100%" CELLPADDING="3" CELLSPACING="0" SUMMARY="">
+                <tr CLASS="TableSubHeadingColor"><th ALIGN="left" COLSPAN="2">
+                <b>Methods inherited from ${c.typeSourceDescription} ${linkable(c)}</b>
+                </th></tr>
+                <tr class="TableRowColor"><td colspan='2'>${list.join(', ')}</td></tr>
+                </table>
+                &nbsp;<%
+            }
+        }
+        classes = nextLevel
+    }
+%>
+
+<P>
+
+<!-- ============ ENUM CONSTANT DETAIL ========== -->
+
+<A NAME="enum_constant_detail"><!-- --></A>
+<% if (hasEnumConstants) { %>
+    <TABLE BORDER="1" WIDTH="100%" CELLPADDING="3" CELLSPACING="0" SUMMARY="">
+    <TR BGCOLOR="#CCCCFF" CLASS="TableHeadingColor">
+    <TH ALIGN="left" COLSPAN="1"><FONT SIZE="+2">
+    <B>Enum Constant Detail</B></FONT></TH>
+    </TR>
+    </TABLE>
+    <% for (ec in classDoc.enumConstants()) { %>
+        <A NAME="${ec.name()}"><!-- --></A><H3>${ec.name()}</H3>
+        <PRE>${modifiers(ec) + '<a href="' + classDoc.relativeRootPath + classDoc.fullPathName + '.html">' + classDoc.name() + '</a>'} <B>${ec.name()}</B></PRE>
+        <DL>
+        <DD>${ec.commentText()}
+        </DD>
+        <P>
+        </DL>
+        <HR>
+    <% } %>
+    &nbsp;
+<% } %>
+
+<!-- =========== FIELD DETAIL =========== -->
+
+<A NAME="field_detail"><!-- --></A>
+<% if (hasFields) { %>
+    <TABLE BORDER="1" WIDTH="100%" CELLPADDING="3" CELLSPACING="0" SUMMARY="">
+    <TR BGCOLOR="#CCCCFF" CLASS="TableHeadingColor">
+    <TH ALIGN="left" COLSPAN="2"><FONT SIZE="+2">
+    <B>Field Detail</B></FONT></TH>
+    </TR>
+    </TABLE>
+    <% for (field in visibleFields) { %>
+        <A NAME="${field.name()}"><!-- --></A><H3>${field.name()}</H3>
+        <PRE>${annotations(field, '\n') + modifiersWithIgnore(field, false) + linkable(field.type())} <B>${field.name()}</B></PRE>
+        <DL>
+        <DD>${field.commentText()}
+        </DD>
+        <P>
+        </DL>
+        <HR>
+    <% } %>
+    &nbsp;
+<% } %>
+
+<!-- =========== PROPERTY DETAIL =========== -->
+
+<A NAME="prop_detail"><!-- --></A>
+<% if (hasProperties) { %>
+    <TABLE BORDER="1" WIDTH="100%" CELLPADDING="3" CELLSPACING="0" SUMMARY="">
+    <TR BGCOLOR="#CCCCFF" CLASS="TableHeadingColor">
+    <TH ALIGN="left" COLSPAN="2"><FONT SIZE="+2">
+    <B>Property Detail</B></FONT></TH>
+    </TR>
+    </TABLE>
+    <% for (prop in visibleProperties) { %>
+        <A NAME="${prop.name()}"><!-- --></A><H3>${prop.name()}</H3>
+        <PRE>${annotations(prop, '\n') + modifiers(prop) + linkable(prop.type())} <B>${prop.name()}</B></PRE>
+        <DL>
+        <DD>${prop.commentText()}
+        </DD>
+        <P>
+        </DL>
+        <HR>
+    <% } %>
+    &nbsp;
+<% } %>
+
+<!-- =========== ELEMENT DETAIL =========== -->
+
+<A NAME="element_detail"><!-- --></A>
+<% if (hasElements) { %>
+    <TABLE BORDER="1" WIDTH="100%" CELLPADDING="3" CELLSPACING="0" SUMMARY="">
+    <TR BGCOLOR="#CCCCFF" CLASS="TableHeadingColor">
+    <TH ALIGN="left" COLSPAN="2"><FONT SIZE="+2">
+    <B>Element Detail</B></FONT></TH>
+    </TR>
+    </TABLE>
+    <% for (element in visibleFields) { %>
+        <A NAME="${element.name()}"><!-- --></A><H3>${element.name()}</H3>
+        <PRE>${modifiers(element) + linkable(element.type())} <B>${element.name()}</B></PRE>
+        <DL>
+        <DD>${element.commentText()}
+        </DD>
+        <P>
+        </DL>
+        <HR>
+    <% } %>
+    &nbsp;
+<% } %>
+
+<!-- ========= CONSTRUCTOR DETAIL ======== -->
+
+<A NAME="constructor_detail"><!-- --></A>
+<% if (visibleConstructors) { %>
+    <TABLE BORDER="1" WIDTH="100%" CELLPADDING="3" CELLSPACING="0" SUMMARY="">
+    <TR BGCOLOR="#CCCCFF" CLASS="TableHeadingColor">
+    <TH ALIGN="left" COLSPAN="1"><FONT SIZE="+2">
+    <B>Constructor Detail</B></FONT></TH>
+    </TR>
+    </TABLE>
+    <% for (constructor in visibleConstructors) { %>
+        <A NAME="${nameFromParams(constructor)}"><!-- --></A><H3>
+        ${constructor.name()}</H3>
+        <PRE>${annotations(constructor, '\n') + modifiers(constructor)}<B>${constructor.name()}</B>(${paramsOf(constructor, false)})</PRE>
+        <DL>
+        <DD>${constructor.commentText()}
+        </DD>
+        <P>
+        </DL>
+        <HR>
+    <% } %>
+    &nbsp;
+<% } %>
+
+<!-- ============ METHOD DETAIL ========== -->
+
+<A NAME="method_detail"><!-- --></A>
+<% if (visibleMethods) { %>
+    <TABLE BORDER="1" WIDTH="100%" CELLPADDING="3" CELLSPACING="0" SUMMARY="">
+    <TR BGCOLOR="#CCCCFF" CLASS="TableHeadingColor">
+    <TH ALIGN="left" COLSPAN="1"><FONT SIZE="+2">
+    <B>Method Detail</B></FONT></TH>
+    </TR>
+    </TABLE>
+    <% for (method in visibleMethods) { %>
+        <A NAME="${nameFromParams(method)}"><!-- --></A><H3>
+        ${method.name()}</H3>
+        <PRE>${annotations(method, '\n') + modifiers(method)}${linkable(method.returnType())} <B>${method.name()}</B>(${paramsOf(method, false)})</PRE>
+        <DL>
+        <DD>${method.commentText()}
+        </DD>
+        <P>
+        </DL>
+        <HR>
+    <% } %>
+    &nbsp;
+<% } %>
+
+<!-- ========= END OF CLASS DATA ========= -->
+<p>${props['footer']?:""}</p>
+<hr>
+
+</body>
+</html>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/resources/org/ssdt_ohio/gradle/userdoc/templates/stylesheet.css	Tue Dec 10 23:24:56 2013 +0000
@@ -0,0 +1,215 @@
+.code, pre
+{
+        border: 1px dashed #6699CC;
+        background-color: #F4F4F4;
+        padding: 5px;
+}
+
+body
+{
+        font-size: 10pt;
+        font-family: 'Lucida Grande',verdana,arial,helvetica,sans-serif;
+        background-color: #fff;
+        color: #333;
+}
+ 
+/* Link colors */
+a
+{
+        color:#569D2F;
+        text-decoration:none;
+}
+ 
+a:hover
+{
+        text-decoration:underline;
+}
+ 
+/* Headings */
+h1
+{
+     background: url(tapestry.png) no-repeat;
+        font-size:28px;
+        color:#007c00;
+        padding: 2.0em;
+}
+h1,h2,h3 {
+        color: #569D2F;
+}
+
+wbr:after
+{
+        content: "\00200B";  /* IE fix */
+}
+
+/* Table colors */
+
+table
+{
+		background: #fff;
+        border-collapse: collapse;
+}
+ 
+td
+{
+        border: 1px dotted #ccc;
+        background: #F4F4F4;
+}
+ 
+th
+{
+        border:none;
+        background-color: #569D2F;
+    color: white;
+    text-align: left;
+}
+ 
+.TableHeadingColor th
+{
+        background-color: #569D2F;
+        background-repeat: repeat-x;
+        color:#fff;
+        font-size:14px;
+        height:26px;
+}
+.TableHeadingColor th font[size="+2"] 
+{ 
+        font-size: 10pt; 
+}
+table.parameters tbody th 
+{
+        background: #F4F4F4;
+        color: #333;
+        border: 1px dotted #ccc;
+        font-weight: normal;
+}
+table.parameters thead tr.columnHeaders th 
+{
+	   background: #e6e6e6; 
+	   color: #6e6e6e; 
+       border-left: 1px dotted #999;
+       border-right: 1px dotted #999;
+}
+body > dt > b 
+{ 
+        display: block; 
+        padding: 0.3em 0 0 0.3em; 
+        margin-top: 1em; 
+        background: #569D2F; 
+        color: #fff; 
+        border: 1px solid black;
+        font-size: 14px; 
+        height: 26px; 
+}
+
+.TableSubHeadingColor  
+{
+        background: #f7ffee;
+ 
+}
+.TableSubHeadingColor a
+{
+        color: white;
+        text-decoration: underline;
+}
+.TableSubHeadingColor a:hover
+{
+        color: white;
+        text-decoration: underline;
+}
+
+.TableRowColor         
+{
+        background: #fff;
+}
+ 
+.TableRowColor a      
+{
+        border-bottom:none;
+        color:#569D2F;
+        font-weight:normal;
+}
+ 
+tr.TableRowColor:hover
+{
+        background:#eef2e1;
+}
+ 
+ 
+/* Font used in left-hand frame lists */
+.FrameTitleFont   
+{
+        font-size: 120%;
+        font-weight:bold;
+}
+ 
+.FrameTitleFont a   
+{  
+        color: #333;
+}
+ 
+.FrameHeadingFont
+{
+        font-weight: bold;
+        font-size:95%;
+}
+ 
+.FrameItemFont    
+{
+        line-height:130%;
+        font-size: 95%;
+}
+ 
+.FrameItemFont a
+{
+        color:#333;
+}
+ 
+.FrameItemFont a:hover
+{
+        color:#249901;
+        border-bottom:none;
+        text-decoration:underline;
+}
+ 
+/* Navigation bar fonts and colors */
+.NavBarCell1    
+{
+        background-color:#fff;
+        border:none;
+}
+ 
+.NavBarCell1Rev
+{
+        background-color:#e3faa5;
+        border:1px solid #9ad00c;
+        padding:0;
+        margin:0;
+}
+ 
+.NavBarCell1 a  
+{
+        color:#333;
+        text-decoration:none;
+}
+ 
+.NavBarFont1Rev
+{
+ 
+}
+ 
+.NavBarCell2
+{
+        border:none;
+}
+ 
+.NavBarCell2 a    
+{
+        color:#569D2F;
+        font-size:90%;
+}
+ 
+.NavBarCell3    
+{
+        border:none;
+}