Skip to content

Commit

Permalink
Added graphical hierarchy support to template engine
Browse files Browse the repository at this point in the history
  • Loading branch information
Dimitri van Heesch committed Dec 25, 2014
1 parent 3ebc431 commit fe818bf
Show file tree
Hide file tree
Showing 12 changed files with 557 additions and 394 deletions.
573 changes: 302 additions & 271 deletions src/context.cpp

Large diffs are not rendered by default.

30 changes: 27 additions & 3 deletions src/context.h
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,8 @@ struct MemberInfo;
class MemberGroup;
class MemberGroupSDict;
class MemberGroupList;
class DotNode;
class DotGfxHierarchyTable;

//----------------------------------------------------

Expand Down Expand Up @@ -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
{
public:
Expand Down Expand Up @@ -485,8 +507,8 @@ class NestingNodeContext : public RefCountedContext, public TemplateStructIntf
{
public:
static NestingNodeContext *alloc(const NestingNodeContext *parent,Definition *def,
int index,int level,bool addClasses)
{ return new NestingNodeContext(parent,def,index,level,addClasses); }
int index,int level,bool addClasses,bool inherit,bool hideSuper)
{ return new NestingNodeContext(parent,def,index,level,addClasses,inherit,hideSuper); }

QCString id() const;

Expand All @@ -497,7 +519,7 @@ class NestingNodeContext : public RefCountedContext, public TemplateStructIntf

private:
NestingNodeContext(const NestingNodeContext *parent,
Definition *,int index,int level,bool addClasses);
Definition *,int index,int level,bool addClasses,bool inherit,bool hideSuper);
~NestingNodeContext();
class Private;
Private *p;
Expand Down Expand Up @@ -527,6 +549,8 @@ class NestingContext : public RefCountedContext, public TemplateListIntf
void addPages(const PageSDict &pages,bool rootOnly);
void addModules(const GroupSDict &modules);
void addModules(const GroupList &modules);
void addClassHierarchy(const ClassSDict &clDict,bool rootOnly);
void addDerivedClasses(const BaseClassList *bcl,bool hideSuper);

private:
NestingContext(const NestingNodeContext *parent,int level);
Expand Down
211 changes: 108 additions & 103 deletions src/dot.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -772,18 +772,18 @@ static bool checkDeliverables(const QCString &file1,

//--------------------------------------------------------------------

/** Class representing a list of DotNode objects. */
class DotNodeList : public QList<DotNode>
inline int DotNode::findParent( DotNode *n )
{
public:
DotNodeList() : QList<DotNode>() {}
~DotNodeList() {}
private:
int compareValues(const DotNode *n1,const DotNode *n2) const
{
return qstricmp(n1->m_label,n2->m_label);
}
};
if ( !m_parents ) return -1;
return m_parents->find(n);
}

//--------------------------------------------------------------------

int DotNodeList::compareValues(const DotNode *n1,const DotNode *n2) const
{
return qstricmp(n1->m_label,n2->m_label);
}

//--------------------------------------------------------------------

Expand Down Expand Up @@ -1908,7 +1908,7 @@ void DotNode::write(FTextStream &t,
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_visible) return; // node is not visible
writeBox(t,gt,format,m_truncated==Truncated,reNumber);
Expand Down Expand Up @@ -2261,12 +2261,106 @@ const DotNode *DotNode::findDocNode() const

int DotGfxHierarchyTable::m_curNodeNumber;

