Commit fe818bf8 authored by Dimitri van Heesch's avatar Dimitri van Heesch

Added graphical hierarchy support to template engine

parent 3ebc4315
This diff is collapsed.
...@@ -51,6 +51,8 @@ struct MemberInfo; ...@@ -51,6 +51,8 @@ struct MemberInfo;
class MemberGroup; class MemberGroup;
class MemberGroupSDict; class MemberGroupSDict;
class MemberGroupList; class MemberGroupList;
class DotNode;
class DotGfxHierarchyTable;
//---------------------------------------------------- //----------------------------------------------------
...@@ -419,6 +421,26 @@ class ClassIndexContext : public RefCountedContext, public TemplateStructIntf ...@@ -419,6 +421,26 @@ class ClassIndexContext : public RefCountedContext, public TemplateStructIntf
//---------------------------------------------------- //----------------------------------------------------
class InheritanceGraphContext : public RefCountedContext, public TemplateStructIntf
{
public:
static InheritanceGraphContext *alloc(DotGfxHierarchyTable *hierarchy,DotNode *n,int id)
{ return new InheritanceGraphContext(hierarchy,n,id); }
// TemplateStructIntf methods
virtual TemplateVariant get(const char *name) const;
virtual int addRef() { return RefCountedContext::addRef(); }
virtual int release() { return RefCountedContext::release(); }
private:
InheritanceGraphContext(DotGfxHierarchyTable *hierarchy,DotNode *n,int id);
~InheritanceGraphContext();
class Private;
Private *p;
};
//----------------------------------------------------
class ClassInheritanceNodeContext : public RefCountedContext, public TemplateStructIntf class ClassInheritanceNodeContext : public RefCountedContext, public TemplateStructIntf
{ {
public: public:
...@@ -485,8 +507,8 @@ class NestingNodeContext : public RefCountedContext, public TemplateStructIntf ...@@ -485,8 +507,8 @@ class NestingNodeContext : public RefCountedContext, public TemplateStructIntf
{ {
public: public:
static NestingNodeContext *alloc(const NestingNodeContext *parent,Definition *def, static NestingNodeContext *alloc(const NestingNodeContext *parent,Definition *def,
int index,int level,bool addClasses) int index,int level,bool addClasses,bool inherit,bool hideSuper)
{ return new NestingNodeContext(parent,def,index,level,addClasses); } { return new NestingNodeContext(parent,def,index,level,addClasses,inherit,hideSuper); }
QCString id() const; QCString id() const;
...@@ -497,7 +519,7 @@ class NestingNodeContext : public RefCountedContext, public TemplateStructIntf ...@@ -497,7 +519,7 @@ class NestingNodeContext : public RefCountedContext, public TemplateStructIntf
private: private:
NestingNodeContext(const NestingNodeContext *parent, NestingNodeContext(const NestingNodeContext *parent,
Definition *,int index,int level,bool addClasses); Definition *,int index,int level,bool addClasses,bool inherit,bool hideSuper);
~NestingNodeContext(); ~NestingNodeContext();
class Private; class Private;
Private *p; Private *p;
...@@ -527,6 +549,8 @@ class NestingContext : public RefCountedContext, public TemplateListIntf ...@@ -527,6 +549,8 @@ class NestingContext : public RefCountedContext, public TemplateListIntf
void addPages(const PageSDict &pages,bool rootOnly); void addPages(const PageSDict &pages,bool rootOnly);
void addModules(const GroupSDict &modules); void addModules(const GroupSDict &modules);
void addModules(const GroupList &modules); void addModules(const GroupList &modules);
void addClassHierarchy(const ClassSDict &clDict,bool rootOnly);
void addDerivedClasses(const BaseClassList *bcl,bool hideSuper);
private: private:
NestingContext(const NestingNodeContext *parent,int level); NestingContext(const NestingNodeContext *parent,int level);
......
...@@ -772,18 +772,18 @@ static bool checkDeliverables(const QCString &file1, ...@@ -772,18 +772,18 @@ static bool checkDeliverables(const QCString &file1,
//-------------------------------------------------------------------- //--------------------------------------------------------------------
/** Class representing a list of DotNode objects. */ inline int DotNode::findParent( DotNode *n )
class DotNodeList : public QList<DotNode> {
if ( !m_parents ) return -1;
return m_parents->find(n);
}
//--------------------------------------------------------------------
int DotNodeList::compareValues(const DotNode *n1,const DotNode *n2) const
{ {
public:
DotNodeList() : QList<DotNode>() {}
~DotNodeList() {}
private:
int compareValues(const DotNode *n1,const DotNode *n2) const
{
return qstricmp(n1->m_label,n2->m_label); return qstricmp(n1->m_label,n2->m_label);
} }
};
//-------------------------------------------------------------------- //--------------------------------------------------------------------
...@@ -1908,7 +1908,7 @@ void DotNode::write(FTextStream &t, ...@@ -1908,7 +1908,7 @@ void DotNode::write(FTextStream &t,
bool reNumber bool reNumber
) )
{ {
//printf("DotNode::write(%d) name=%s this=%p written=%d\n",distance,m_label.data(),this,m_written); //printf("DotNode::write(%d) name=%s this=%p written=%d visible=%d\n",m_distance,m_label.data(),this,m_written,m_visible);
if (m_written) return; // node already written to the output if (m_written) return; // node already written to the output
if (!m_visible) return; // node is not visible if (!m_visible) return; // node is not visible
writeBox(t,gt,format,m_truncated==Truncated,reNumber); writeBox(t,gt,format,m_truncated==Truncated,reNumber);
...@@ -2261,33 +2261,13 @@ const DotNode *DotNode::findDocNode() const ...@@ -2261,33 +2261,13 @@ const DotNode *DotNode::findDocNode() const
int DotGfxHierarchyTable::m_curNodeNumber; int DotGfxHierarchyTable::m_curNodeNumber;
void DotGfxHierarchyTable::writeGraph(FTextStream &out, void DotGfxHierarchyTable::createGraph(DotNode *n,FTextStream &out,
const char *path,const char *fileName) const const char *path,const char *fileName,int id) const
{ {
//printf("DotGfxHierarchyTable::writeGraph(%s)\n",name);
//printf("m_rootNodes=%p count=%d\n",m_rootNodes,m_rootNodes->count());
if (m_rootSubgraphs->count()==0) return;
QDir d(path); QDir d(path);
// store the original directory
if (!d.exists())
{
err("Output dir %s does not exist!\n",path); exit(1);
}
// put each connected subgraph of the hierarchy in a row of the HTML output
out << "<table border=\"0\" cellspacing=\"10\" cellpadding=\"0\">" << endl;
QListIterator<DotNode> dnli(*m_rootSubgraphs);
DotNode *n;
int count=0;
for (dnli.toFirst();(n=dnli.current());++dnli)
{
QCString baseName; QCString baseName;
QCString imgExt = Config_getEnum("DOT_IMAGE_FORMAT"); QCString imgExt = Config_getEnum("DOT_IMAGE_FORMAT");
baseName.sprintf("inherit_graph_%d",count++); baseName.sprintf("inherit_graph_%d",id);
//baseName = convertNameToFile(baseName);
QCString imgName = baseName+"."+ imgExt; QCString imgName = baseName+"."+ imgExt;
QCString mapName = baseName+".map"; QCString mapName = baseName+".map";
QCString absImgName = QCString(d.absPath().data())+"/"+imgName; QCString absImgName = QCString(d.absPath().data())+"/"+imgName;
...@@ -2347,7 +2327,6 @@ void DotGfxHierarchyTable::writeGraph(FTextStream &out, ...@@ -2347,7 +2327,6 @@ void DotGfxHierarchyTable::writeGraph(FTextStream &out,
Doxygen::indexList->addImageFile(imgName); Doxygen::indexList->addImageFile(imgName);
// write image and map in a table row // write image and map in a table row
QCString mapLabel = escapeCharsInString(n->m_label,FALSE); QCString mapLabel = escapeCharsInString(n->m_label,FALSE);
out << "<tr><td>";
if (imgExt=="svg") // vector graphics if (imgExt=="svg") // vector graphics
{ {
if (regenerate || !writeSVGFigureLink(out,QCString(),baseName,absImgName)) if (regenerate || !writeSVGFigureLink(out,QCString(),baseName,absImgName))
...@@ -2374,7 +2353,33 @@ void DotGfxHierarchyTable::writeGraph(FTextStream &out, ...@@ -2374,7 +2353,33 @@ void DotGfxHierarchyTable::writeGraph(FTextStream &out,
out << "<!-- MAP " << mapId << " -->" << endl; out << "<!-- MAP " << mapId << " -->" << endl;
} }
} }
}
void DotGfxHierarchyTable::writeGraph(FTextStream &out,
const char *path,const char *fileName) const
{
//printf("DotGfxHierarchyTable::writeGraph(%s)\n",name);
//printf("m_rootNodes=%p count=%d\n",m_rootNodes,m_rootNodes->count());
if (m_rootSubgraphs->count()==0) return;
QDir d(path);
// store the original directory
if (!d.exists())
{
err("Output dir %s does not exist!\n",path); exit(1);
}
// put each connected subgraph of the hierarchy in a row of the HTML output
out << "<table border=\"0\" cellspacing=\"10\" cellpadding=\"0\">" << endl;
QListIterator<DotNode> dnli(*m_rootSubgraphs);
DotNode *n;
int count=0;
for (dnli.toFirst();(n=dnli.current());++dnli)
{
out << "<tr><td>";
createGraph(n,out,path,fileName,count++);
out << "</td></tr>" << endl; out << "</td></tr>" << endl;
} }
out << "</table>" << endl; out << "</table>" << endl;
......
...@@ -122,6 +122,7 @@ class DotNode ...@@ -122,6 +122,7 @@ class DotNode
friend class DotNodeList; friend class DotNodeList;
friend class DotCallGraph; friend class DotCallGraph;
friend class DotGroupCollaboration; friend class DotGroupCollaboration;
friend class DotInheritanceGraph;
friend QCString computeMd5Signature( friend QCString computeMd5Signature(
DotNode *root, GraphType gt, DotNode *root, GraphType gt,
...@@ -133,12 +134,15 @@ class DotNode ...@@ -133,12 +134,15 @@ class DotNode
); );
}; };
inline int DotNode::findParent( DotNode *n ) /** Class representing a list of DotNode objects. */
class DotNodeList : public QList<DotNode>
{ {
if( !m_parents ) public:
return -1; DotNodeList() : QList<DotNode>() {}
return m_parents->find(n); ~DotNodeList() {}
} private:
int compareValues(const DotNode *n1,const DotNode *n2) const;
};
/** Represents a graphical class hierarchy */ /** Represents a graphical class hierarchy */
class DotGfxHierarchyTable class DotGfxHierarchyTable
...@@ -147,6 +151,8 @@ class DotGfxHierarchyTable ...@@ -147,6 +151,8 @@ class DotGfxHierarchyTable
DotGfxHierarchyTable(); DotGfxHierarchyTable();
~DotGfxHierarchyTable(); ~DotGfxHierarchyTable();
void writeGraph(FTextStream &t,const char *path, const char *fileName) const; void writeGraph(FTextStream &t,const char *path, const char *fileName) const;
void createGraph(DotNode *rootNode,FTextStream &t,const char *path,const char *fileName,int id) const;
const DotNodeList *subGraphs() const { return m_rootSubgraphs; }
private: private:
void addHierarchy(DotNode *n,ClassDef *cd,bool hide); void addHierarchy(DotNode *n,ClassDef *cd,bool hide);
......
...@@ -1976,10 +1976,21 @@ class ExpressionParser ...@@ -1976,10 +1976,21 @@ class ExpressionParser
ExprAst *parseLiteral() ExprAst *parseLiteral()
{ {
TRACE(("{parseLiteral(%s)\n",m_curToken.id.data())); TRACE(("{parseLiteral(%s)\n",m_curToken.id.data()));
ExprAst *lit = new ExprAstLiteral(m_curToken.id); ExprAst *expr = new ExprAstLiteral(m_curToken.id);
getNextToken(); getNextToken();
if (expr)
{
while (m_curToken.type==ExprToken::Operator &&
m_curToken.op==Operator::Filter)
{
getNextToken();
ExprAstFilter *filter = parseFilter();
if (!filter) break;
expr = new ExprAstFilterAppl(expr,filter);
}
}
TRACE(("}parseLiteral()\n")); TRACE(("}parseLiteral()\n"));
return lit; return expr;
} }
ExprAst *parseIdentifierOptionalArgs() ExprAst *parseIdentifierOptionalArgs()
...@@ -3550,6 +3561,7 @@ class TemplateNodeCreate : public TemplateNodeCreator<TemplateNodeCreate> ...@@ -3550,6 +3561,7 @@ class TemplateNodeCreate : public TemplateNodeCreator<TemplateNodeCreate>
{ {
outputFile.prepend(ci->outputDirectory()+"/"); outputFile.prepend(ci->outputDirectory()+"/");
} }
//printf("NoteCreate(%s)\n",outputFile.data());
QFile f(outputFile); QFile f(outputFile);
if (f.open(IO_WriteOnly)) if (f.open(IO_WriteOnly))
{ {
...@@ -3622,9 +3634,11 @@ class TemplateNodeTree : public TemplateNodeCreator<TemplateNodeTree> ...@@ -3622,9 +3634,11 @@ class TemplateNodeTree : public TemplateNodeCreator<TemplateNodeTree>
{ {
//printf("TemplateNodeTree::renderChildren(%d)\n",ctx->list->count()); //printf("TemplateNodeTree::renderChildren(%d)\n",ctx->list->count());
// render all children of node to a string and return it // render all children of node to a string and return it
TemplateContext *c = ctx->templateCtx;
TemplateContextImpl* ci = dynamic_cast<TemplateContextImpl*>(c);
if (ci==0) return QCString(); // should not happen
QGString result; QGString result;
FTextStream ss(&result); FTextStream ss(&result);
TemplateContext *c = ctx->templateCtx;
c->push(); c->push();
TemplateVariant node; TemplateVariant node;
TemplateListIntf::ConstIterator *it = ctx->list->createIterator(); TemplateListIntf::ConstIterator *it = ctx->list->createIterator();
...@@ -3642,14 +3656,21 @@ class TemplateNodeTree : public TemplateNodeCreator<TemplateNodeTree> ...@@ -3642,14 +3656,21 @@ class TemplateNodeTree : public TemplateNodeCreator<TemplateNodeTree>
if (list && list->count()>0) // non-empty list if (list && list->count()>0) // non-empty list
{ {
TreeContext childCtx(this,list,ctx->templateCtx); TreeContext childCtx(this,list,ctx->templateCtx);
// TemplateVariant children(&childCtx,renderChildrenStub);
TemplateVariant children(TemplateVariant::Delegate::fromFunction(&childCtx,renderChildrenStub)); TemplateVariant children(TemplateVariant::Delegate::fromFunction(&childCtx,renderChildrenStub));
children.setRaw(TRUE); children.setRaw(TRUE);
c->set("children",children); c->set("children",children);
m_treeNodes.render(ss,c); m_treeNodes.render(ss,c);
hasChildren=TRUE; hasChildren=TRUE;
} }
else if (list==0)
{
ci->warn(m_templateName,m_line,"recursetree: children attribute has type '%s' instead of list\n",v.typeAsString().data());
}
} }
//else
//{
// ci->warn(m_templateName,m_line,"recursetree: children attribute is not valid");
//}
} }
if (!hasChildren) if (!hasChildren)
{ {
......
...@@ -227,7 +227,7 @@ span.lineno a:hover { ...@@ -227,7 +227,7 @@ span.lineno a:hover {
background-color: #C8C8C8; background-color: #C8C8C8;
} }
div.ah { div.ah, span.ah {
background-color: black; background-color: black;
font-weight: bold; font-weight: bold;
color: #ffffff; color: #ffffff;
...@@ -245,6 +245,15 @@ div.ah { ...@@ -245,6 +245,15 @@ div.ah {
background-image: -moz-linear-gradient(center top, #eee 0%, #444 40%, #000); background-image: -moz-linear-gradient(center top, #eee 0%, #444 40%, #000);
} }
div.classindex ul {
list-style: none;
padding-left: 0;
}
div.classindex span.ai {
display: inline-block;
}
div.groupHeader { div.groupHeader {
margin-left: 16px; margin-left: 16px;
margin-top: 12px; margin-top: 12px;
......
...@@ -4,18 +4,46 @@ ...@@ -4,18 +4,46 @@
<div class="textblock"> <div class="textblock">
{% indexentry nav name=tr.classIndex file=page.fileName anchor='' %} {% indexentry nav name=tr.classIndex file=page.fileName anchor='' %}
</div> </div>
<div class="classindex" style="column-count:{{ config.COLS_IN_ALPHA_INDEX }};-moz-column-count:{{ config.COLS_IN_ALPHA_INDEX }};-webkit-column-count:{{ config.COLS_IN_ALPHA_INDEX}}">
<ul>
{% with index=classIndex.list|alphaIndex:'name' %} {% with index=classIndex.list|alphaIndex:'name' %}
{# quick index at top #}
<div class="qindex">
{% for section in index %} {% for section in index %}
<div class="ah">&#160;&#160;{{ section.letter }}&#160;&#160;</div> <a class="qindex" href="#letter_{{ section.label }}">{{ section.letter }}</a>
{% if not forloop.last %}
&#160;|&#160;
{% endif %}
{% endfor %}
</div>
{# multi column index #}
<div class="classindex" style="column-count:{{ config.COLS_IN_ALPHA_INDEX }};-moz-column-count:{{ config.COLS_IN_ALPHA_INDEX }};-webkit-column-count:{{ config.COLS_IN_ALPHA_INDEX}}">
{% for section in index %}
<ul>
{% for cls in section.items %} {% for cls in section.items %}
<li>{{ cls.name }}</li> <li>
<span class="ai">
{% if forloop.first %}
<a name="#letter_{{ section.label }}"></a>
<span class="ah">&#160;&#160;{{ section.letter }}&#160;&#160;</span><br/>
{% endif %}
{% with obj=cls text=cls.name %}
{% include 'htmlobjlink.tpl' %}
{% endwith %}
</span>
</li>
{% endfor %} {% endfor %}
</ul>
{% endfor %}
</div><!-- classindex -->
{# quick index at bottom #}
<div class="qindex">
{% for section in index %}
<a class="qindex" href="#letter_{{ section.label }}">{{ section.letter }}</a>
{% if not forloop.last %}
&#160;|&#160;
{% endif %}
{% endfor %} {% endfor %}
</div>
{% endwith %} {% endwith %}
</ul>
</div><!-- classindex -->
</div><!-- contents --> </div><!-- contents -->
{% endblock %} {% endblock %}
{% extend 'htmlbase.tpl' %}
{% block content %}
<div class="contents">
<div class="textblock">
<p><a href="hierarchy{{ config.HTML_FILE_EXTENSION }}">{{ tr.gotoTextualHierarchy }}</a></p>
</div>
<table border="0" cellspacing="10" cellpadding="0">
{% for d in classHierarchy.diagrams %}
<tr><td>{{ d.graph }}</td></tr>
{% endfor %}
</table>
</div>
{% endblock %}
{% extend 'htmlbase.tpl' %}
{% block content %}
<div class="contents">
<div class="textblock">
<p>{{ tr.classHierarchyDescription }}</p>
{% if config.HAVE_DOT and config.GRAPHICAL_HIERARCHY %}
<p><a href="inherits{{ config.HTML_FILE_EXTENSION }}">{{ tr.gotoGraphicalHierarchy }}</a></p>
{% endif %}
</div>
{% indexentry nav name=tr.classHierarchy file=page.fileName anchor='' %}
{% opensubindex nav %}
{% with tree=classHierarchy %}
{% include 'htmldirtree.tpl' %}
{% endwith %}
{% closesubindex nav %}
</div>
{% endblock %}
...@@ -179,7 +179,12 @@ ...@@ -179,7 +179,12 @@
{# TODO: write the class inheritance hierarchy #} {# TODO: write the class inheritance hierarchy #}
{% if classHierarchy.tree %} {% if classHierarchy.tree %}
{% with page=classHierarchy %} {% with page=classHierarchy %}
{# {% create classHierarchy.fileName|append:config.HTML_FILE_EXTENSION from 'hierarchy.tpl' %} #} {% create classHierarchy.fileName|append:config.HTML_FILE_EXTENSION from 'htmlhierarchy.tpl' %}
{% endwith %}
{% with page=classHierarchy %}
{% if config.HAVE_DOT and config.GRAPHICAL_HIERARCHY %}
{% create 'inherits'|append:config.HTML_FILE_EXTENSION from 'htmlgraphhierarchy.tpl' %}
{% endif %}
{% endwith %} {% endwith %}
{% endif %} {% endif %}
......
...@@ -34,7 +34,9 @@ ...@@ -34,7 +34,9 @@
{% if classHierarchy.tree %} {% if classHierarchy.tree %}
<li><a href="{{ page.relPath }}hierarchy{{ config.HTML_FILE_EXTENSION }}"><span>{{ tr.classHierarchy }} </span></a></li> <li><a href="{{ page.relPath }}hierarchy{{ config.HTML_FILE_EXTENSION }}"><span>{{ tr.classHierarchy }} </span></a></li>
{% endif %} {% endif %}
{% if classMembersIndex.all %}
<li><a href="{{ page.relPath }}functions{{ config.HTML_FILE_EXTENSION }}"><span>{{ tr.classMembers }} </span></a></li> <li><a href="{{ page.relPath }}functions{{ config.HTML_FILE_EXTENSION }}"><span>{{ tr.classMembers }} </span></a></li>
{% endif %}
</ul> </ul>
</li> </li>
{% endif %} {% endif %}
......
...@@ -83,8 +83,10 @@ ...@@ -83,8 +83,10 @@
{% if classHierarchy.tree %} {% if classHierarchy.tree %}
<li{% if page.subhighlight=='classhierarchy' %} class="current"{% endif %}><a href="{{ page.relPath }}hierarchy{{ config.HTML_FILE_EXTENSION }}"><span>{{ tr.classHierarchy|nowrap }}</span></a></li> <li{% if page.subhighlight=='classhierarchy' %} class="current"{% endif %}><a href="{{ page.relPath }}hierarchy{{ config.HTML_FILE_EXTENSION }}"><span>{{ tr.classHierarchy|nowrap }}</span></a></li>
{% endif %} {% endif %}
{% if classMembersIndex.all %}
<li{% if page.subhighlight=='classmembers' %} class="current"{% endif %}><a href="{{ page.relPath }}functions{{ config.HTML_FILE_EXTENSION }}"><span>{{ tr.classMembers|nowrap }}</span></a></li> <li{% if page.subhighlight=='classmembers' %} class="current"{% endif %}><a href="{{ page.relPath }}functions{{ config.HTML_FILE_EXTENSION }}"><span>{{ tr.classMembers|nowrap }}</span></a></li>
{% endif %} {% endif %}
{% endif %}
{# file subtabs #} {# file subtabs #}
{% if page.highlight=='files' %} {% if page.highlight=='files' %}
<li{% if page.subhighlight=='filelist' %} class="current"{% endif %}><a href="{{ page.relPath }}files{{ config.HTML_FILE_EXTENSION }}"><span>{{ tr.fileList|nowrap }}</span></a></li> <li{% if page.subhighlight=='filelist' %} class="current"{% endif %}><a href="{{ page.relPath }}files{{ config.HTML_FILE_EXTENSION }}"><span>{{ tr.fileList|nowrap }}</span></a></li>
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment