package org.scala_tools.vscaladoc
import scala.tools.nsc.symtab
import scala.xml.{NodeSeq, Text}
import scala.tools.nsc.symtab.Symbols
import scala.tools.nsc.symtab.Types
class Page4ClassOrObject(cls: ModelExtractor#ClassOrObject, allClasses: Iterable[ModelExtractor#ClassOrObject]) extends ContentPage {
case class Member(entity: ModelExtractor#Entity, inheritedFrom:Option[Symbols#Symbol]);
def uri = Services.linkHelper.uriFor(cls).getOrElse(null)
def link(tpe: Types#Type) = Services.linkHelper.link(uri)(tpe)
override def title = super.title + " : " + cls.fullName('.')
override def header = surroundHeader(None)
override def body = surroundBody(Some(
<xml:group>
<!-- ======== START OF CLASS DATA ======== -->
<h2>
<span style="font-size:80%">{cls.fullName('.')}</span>
<br/>
{cls.kind} {cls.name}
</h2>
<div id="intro">
{signatureFor(cls)}
{extendsFor(cls)}
<br/>
{htmlize(cls.decodeComment, false)}
<br/>
{linkToCompanion}
{linkToSource}
</div>
{directKnownSubclasses}
{nestedClasses}
{section("Constructors", Services.modelHelper.isConstructor, asXmlConstructor)}
{section("Fields", Services.modelHelper.isField, asXmlField)}
{section("Methods", Services.modelHelper.isMethod, asXmlField)}
<!-- ========= END OF CLASS DATA ========= -->
</xml:group>
))
//TODO: create a UML graph (with graphviz or txt)
def extendsFor(entity: ModelExtractor#Entity) : NodeSeq = {
if (entity.parents.isEmpty) NodeSeq.Empty
else {
<code class="signature">
<br/> extends
{DocUtil.NodeWrapper(entity.parents.elements.map(_.normalize)).mkXML(Text(""), Text(" with "), Text(""))({v=> link(v)})}
</code>
}
}
//TODO: to implement Direct Know Subclasses
def directKnownSubclasses : NodeSeq = {
val subClasses = Services.modelHelper.findSubClassesOf(cls)
if (!subClasses.isEmpty) {
<xml:group>
<h3>Direct Known Subclasses</h3>
{subClasses.map(m => Services.linkHelper.link(m, uri, None, None) ++ Text(", "))}
</xml:group>
} else {
NodeSeq.Empty
}
}
//def inheritanceGraph : NodeSeq = Text(Services.modelHelper.inheritanceGraphOf(cls))
def nestedClasses : NodeSeq = {
val nclasses = findMembers(Services.modelHelper.isNestedClass, true)
if (nclasses.length > 0) {
<xml:group>
<h3>Nested Classes</h3>
{nclasses.map(m => Services.linkHelper.link(m.entity, uri, None, None) ++ Text(", "))}
</xml:group>
} else {
NodeSeq.Empty
}
}
def linkToCompanion : NodeSeq = {
val src = cls.sym.sourceFile
val line = cls.sym.pos.line
Services.modelHelper.findCompanionOf(cls, allClasses)
.map(u => Text("Companion: ") ++ Services.linkHelper.link(u, uri, None, None) ++ <br/>)
.getOrElse(NodeSeq.Empty)
}
def linkToSource : NodeSeq = {
val src = cls.sym.sourceFile
val line = cls.sym.pos.line
Services.sourceHtmlizer.scalaToHtml(src.file)
.flatMap(f => Services.linkHelper.uriFor(f))
.map(u => Text("Source: ") ++ <a href={relativize(u)+"#"+line}>{Text(src.name + line.map("(" + _ +")").getOrElse(""))}</a>)
.getOrElse(NodeSeq.Empty)
}
def section(subtitle: String, filter: ModelExtractor#ClassOrObject#Member=> Boolean, renderer: Member => NodeSeq) = {
val items = findMembers(filter, true)
if (items.length > 0) {
<xml:group>
<!-- =========== {subtitle} =========== -->
<h3><a name={subtitle}> </a>{subtitle}</h3>
<table border="1" width="100%" cellpadding="3" cellspacing="0" summary="">
<tbody class="TableRowColor">
{items.map(renderer(_))}
</tbody>
</table>
</xml:group>
} else {
NodeSeq.Empty
}
}
/**
* generate a a filtered list of Members (ordored by name)
*/
def findMembers(filter: ModelExtractor#ClassOrObject#Member=> Boolean, includeInherited: Boolean): List[Member] = {
//var back = cls.members0(filter).map(Member(_, None)).toList
var back = (for ((tpe, member) <- cls.decls; if filter(member)) yield Member(member, None)).toList
if (includeInherited) {
back = back ::: (for ((tpe,members) <- cls.inherited; member <- members.filter(m => filter(m))) yield Member(member, Some(tpe))).toList
}
back.sort(_.entity.name < _.entity.name)
}
def asXmlConstructor(member: Member) = {
val entity = member.entity
<tr class={member.inheritedFrom.map(v => "isInherited").getOrElse("") + (if (entity.sym.isDeprecated) " isDeprecated" else "")}>
<td class="signature">
{signatureFor(entity)}
{htmlize(entity.decodeComment)}
</td>
</tr>
}
//"sym :" + entity.sym + "|flagsString:" + entity.flagsString + "|kind:" + entity.kind + "|resultType:" + entity.resultType
//TODO: manage deprecated
//TODO: manage override
def asXmlField(member: Member) = {
val entity = member.entity
val isDeprecated = if ((entity.sym.isDeprecated) || (entity.decodeComment.map(_.attributes.exists(_.tag.toLowerCase == "deprecated")).getOrElse(false))) " isDeprecated" else ""
val isInherited = member.inheritedFrom.map(v => "isInherited").getOrElse("")
<tr class={isInherited + isDeprecated}>
<td class="name">
<b>{entity.name}</b>
</td>
<td class="signature">
{signatureFor(entity)}
{codeAsDoc(entity)}
{htmlize(entity.decodeComment)}
</td>
<td class="type">{entity.resultType.map(link(_)).getOrElse(NodeSeq.Empty)}{extendsFor(entity)}</td>
<td class="remarks">
{/** TODO add override from */}
{member.inheritedFrom.map(Services.linkHelper.link(_, uri, None, None)).getOrElse(NodeSeq.Empty)}
</td>
</tr>
}
private def codeAsDoc(entity: ModelExtractor#Entity) = {
entity.decodeComment match {
case Some(comment) if (comment.attributes.exists(_.tag == "codeAsDoc")) => <pre class="codeAsDoc">{Text(entity.sym.pos.lineContent)}</pre>
case _ => NodeSeq.Empty
}
}
private def printIf(what: Option[Types#Type], before: String, after: String): NodeSeq =
if (what.isEmpty) NodeSeq.Empty
else Text(before) ++ link(what.get) ++ Text(after)
def signatureFor(entity: ModelExtractor#Entity): NodeSeq = {
<code class="signature">{
Text((entity.flagsString + " " + entity.kind + " " +entity.name).trim) ++
DocUtil.NodeWrapper(entity.typeParams.elements).surround("[", "]")(e =>
Text((e.variance + " " + e.name).trim) ++ printIf(e.hi, " <: ", "") ++ printIf(e.lo, " >: ", "")
) ++
printIf(entity.hi, " <: ", "") ++ printIf(entity.lo, " >: ", "") ++
entity.params.map(xs =>
DocUtil.NodeWrapper(xs.elements).mkXML("(", ", ", ")")(arg =>
Text((arg.flagsString + " " + arg.name).trim + " : ") ++ link(arg.resultType.get)
)
)
}</code>
}
override def navBarCell1 = {
<xml:group>
<a href={relativize("site:/overview.html")}>OVERVIEW</a> |
{Services.modelHelper.packageFor(cls.sym).map(Services.linkHelper.link(_, uri, Some("PACKAGE"), None) ++ Text(" | ")).getOrElse(NodeSeq.Empty)}
<a href="#Constructors">CONSTR</a> |
<a href="#Fields">FIELDS</a> |
<a href="#Methods">METHODS</a>
</xml:group>
}
override def navBarCell3 = {
<a class="btnInherited" href="#" onclick="toggleInherited()" title="show/hide inherited">INHERITED<input type="checkbox" checked="true" class="filter_inherited_cb"/></a>
}
}