void DotGfxHierarchyTable::createGraph(DotNode *n,FTextStream &out,
const char *path,const char *fileName,int id) const
{
QDir d(path);
QCString baseName;
QCString imgExt = Config_getEnum("DOT_IMAGE_FORMAT");
baseName.sprintf("inherit_graph_%d",id);
QCString imgName = baseName+"."+ imgExt;
QCString mapName = baseName+".map";
QCString absImgName = QCString(d.absPath().data())+"/"+imgName;
QCString absMapName = QCString(d.absPath().data())+"/"+mapName;
QCString absBaseName = QCString(d.absPath().data())+"/"+baseName;
QListIterator<DotNode> dnli2(*m_rootNodes);
DotNode *node;

// compute md5 checksum of the graph were are about to generate
QGString theGraph;
FTextStream md5stream(&theGraph);
writeGraphHeader(md5stream,theTranslator->trGraphicalHierarchy());
md5stream << " rankdir=\"LR\";" << endl;
for (dnli2.toFirst();(node=dnli2.current());++dnli2)
{
if (node->m_subgraphId==n->m_subgraphId)
{
node->clearWriteFlag();
}
}
for (dnli2.toFirst();(node=dnli2.current());++dnli2)
{
if (node->m_subgraphId==n->m_subgraphId)
{
node->write(md5stream,DotNode::Hierarchy,GOF_BITMAP,FALSE,TRUE,TRUE,TRUE);
}
}
writeGraphFooter(md5stream);
resetReNumbering();
uchar md5_sig[16];
QCString sigStr(33);
MD5Buffer((const unsigned char *)theGraph.data(),theGraph.length(),md5_sig);
MD5SigToString(md5_sig,sigStr.data(),33);
bool regenerate=FALSE;
if (checkAndUpdateMd5Signature(absBaseName,sigStr) ||
!checkDeliverables(absImgName,absMapName))
{
regenerate=TRUE;
// image was new or has changed
QCString dotName=absBaseName+".dot";
QFile f(dotName);
if (!f.open(IO_WriteOnly)) return;
FTextStream t(&f);
t << theGraph;
f.close();
resetReNumbering();

DotRunner *dotRun = new DotRunner(dotName,d.absPath().data(),TRUE,absImgName);
dotRun->addJob(imgExt,absImgName);
dotRun->addJob(MAP_CMD,absMapName);
DotManager::instance()->addRun(dotRun);
}
else
{
removeDotGraph(absBaseName+".dot");
}
Doxygen::indexList->addImageFile(imgName);
// write image and map in a table row
QCString mapLabel = escapeCharsInString(n->m_label,FALSE);
if (imgExt=="svg") // vector graphics
{
if (regenerate || !writeSVGFigureLink(out,QCString(),baseName,absImgName))
{
if (regenerate)
{
DotManager::instance()->addSVGConversion(absImgName,QCString(),
FALSE,QCString(),FALSE,0);
}
int mapId = DotManager::instance()->addSVGObject(fileName,baseName,
absImgName,QCString());
out << "<!-- SVG " << mapId << " -->" << endl;
}
}
else // normal bitmap
{
out << "<img src=\"" << imgName << "\" border=\"0\" alt=\"\" usemap=\"#"
<< mapLabel << "\"/>" << endl;

if (regenerate || !insertMapFile(out,absMapName,QCString(),mapLabel))
{
int mapId = DotManager::instance()->addMap(fileName,absMapName,QCString(),
FALSE,QCString(),mapLabel);
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);
Expand All @@ -2284,97 +2378,8 @@ void DotGfxHierarchyTable::writeGraph(FTextStream &out,
int count=0;
for (dnli.toFirst();(n=dnli.current());++dnli)
{
QCString baseName;
QCString imgExt = Config_getEnum("DOT_IMAGE_FORMAT");
baseName.sprintf("inherit_graph_%d",count++);
//baseName = convertNameToFile(baseName);
QCString imgName = baseName+"."+ imgExt;
QCString mapName = baseName+".map";
QCString absImgName = QCString(d.absPath().data())+"/"+imgName;
QCString absMapName = QCString(d.absPath().data())+"/"+mapName;
QCString absBaseName = QCString(d.absPath().data())+"/"+baseName;
QListIterator<DotNode> dnli2(*m_rootNodes);
DotNode *node;

// compute md5 checksum of the graph were are about to generate
QGString theGraph;
FTextStream md5stream(&theGraph);
writeGraphHeader(md5stream,theTranslator->trGraphicalHierarchy());
md5stream << " rankdir=\"LR\";" << endl;
for (dnli2.toFirst();(node=dnli2.current());++dnli2)
{
if (node->m_subgraphId==n->m_subgraphId)
{
node->clearWriteFlag();
}
}
for (dnli2.toFirst();(node=dnli2.current());++dnli2)
{
if (node->m_subgraphId==n->m_subgraphId)
{
node->write(md5stream,DotNode::Hierarchy,GOF_BITMAP,FALSE,TRUE,TRUE,TRUE);
}
}
writeGraphFooter(md5stream);
resetReNumbering();
uchar md5_sig[16];
QCString sigStr(33);
MD5Buffer((const unsigned char *)theGraph.data(),theGraph.length(),md5_sig);
MD5SigToString(md5_sig,sigStr.data(),33);
bool regenerate=FALSE;
if (checkAndUpdateMd5Signature(absBaseName,sigStr) ||
!checkDeliverables(absImgName,absMapName))
{
regenerate=TRUE;
// image was new or has changed
QCString dotName=absBaseName+".dot";
QFile f(dotName);
if (!f.open(IO_WriteOnly)) return;
FTextStream t(&f);
t << theGraph;
f.close();
resetReNumbering();

DotRunner *dotRun = new DotRunner(dotName,d.absPath().data(),TRUE,absImgName);
dotRun->addJob(imgExt,absImgName);
dotRun->addJob(MAP_CMD,absMapName);
DotManager::instance()->addRun(dotRun);
}
else
{
removeDotGraph(absBaseName+".dot");
}
Doxygen::indexList->addImageFile(imgName);
// write image and map in a table row
QCString mapLabel = escapeCharsInString(n->m_label,FALSE);
out << "<tr><td>";
if (imgExt=="svg") // vector graphics
{
if (regenerate || !writeSVGFigureLink(out,QCString(),baseName,absImgName))
{
if (regenerate)
{
DotManager::instance()->addSVGConversion(absImgName,QCString(),
FALSE,QCString(),FALSE,0);
}
int mapId = DotManager::instance()->addSVGObject(fileName,baseName,
absImgName,QCString());
out << "<!-- SVG " << mapId << " -->" << endl;
}
}
else // normal bitmap
{
out << "<img src=\"" << imgName << "\" border=\"0\" alt=\"\" usemap=\"#"
<< mapLabel << "\"/>" << endl;

if (regenerate || !insertMapFile(out,absMapName,QCString(),mapLabel))
{
int mapId = DotManager::instance()->addMap(fileName,absMapName,QCString(),
FALSE,QCString(),mapLabel);
out << "<!-- MAP " << mapId << " -->" << endl;
}
}

createGraph(n,out,path,fileName,count++);
out << "</td></tr>" << endl;
}
out << "</table>" << endl;
Expand Down
16 changes: 11 additions & 5 deletions src/dot.h
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,7 @@ class DotNode
friend class DotNodeList;
friend class DotCallGraph;
friend class DotGroupCollaboration;
friend class DotInheritanceGraph;

friend QCString computeMd5Signature(
DotNode *root, GraphType gt,
Expand All @@ -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 )
return -1;
return m_parents->find(n);
}
public:
DotNodeList() : QList<DotNode>() {}
~DotNodeList() {}
private:
int compareValues(const DotNode *n1,const DotNode *n2) const;
};

/** Represents a graphical class hierarchy */
class DotGfxHierarchyTable
Expand All @@ -147,6 +151,8 @@ class DotGfxHierarchyTable
DotGfxHierarchyTable();
~DotGfxHierarchyTable();
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:
void addHierarchy(DotNode *n,ClassDef *cd,bool hide);
Expand Down
Loading

0 comments on commit fe818bf

Please sign in to comment.