summaryrefslogtreecommitdiffstats
path: root/src/dot.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/dot.cpp')
-rw-r--r--src/dot.cpp231
1 files changed, 161 insertions, 70 deletions
diff --git a/src/dot.cpp b/src/dot.cpp
index 211ffa3..8587866 100644
--- a/src/dot.cpp
+++ b/src/dot.cpp
@@ -312,14 +312,15 @@ void DotNode::writeBox(QTextStream &t,bool hasNonReachableChildren)
t << "];" << endl;
}
-void DotNode::writeArrow(QTextStream &t,DotNode *cn,EdgeInfo *ei,bool topDown)
+void DotNode::writeArrow(QTextStream &t,DotNode *cn,EdgeInfo *ei,bool topDown,
+ bool pointBack)
{
t << " Node";
if (topDown) t << cn->number(); else t << m_number;
t << " -> Node";
if (topDown) t << m_number; else t << cn->number();
t << " [";
- t << "dir=back,";
+ if (pointBack) t << "dir=back,";
t << "color=\"" << edgeColorMap[ei->m_color]
<< "\",fontsize=10,style=\"" << edgeStyleMap[ei->m_style] << "\"";
if (!ei->m_label.isEmpty())
@@ -330,15 +331,16 @@ void DotNode::writeArrow(QTextStream &t,DotNode *cn,EdgeInfo *ei,bool topDown)
t << "];" << endl;
}
-void DotNode::write(QTextStream &t,bool topDown,int distance)
+void DotNode::write(QTextStream &t,bool topDown,bool toChildren,int distance)
{
//printf("DotNode::write(%d) name=%s\n",distance,m_label.data());
if (m_written) return; // node already written to the output
if (m_distance>distance) return;
+ QList<DotNode> *nl = toChildren ? m_children : m_parents;
bool hasNonReachableChildren=FALSE;
- if (m_distance==distance && m_children)
+ if (m_distance==distance && nl)
{
- QListIterator<DotNode> dnli(*m_children);
+ QListIterator<DotNode> dnli(*nl);
DotNode *cn;
for (dnli.toFirst();(cn=dnli.current());++dnli)
{
@@ -347,15 +349,38 @@ void DotNode::write(QTextStream &t,bool topDown,int distance)
}
writeBox(t,hasNonReachableChildren);
m_written=TRUE;
- if (m_children)
+ if (nl)
{
- QListIterator<DotNode> dnli1(*m_children);
- QListIterator<EdgeInfo> dnli2(*m_edgeInfo);
- DotNode *cn;
- for (dnli1.toFirst();(cn=dnli1.current());++dnli1,++dnli2)
+ if (toChildren)
{
- if (cn->m_distance<=distance) writeArrow(t,cn,dnli2.current(),topDown);
- cn->write(t,topDown,distance);
+ QListIterator<DotNode> dnli1(*nl);
+ QListIterator<EdgeInfo> dnli2(*m_edgeInfo);
+ DotNode *cn;
+ for (dnli1.toFirst();(cn=dnli1.current());++dnli1,++dnli2)
+ {
+ if (cn->m_distance<=distance)
+ {
+ writeArrow(t,cn,dnli2.current(),topDown);
+ }
+ cn->write(t,topDown,toChildren,distance);
+ }
+ }
+ else // render parents
+ {
+ QListIterator<DotNode> dnli(*nl);
+ DotNode *pn;
+ for (dnli.toFirst();(pn=dnli.current());++dnli)
+ {
+ if (pn->m_distance<=distance)
+ {
+ writeArrow(t,
+ pn,
+ pn->m_edgeInfo->at(pn->m_children->findRef(this)),
+ FALSE
+ );
+ }
+ pn->write(t,TRUE,FALSE,distance);
+ }
}
}
}
@@ -510,7 +535,7 @@ void DotGfxHierarchyTable::writeGraph(QTextStream &out,const char *path)
DotNode *node;
for (;(node=dnli2.current());++dnli2)
{
- if (node->m_subgraphId==n->m_subgraphId) node->write(t,FALSE);
+ if (node->m_subgraphId==n->m_subgraphId) node->write(t,FALSE,TRUE);
}
t << "}" << endl;
f.close();
@@ -712,82 +737,106 @@ DotGfxHierarchyTable::~DotGfxHierarchyTable()
//--------------------------------------------------------------------
-int DotGfxUsageGraph::m_curNodeNumber;
+int DotClassGraph::m_curNodeNumber;
-void DotGfxUsageGraph::addClass(ClassDef *cd,DotNode *n,int prot,
- const char *label,int distance)
+void DotClassGraph::addClass(ClassDef *cd,DotNode *n,int prot,
+ const char *label,int distance,const char *templSpec,bool base)
{
//printf(":: DoxGfxUsageGraph::addClass(class=%s,parent=%s,prot=%d,label=%s,dist=%d)\n",
// cd->name().data(),n->m_label.data(),prot,label,distance);
int edgeStyle = label ? EdgeInfo::Dashed : EdgeInfo::Solid;
- DotNode *bn = m_usedNodes->find(cd->name());
+ QCString className;
+ if (templSpec)
+ className=insertTemplateSpecifierInScope(cd->name(),templSpec);
+ else
+ className=cd->name().copy();
+ DotNode *bn = m_usedNodes->find(className);
if (bn) // class already inserted
{
- n->addChild(bn,prot,edgeStyle,label);
- bn->addParent(n);
+ if (base)
+ {
+ n->addChild(bn,prot,edgeStyle,label);
+ bn->addParent(n);
+ }
+ else
+ {
+ bn->addChild(n,prot,edgeStyle,label);
+ n->addParent(bn);
+ }
bn->setDistance(distance);
//printf(" add exiting node %s of %s\n",bn->m_label.data(),n->m_label.data());
}
else // new class
{
bn = new DotNode(m_curNodeNumber++,
- cd->name(),
+ className,
cd->isLinkable() ?
(cd->getReference()+"$"+cd->getOutputFileBase()).data() : 0,
distance
);
if (distance>m_maxDistance) m_maxDistance=distance;
- n->addChild(bn,prot,edgeStyle,label);
- bn->addParent(n);
- m_usedNodes->insert(cd->name(),bn);
+ if (base)
+ {
+ n->addChild(bn,prot,edgeStyle,label);
+ bn->addParent(n);
+ }
+ else
+ {
+ bn->addChild(n,prot,edgeStyle,label);
+ n->addParent(bn);
+ }
+ m_usedNodes->insert(className,bn);
//printf(" add used node %s of %s\n",cd->name().data(),n->m_label.data());
- if (distance<m_recDepth) buildGraph(cd,bn,distance+1);
+ if (distance<m_recDepth) buildGraph(cd,bn,distance+1,base);
}
}
-void DotGfxUsageGraph::buildGraph(ClassDef *cd,DotNode *n,int distance)
+void DotClassGraph::buildGraph(ClassDef *cd,DotNode *n,int distance,bool base)
{
- // add base classes
- BaseClassListIterator bcli(*cd->baseClasses());
+ BaseClassListIterator bcli(base ? *cd->baseClasses() : *cd->superClasses());
BaseClassDef *bcd;
for ( ; (bcd=bcli.current()) ; ++bcli )
{
- addClass(bcd->classDef,n,bcd->prot,0,distance);
+ addClass(bcd->classDef,n,bcd->prot,0,distance,bcd->templSpecifiers,base);
}
- UsesClassDict *dict = m_impl ? cd->usedImplementationClasses() :
- cd->usedInterfaceClasses();
- if (dict)
+ if (m_graphType != Inheritance)
{
- UsesClassDictIterator ucdi(*dict);
- UsesClassDef *ucd;
- for (;(ucd=ucdi.current());++ucdi)
+ UsesClassDict *dict =
+ m_graphType==Implementation ? cd->usedImplementationClasses() :
+ cd->usedInterfaceClasses();
+ if (dict)
{
- QCString label;
- QDictIterator<void> dvi(*ucd->accessors);
- const char *s;
- bool first=TRUE;
- for (;(s=dvi.currentKey());++dvi)
+ UsesClassDictIterator ucdi(*dict);
+ UsesClassDef *ucd;
+ for (;(ucd=ucdi.current());++ucdi)
{
- if (first)
- {
- label=s;
- first=FALSE;
- }
- else
+ QCString label;
+ QDictIterator<void> dvi(*ucd->accessors);
+ const char *s;
+ bool first=TRUE;
+ for (;(s=dvi.currentKey());++dvi)
{
- label+=QCString("\\n")+s;
+ if (first)
+ {
+ label=s;
+ first=FALSE;
+ }
+ else
+ {
+ label+=QCString("\\n")+s;
+ }
}
+ //printf("Found label=`%s'\n",label.data());
+ addClass(ucd->classDef,n,EdgeInfo::Black,label,distance,ucd->templSpecifiers,base);
}
- //printf("Found label=`%s'\n",label.data());
- addClass(ucd->classDef,n,EdgeInfo::Black,label,distance);
}
}
}
-DotGfxUsageGraph::DotGfxUsageGraph(ClassDef *cd,bool impl,int maxRecursionDepth)
+DotClassGraph::DotClassGraph(ClassDef *cd,GraphType t,int maxRecursionDepth)
{
//printf("DotGfxUsage::DotGfxUsage %s\n",cd->name().data());
- m_impl = impl;
+ m_graphType = t;
m_maxDistance = 0;
m_recDepth = maxRecursionDepth;
m_startNode = new DotNode(m_curNodeNumber++,
@@ -800,25 +849,33 @@ DotGfxUsageGraph::DotGfxUsageGraph(ClassDef *cd,bool impl,int maxRecursionDepth)
m_usedNodes = new QDict<DotNode>(1009);
m_usedNodes->insert(cd->name(),m_startNode);
//printf("Root node %s\n",cd->name().data());
- if (m_recDepth>0) buildGraph(cd,m_startNode,1);
+ if (m_recDepth>0)
+ {
+ buildGraph(cd,m_startNode,1,TRUE);
+ if (t==Inheritance) buildGraph(cd,m_startNode,1,FALSE);
+ }
m_diskName = cd->getOutputFileBase().copy();
}
-bool DotGfxUsageGraph::isTrivial() const
+bool DotClassGraph::isTrivial() const
{
- return m_startNode->m_children==0;
+ if (m_graphType==Inheritance)
+ return m_startNode->m_children==0 && m_startNode->m_parents==0;
+ else
+ return m_startNode->m_children==0;
}
-DotGfxUsageGraph::~DotGfxUsageGraph()
+DotClassGraph::~DotClassGraph()
{
deleteNodes(m_startNode);
delete m_usedNodes;
}
-static void writeDotGraph(DotNode *root,const QCString &baseName,
- bool lrRank,int distance)
+void writeDotGraph(DotNode *root,const QCString &baseName,
+ bool lrRank,bool renderParents,int distance)
{
// generate the graph description for dot
+ //printf("writeDotGraph(%s,%d)\n",baseName.data(),renderParents);
QFile f;
f.setName(baseName+".dot");
if (f.open(IO_WriteOnly))
@@ -831,7 +888,25 @@ static void writeDotGraph(DotNode *root,const QCString &baseName,
t << " rankdir=LR;" << endl;
}
root->clearWriteFlag();
- root->write(t,TRUE,distance);
+ root->write(t,TRUE,TRUE,distance);
+ if (renderParents && root->m_parents)
+ {
+ //printf("rendering parents!\n");
+ QListIterator<DotNode> dnli(*root->m_parents);
+ DotNode *pn;
+ for (dnli.toFirst();(pn=dnli.current());++dnli)
+ {
+ if (pn->m_distance<=distance)
+ {
+ root->writeArrow(t,
+ pn,
+ pn->m_edgeInfo->at(pn->m_children->findRef(root)),
+ FALSE
+ );
+ }
+ pn->write(t,TRUE,FALSE,distance);
+ }
+ }
t << "}" << endl;
f.close();
}
@@ -840,7 +915,8 @@ static void writeDotGraph(DotNode *root,const QCString &baseName,
static void findMaximalDotGraph(DotNode *root,int maxDist,
const QCString &baseName,
QDir &thisDir,
- bool lrRank=FALSE
+ bool lrRank=FALSE,
+ bool renderParents=FALSE
)
{
bool lastFit;
@@ -854,7 +930,7 @@ static void findMaximalDotGraph(DotNode *root,int maxDist,
// sized image (dimensions: maxImageWidth, maxImageHeight)
do
{
- writeDotGraph(root,baseName,lrRank,curDistance);
+ writeDotGraph(root,baseName,lrRank,renderParents,curDistance);
QCString dotCmd;
// create annotated dot file
@@ -891,19 +967,21 @@ static void findMaximalDotGraph(DotNode *root,int maxDist,
if (!lastFit)
{
//printf("Using last fit %d\n",minDistance);
- writeDotGraph(root,baseName,
+ writeDotGraph(root,
+ baseName,
lrRank || (curDistance==1 && width>maxImageWidth),
+ renderParents,
minDistance
);
}
}
-QCString DotGfxUsageGraph::diskName() const
+QCString DotClassGraph::diskName() const
{
return m_diskName + "_coll_graph";
}
-void DotGfxUsageGraph::writeGraph(QTextStream &out,
+void DotClassGraph::writeGraph(QTextStream &out,
const char *path,
bool isTBRank)
{
@@ -919,14 +997,27 @@ void DotGfxUsageGraph::writeGraph(QTextStream &out,
QDir thisDir;
QCString baseName;
- if (m_impl)
- baseName.sprintf("%s_coll_graph",m_diskName.data());
- else
- baseName.sprintf("%s_intf_graph",m_diskName.data());
+ QCString mapName;
+ switch (m_graphType)
+ {
+ case Implementation:
+ baseName.sprintf("%s_coll_graph",m_diskName.data());
+ mapName="coll_map";
+ break;
+ case Interface:
+ baseName.sprintf("%s_intf_graph",m_diskName.data());
+ mapName="intf_map";
+ break;
+ case Inheritance:
+ baseName.sprintf("%s_inherit_graph",m_diskName.data());
+ mapName="inherit_map";
+ break;
+ }
// TODO: make sure curDistance>0
- findMaximalDotGraph(m_startNode,m_maxDistance,baseName,thisDir,!isTBRank);
+ findMaximalDotGraph(m_startNode,m_maxDistance,baseName,
+ thisDir,!isTBRank,m_graphType==Inheritance);
// run dot to create a .gif image
QCString dotCmd;
@@ -948,12 +1039,12 @@ void DotGfxUsageGraph::writeGraph(QTextStream &out,
//printf("dot -Timap %s.dot -o %s.map\n",baseName.data(),baseName.data());
out << "<p><center><img src=\"" << baseName << ".gif\" border=\"0\" usemap=\"#"
- << m_startNode->m_label << "_impl_map\"></center>" << endl;
- out << "<map name=\"" << m_startNode->m_label << "_impl_map\">" << endl;
+ << m_startNode->m_label << "_" << mapName << "\"></center>" << endl;
+ out << "<map name=\"" << m_startNode->m_label << "_" << mapName << "\">" << endl;
convertMapFile(out,baseName+".map");
out << "</map><p>" << endl;
- thisDir.remove(baseName+".dot");
+ //thisDir.remove(baseName+".dot");
thisDir.remove(baseName+".map");
QDir::setCurrent(oldDir);