diff options
author | dimitri <dimitri@afe2bf4a-e733-0410-8a33-86f594647bc7> | 2007-01-07 21:17:16 (GMT) |
---|---|---|
committer | dimitri <dimitri@afe2bf4a-e733-0410-8a33-86f594647bc7> | 2007-01-07 21:17:16 (GMT) |
commit | 0ee700fc0f6a02b75aa5651c23cc3339c1255ebc (patch) | |
tree | e21d038e7bc244d411ee71ee440f3b527bb9402f /src/dot.cpp | |
parent | be3407fc9ef6e4cf558cce39bb50dd2ab1168934 (diff) | |
download | Doxygen-0ee700fc0f6a02b75aa5651c23cc3339c1255ebc.zip Doxygen-0ee700fc0f6a02b75aa5651c23cc3339c1255ebc.tar.gz Doxygen-0ee700fc0f6a02b75aa5651c23cc3339c1255ebc.tar.bz2 |
Release-1.5.1-20070107
Diffstat (limited to 'src/dot.cpp')
-rw-r--r-- | src/dot.cpp | 854 |
1 files changed, 585 insertions, 269 deletions
diff --git a/src/dot.cpp b/src/dot.cpp index 37268ee..188b15f 100644 --- a/src/dot.cpp +++ b/src/dot.cpp @@ -1,6 +1,6 @@ /***************************************************************************** * - * $Id$ + * * * * Copyright (C) 1997-2006 by Dimitri van Heesch. @@ -34,6 +34,7 @@ #include <qtextstream.h> #include <md5.h> +#define MAP_CMD "cmap" //-------------------------------------------------------------------- @@ -84,6 +85,7 @@ static void writeGraphFooter(QTextStream &t) t << "}" << endl; } +#if 0 /*! converts the rectangles in a server site image map into a client * site image map. * \param t the stream to which the result is written. @@ -198,6 +200,105 @@ static bool convertMapFile(QTextStream &t,const char *mapName, return TRUE; } +#endif + +/*! converts the rectangles in a client site image map into a stream + * \param t the stream to which the result is written. + * \param mapName the name of the map file. + * \param relPath the relative path to the root of the output directory + * (used in case CREATE_SUBDIRS is enabled). + * \param urlOnly if FALSE the url field in the map contains an external + * references followed by a $ and then the URL. + * \returns TRUE if succesful. + */ +static bool convertMapFile(QTextStream &t,const char *mapName, + const QCString relPath, bool urlOnly=FALSE) +{ + QFile f(mapName); + if (!f.open(IO_ReadOnly)) + { + err("Error opening map file %s for inclusion in the docs!\n",mapName); + return FALSE; + } + const int maxLineLen=10240; + while (!f.atEnd()) // foreach line + { + QCString buf(maxLineLen); + int numBytes = f.readLine(buf.data(),maxLineLen); + buf[numBytes-1]='\0'; + + // search for href="...", store ... part in link + int indexS = buf.find("href=\""), indexE; + if (indexS!=-1 && (indexE=buf.find('"',indexS+6))!=-1) + { + QCString link = buf.mid(indexS+6,indexE-indexS-6); + QCString result; + QCString *dest; + if (urlOnly) // for user defined dot graphs + { + if (link.left(5)=="\\ref ") // \ref url + { + result="href=\""; + // fake ref node to resolve the url + DocRef *df = new DocRef( (DocNode*) 0, link.mid(5) ); + if (!df->ref().isEmpty()) + { + if ((dest=Doxygen::tagDestinationDict[df->ref()])) + result += *dest + "/"; + } + else if (!relPath.isEmpty()) + { + result += relPath; + } + if (!df->file().isEmpty()) + result += df->file().data() + Doxygen::htmlFileExtension; + if (!df->anchor().isEmpty()) + result += "#" + df->anchor(); + delete df; + result += "\""; + } + else + { + result = "href=\"" + link + "\""; + } + } + else // ref$url (external ref via tag file), or $url (local ref) + { + int marker = link.find('$'); + if (marker!=-1) + { + QCString ref = link.left(marker); + QCString url = link.mid(marker+1); + if (!ref.isEmpty()) + { + result = "doxygen=\"" + ref + ":"; + if ((dest=Doxygen::tagDestinationDict[ref])) result += *dest + "/"; + result += "\" "; + } + result+= "href=\""; + if (!ref.isEmpty()) + { + if ((dest=Doxygen::tagDestinationDict[ref])) result += *dest + "/"; + } + else if (!relPath.isEmpty()) + { + result += relPath; + } + result+= url + "\""; + } + else // should not happen, but handle properly anyway + { + result = "href=\"" + link + "\""; + } + } + QCString leftPart = buf.left(indexS); + QCString rightPart = buf.mid(indexE+1); + buf = leftPart + result + rightPart; + } + t << buf; + } + return TRUE; +} static QArray<int> s_newNumber; static int s_max_newNumber=0; @@ -241,6 +342,7 @@ static void resetReNumbering() s_newNumber.resize(s_max_newNumber); } +#if 0 static bool readBoundingBoxDot(const char *fileName,int *width,int *height) { QFile f(fileName); @@ -263,6 +365,7 @@ static bool readBoundingBoxDot(const char *fileName,int *width,int *height) } return FALSE; } +#endif static bool readBoundingBoxEPS(const char *fileName,int *width,int *height) { @@ -360,6 +463,7 @@ static bool checkAndUpdateMd5Signature(const QCString &baseName,const QCString & // read checksum QCString md5stored(33); int bytesRead=f.readBlock(md5stored.data(),32); + md5stored[32]='\0'; // compare checksum if (bytesRead==32 && md5==md5stored) { @@ -405,17 +509,20 @@ void DotRunner::addJob(const char *format,const char *output) bool DotRunner::run() { + int exitCode=0; + static QCString dotExe = Config_getString("DOT_PATH")+"dot"; + QCString dotArgs; QListIterator<QCString> li(m_jobs); QCString *s; if (Config_getBool("DOT_MULTI_TARGETS")) { - QCString dotArgs="\""+m_file+"\""; + dotArgs="\""+m_file+"\""; for (li.toFirst();(s=li.current());++li) { dotArgs+=' '; dotArgs+=*s; } - if (iSystem(Config_getString("DOT_PATH")+"dot",dotArgs,FALSE)!=0) + if ((exitCode=iSystem(dotExe,dotArgs,FALSE))!=0) { goto error; } @@ -424,8 +531,8 @@ bool DotRunner::run() { for (li.toFirst();(s=li.current());++li) { - QCString dotArgs="\""+m_file+"\" "+*s; - if (iSystem(Config_getString("DOT_PATH")+"dot",dotArgs,FALSE)!=0) + dotArgs="\""+m_file+"\" "+*s; + if ((exitCode=iSystem(dotExe,dotArgs,FALSE))!=0) { goto error; } @@ -433,7 +540,8 @@ bool DotRunner::run() } return TRUE; error: - err("Problems running dot. Check your installation!\n"); + err("Problems running dot: exit code=%d, command='%s', arguments='%s'\n", + exitCode,dotExe.data(),dotArgs.data()); return FALSE; } @@ -452,18 +560,24 @@ static void deleteNodes(DotNode *node,SDict<DotNode> *skipNodes=0) deletedNodes.clear(); // actually remove the nodes. } -DotNode::DotNode(int n,const char *lab,const char *url,int distance, +DotNode::DotNode(int n,const char *lab,const char *tip, const char *url, bool isRoot,ClassDef *cd) - : m_number(n), m_label(lab), m_url(url), m_isRoot(isRoot), m_classDef(cd) + : m_subgraphId(-1) + , m_number(n) + , m_label(lab) + , m_tooltip(tip) + , m_url(url) + , m_parents(0) + , m_children(0) + , m_edgeInfo(0) + , m_deleted(FALSE) + , m_written(FALSE) + , m_hasDoc(FALSE) + , m_isRoot(isRoot) + , m_classDef(cd) + , m_visible(FALSE) + , m_truncated(Unknown) { - m_children = 0; - m_edgeInfo = 0; - m_parents = 0; - m_subgraphId =-1; - m_deleted = FALSE; - m_written = FALSE; - m_hasDoc = FALSE; - m_distance = distance; } DotNode::~DotNode() @@ -473,11 +587,6 @@ DotNode::~DotNode() delete m_edgeInfo; } -void DotNode::setDistance(int distance) -{ - if (distance<m_distance) m_distance=distance; -} - void DotNode::addChild(DotNode *n, int edgeColor, int edgeStyle, @@ -663,7 +772,7 @@ void DotNode::writeBox(QTextStream &t, } t << "}"; } - else // old look + else // standard look { t << convertLabel(m_label); } @@ -695,6 +804,10 @@ void DotNode::writeBox(QTextStream &t, << m_url.right(m_url.length()-anchorPos) << "\""; } } + if (!m_tooltip.isEmpty()) + { + t << ",tooltip=\"" << m_tooltip << "\""; + } } t << "];" << endl; } @@ -741,27 +854,16 @@ void DotNode::write(QTextStream &t, GraphOutputFormat format, bool topDown, bool toChildren, - int distance, bool backArrows, bool reNumber ) { //printf("DotNode::write(%d) name=%s this=%p written=%d\n",distance,m_label.data(),this,m_written); 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 && nl) - { - QListIterator<DotNode> dnli(*nl); - DotNode *cn; - for (dnli.toFirst();(cn=dnli.current());++dnli) - { - if (cn->m_distance>distance) hasNonReachableChildren=TRUE; - } - } - writeBox(t,gt,format,hasNonReachableChildren,reNumber); + if (!m_visible) return; // node is not visible + writeBox(t,gt,format,m_truncated==Truncated,reNumber); m_written=TRUE; + QList<DotNode> *nl = toChildren ? m_children : m_parents; if (nl) { if (toChildren) @@ -771,12 +873,12 @@ void DotNode::write(QTextStream &t, DotNode *cn; for (dnli1.toFirst();(cn=dnli1.current());++dnli1,++dnli2) { - if (cn->m_distance<=distance) + if (cn->isVisible()) { //printf("write arrow %s%s%s\n",label().data(),backArrows?"<-":"->",cn->label().data()); writeArrow(t,gt,format,cn,dnli2.current(),topDown,backArrows,reNumber); } - cn->write(t,gt,format,topDown,toChildren,distance,backArrows,reNumber); + cn->write(t,gt,format,topDown,toChildren,backArrows,reNumber); } } else // render parents @@ -785,7 +887,7 @@ void DotNode::write(QTextStream &t, DotNode *pn; for (dnli.toFirst();(pn=dnli.current());++dnli) { - if (pn->m_distance<=distance) + if (pn->isVisible()) { //printf("write arrow %s%s%s\n",label().data(),backArrows?"<-":"->",pn->label().data()); writeArrow(t, @@ -798,7 +900,7 @@ void DotNode::write(QTextStream &t, reNumber ); } - pn->write(t,gt,format,TRUE,FALSE,distance,backArrows,reNumber); + pn->write(t,gt,format,TRUE,FALSE,backArrows,reNumber); } } } @@ -978,6 +1080,7 @@ void DotNode::colorConnectedNodes(int curColor) if (cn->m_subgraphId==-1) // uncolored child node { cn->m_subgraphId=curColor; + cn->markAsVisible(); cn->colorConnectedNodes(curColor); //printf("coloring node %s (%p): %d\n",cn->m_label.data(),cn,cn->m_subgraphId); } @@ -993,6 +1096,7 @@ void DotNode::colorConnectedNodes(int curColor) if (pn->m_subgraphId==-1) // uncolored parent node { pn->m_subgraphId=curColor; + pn->markAsVisible(); pn->colorConnectedNodes(curColor); //printf("coloring node %s (%p): %d\n",pn->m_label.data(),pn,pn->m_subgraphId); } @@ -1074,8 +1178,10 @@ void DotGfxHierarchyTable::writeGraph(QTextStream &out,const char *path) DotNode *node; // compute md5 checksum of the graph were are about to generate - QString buf; - QTextStream md5stream(&buf,IO_WriteOnly); + QString theGraph; + QTextStream md5stream(&theGraph,IO_WriteOnly); + writeGraphHeader(md5stream); + md5stream << " rankdir=LR;" << endl; for (dnli2.toFirst();(node=dnli2.current());++dnli2) { if (node->m_subgraphId==n->m_subgraphId) @@ -1087,13 +1193,14 @@ void DotGfxHierarchyTable::writeGraph(QTextStream &out,const char *path) { if (node->m_subgraphId==n->m_subgraphId) { - node->write(md5stream,DotNode::Hierarchy,BITMAP,FALSE,TRUE,1000,TRUE,TRUE); + node->write(md5stream,DotNode::Hierarchy,BITMAP,FALSE,TRUE,TRUE,TRUE); } } + writeGraphFooter(md5stream); resetReNumbering(); uchar md5_sig[16]; QCString sigStr(33); - MD5Buffer((const unsigned char *)buf.ascii(),buf.length(),md5_sig); + MD5Buffer((const unsigned char *)theGraph.ascii(),theGraph.length(),md5_sig); MD5SigToString(md5_sig,sigStr.data(),33); if (checkAndUpdateMd5Signature(baseName,sigStr) || !QFileInfo(mapName).exists()) @@ -1103,29 +1210,13 @@ void DotGfxHierarchyTable::writeGraph(QTextStream &out,const char *path) QFile f(dotName); if (!f.open(IO_WriteOnly)) return; QTextStream t(&f); - writeGraphHeader(t); - t << " 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(t,DotNode::Hierarchy,BITMAP,FALSE,TRUE,1000,TRUE,TRUE); - } - } - writeGraphFooter(t); + t << theGraph; f.close(); resetReNumbering(); DotRunner dotRun(dotName); dotRun.addJob(imgExt,imgName); - dotRun.addJob("imap",mapName); + dotRun.addJob(MAP_CMD,mapName); if (!dotRun.run()) { out << "</table>" << endl; @@ -1190,8 +1281,10 @@ void DotGfxHierarchyTable::addHierarchy(DotNode *n,ClassDef *cd,bool hideSuper) { tmp_url=bClass->getReference()+"$"+bClass->getOutputFileBase(); } + QCString tooltip = bClass->briefDescriptionAsTooltip(); bn = new DotNode(m_curNodeNumber++, bClass->displayName(), + tooltip, tmp_url.data() ); n->addChild(bn,bcd->prot); @@ -1234,8 +1327,10 @@ void DotGfxHierarchyTable::addClassList(ClassSDict *cl) tmp_url=cd->getReference()+"$"+cd->getOutputFileBase(); } //printf("Inserting root class %s\n",cd->name().data()); + QCString tooltip = cd->briefDescriptionAsTooltip(); DotNode *n = new DotNode(m_curNodeNumber++, cd->displayName(), + tooltip, tmp_url.data()); //m_usedNodes->clear(); @@ -1281,6 +1376,7 @@ DotGfxHierarchyTable::DotGfxHierarchyTable() //printf("Starting at node %s (%p): %d\n",n->m_label.data(),n,curColor); done=FALSE; // still uncolored nodes n->m_subgraphId=curColor; + n->markAsVisible(); n->colorConnectedNodes(curColor); curColor++; const DotNode *dn=n->findDocNode(); @@ -1325,7 +1421,7 @@ DotGfxHierarchyTable::~DotGfxHierarchyTable() int DotClassGraph::m_curNodeNumber = 0; void DotClassGraph::addClass(ClassDef *cd,DotNode *n,int prot, - const char *label,int distance,const char *usedName,const char *templSpec,bool base) + const char *label,const char *usedName,const char *templSpec,bool base) { if (Config_getBool("HIDE_UNDOC_CLASSES") && !cd->isLinkable()) return; @@ -1358,7 +1454,6 @@ void DotClassGraph::addClass(ClassDef *cd,DotNode *n,int prot, 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 @@ -1370,14 +1465,14 @@ void DotClassGraph::addClass(ClassDef *cd,DotNode *n,int prot, { tmp_url=cd->getReference()+"$"+cd->getOutputFileBase(); } + QCString tooltip = cd->briefDescriptionAsTooltip(); bn = new DotNode(m_curNodeNumber++, displayName, + tooltip, tmp_url.data(), - distance, FALSE, // rootNode cd ); - if (distance>m_maxDistance) m_maxDistance=distance; if (base) { n->addChild(bn,prot,edgeStyle,label); @@ -1392,13 +1487,85 @@ void DotClassGraph::addClass(ClassDef *cd,DotNode *n,int prot, //printf(" add new child node `%s' to %s hidden=%d url=%s\n", // className.data(),n->m_label.data(),cd->isHidden(),tmp_url.data()); - // we use <=, i.s.o < to cause one more level than intended which is used to - // detect truncated nodes - if (distance<=m_recDepth) buildGraph(cd,bn,distance+1,base); + buildGraph(cd,bn,base); + } +} + +void DotClassGraph::determineTruncatedNodes(QList<DotNode> &queue,bool includeParents) +{ + while (queue.count()>0) + { + DotNode *n = queue.take(0); + if (n->isVisible() && n->isTruncated()==DotNode::Unknown) + { + bool truncated = FALSE; + if (n->m_children) + { + QListIterator<DotNode> li(*n->m_children); + DotNode *dn; + for (li.toFirst();(dn=li.current());++li) + { + if (!dn->isVisible()) + truncated = TRUE; + else + queue.append(dn); + } + } + if (n->m_parents && includeParents) + { + QListIterator<DotNode> li(*n->m_parents); + DotNode *dn; + for (li.toFirst();(dn=li.current());++li) + { + if (!dn->isVisible()) + truncated = TRUE; + else + queue.append(dn); + } + } + n->markAsTruncated(truncated); + } } } -void DotClassGraph::buildGraph(ClassDef *cd,DotNode *n,int distance,bool base) +void DotClassGraph::determineVisibleNodes(QList<DotNode> &queue, + int &maxNodes,bool includeParents) +{ + while (queue.count()>0 && maxNodes>0) + { + DotNode *n = queue.take(0); + //printf("*** Processing node %p queue=%d maxNodes=%d m_children=%p m_parents=%p\n", + // n,queue.count(),maxNodes,n->m_children,n->m_parents); + if (!n->isVisible()) // not yet processed + { + //printf(" Marked as visible!\n"); + n->markAsVisible(); + maxNodes--; + // add direct children + if (n->m_children) + { + QListIterator<DotNode> li(*n->m_children); + DotNode *dn; + for (li.toFirst();(dn=li.current());++li) + { + queue.append(dn); + } + } + // add direct parents + if (n->m_parents && includeParents) + { + QListIterator<DotNode> li(*n->m_parents); + DotNode *dn; + for (li.toFirst();(dn=li.current());++li) + { + queue.append(dn); + } + } + } + } +} + +void DotClassGraph::buildGraph(ClassDef *cd,DotNode *n,bool base) { //printf("DocClassGraph::buildGraph(%s,distance=%d,base=%d)\n", // cd->name().data(),distance,base); @@ -1415,7 +1582,7 @@ void DotClassGraph::buildGraph(ClassDef *cd,DotNode *n,int distance,bool base) { //printf("-------- inheritance relation %s->%s templ=`%s'\n", // cd->name().data(),bcd->classDef->name().data(),bcd->templSpecifiers.data()); - addClass(bcd->classDef,n,bcd->prot,0,distance,bcd->usedName, + addClass(bcd->classDef,n,bcd->prot,0,bcd->usedName, bcd->templSpecifiers,base); } } @@ -1434,15 +1601,6 @@ void DotClassGraph::buildGraph(ClassDef *cd,DotNode *n,int distance,bool base) UsesClassDef *ucd; for (;(ucd=ucdi.current());++ucdi) { - //if (base) - //{ - // printf("%s uses %s\n",cd->name().data(),ucd->classDef->name().data()); - //} - //else - //{ - // printf("%s is used by %s\n",cd->name().data(),ucd->classDef->name().data()); - //} - //printf("drawing\n"); QCString label; QDictIterator<void> dvi(*ucd->accessors); const char *s; @@ -1459,7 +1617,7 @@ void DotClassGraph::buildGraph(ClassDef *cd,DotNode *n,int distance,bool base) label+=QCString("\n")+s; } } - addClass(ucd->classDef,n,EdgeInfo::Purple,label,distance,0, + addClass(ucd->classDef,n,EdgeInfo::Purple,label,0, ucd->templSpecifiers,base); } } @@ -1480,7 +1638,7 @@ void DotClassGraph::buildGraph(ClassDef *cd,DotNode *n,int distance,bool base) { if (templInstance==cd) { - addClass(templMaster,n,EdgeInfo::Orange,cli.currentKey(),distance,0, + addClass(templMaster,n,EdgeInfo::Orange,cli.currentKey(),0, 0,TRUE); } } @@ -1495,7 +1653,7 @@ void DotClassGraph::buildGraph(ClassDef *cd,DotNode *n,int distance,bool base) ClassDef *templInstance; for (;(templInstance=cli.current());++cli) { - addClass(templInstance,n,EdgeInfo::Orange,cli.currentKey(),distance,0, + addClass(templInstance,n,EdgeInfo::Orange,cli.currentKey(),0, 0,FALSE); } } @@ -1503,42 +1661,48 @@ void DotClassGraph::buildGraph(ClassDef *cd,DotNode *n,int distance,bool base) } } -DotClassGraph::DotClassGraph(ClassDef *cd,DotNode::GraphType t,int maxRecursionDepth) +DotClassGraph::DotClassGraph(ClassDef *cd,DotNode::GraphType t) { //printf("--------------- DotClassGraph::DotClassGraph `%s'\n",cd->displayName().data()); m_graphType = t; - m_maxDistance = 0; - m_recDepth = maxRecursionDepth; QCString tmp_url=""; if (cd->isLinkable() && !cd->isHidden()) { tmp_url=cd->getReference()+"$"+cd->getOutputFileBase(); } QCString className = cd->displayName(); - //if (cd->templateArguments()) - //{ - // className+=tempArgListToString(cd->templateArguments()); - //} + QCString tooltip = cd->briefDescriptionAsTooltip(); m_startNode = new DotNode(m_curNodeNumber++, className, + tooltip, tmp_url.data(), - 0, // distance TRUE, // is a root node cd ); m_usedNodes = new QDict<DotNode>(1009); m_usedNodes->insert(className,m_startNode); - //ClassSDict::Iterator cli(Doxygen::classSDict); - //ClassDef *icd; - //for (cli.toFirst();(icd=cli.current());++cli) icd->initTemplateMapping(); - //printf("Root node %s\n",cd->name().data()); - if (m_recDepth>0) - { - buildGraph(cd,m_startNode,1,TRUE); - if (t==DotNode::Inheritance) buildGraph(cd,m_startNode,1,FALSE); - } + //if (m_recDepth>0) + //{ + buildGraph(cd,m_startNode,TRUE); + if (t==DotNode::Inheritance) buildGraph(cd,m_startNode,FALSE); + //} + + int maxNodes = Config_getInt("DOT_GRAPH_MAX_NODES"); + int directChildNodes = 1; + if (m_startNode->m_children!=0) + directChildNodes+=m_startNode->m_children->count(); + if (t==DotNode::Inheritance && m_startNode->m_parents!=0) + directChildNodes+=m_startNode->m_parents->count(); + if (directChildNodes>maxNodes) maxNodes=directChildNodes; + QList<DotNode> openNodeQueue; + openNodeQueue.append(m_startNode); + determineVisibleNodes(openNodeQueue,maxNodes,t==DotNode::Inheritance); + openNodeQueue.clear(); + openNodeQueue.append(m_startNode); + determineTruncatedNodes(openNodeQueue,t==DotNode::Inheritance); + m_diskName = cd->getFileBase().copy(); } @@ -1556,6 +1720,7 @@ DotClassGraph::~DotClassGraph() delete m_usedNodes; } +#if 0 void writeDotGraph(DotNode *root, DotNode::GraphType gt, GraphOutputFormat format, @@ -1607,6 +1772,7 @@ void writeDotGraph(DotNode *root, f.close(); } } +#endif /*! Computes a 16 byte md5 checksum for a given dot graph. * The md5 checksum is returned as a 32 character ASCII string. @@ -1616,8 +1782,8 @@ QCString computeMd5Signature(DotNode *root, GraphOutputFormat format, bool lrRank, bool renderParents, - int distance, - bool backArrows + bool backArrows, + QCString &graphStr ) { bool reNumber=TRUE; @@ -1625,33 +1791,42 @@ QCString computeMd5Signature(DotNode *root, //printf("computeMd5Signature\n"); QString buf; QTextStream md5stream(&buf,IO_WriteOnly); + writeGraphHeader(md5stream); if (lrRank) { md5stream << "rankdir=LR;" << endl; } root->clearWriteFlag(); - root->write(md5stream,gt,format,gt!=DotNode::CallGraph,TRUE,distance,backArrows,reNumber); + root->write(md5stream,gt,format,gt!=DotNode::CallGraph,TRUE,backArrows,reNumber); if (renderParents && root->m_parents) { QListIterator<DotNode> dnli(*root->m_parents); DotNode *pn; for (dnli.toFirst();(pn=dnli.current());++dnli) { - if (pn->m_distance<=distance) + if (pn->isVisible()) { - root->writeArrow(md5stream, - gt, - format, - pn, - pn->m_edgeInfo->at(pn->m_children->findRef(root)), - FALSE, - backArrows, - reNumber + root->writeArrow(md5stream, // stream + gt, // graph type + format, // output format + pn, // child node + pn->m_edgeInfo->at(pn->m_children->findRef(root)), // edge info + FALSE, // topDown? + backArrows, // point back? + reNumber // renumber nodes ); } - pn->write(md5stream,gt,format,TRUE,FALSE,distance,backArrows,reNumber); + pn->write(md5stream, // stream + gt, // graph type + format, // output format + TRUE, // topDown? + FALSE, // toChildren? + backArrows, // backward pointing arrows? + reNumber // renumber nodes? + ); } } + writeGraphFooter(md5stream); uchar md5_sig[16]; QCString sigStr(33); MD5Buffer((const unsigned char *)buf.ascii(),buf.length(),md5_sig); @@ -1660,10 +1835,40 @@ QCString computeMd5Signature(DotNode *root, { resetReNumbering(); } + graphStr=buf.ascii(); //printf("md5: %s | file: %s\n",sigStr,baseName.data()); return sigStr; } +static bool updateDotGraph(DotNode *root, + DotNode::GraphType gt, + //QDir &thisDir, + const QCString &baseName, + GraphOutputFormat format, + bool lrRank, + bool renderParents, + bool backArrows + ) +{ + QCString theGraph; + // TODO: write graph to theGraph, then compute md5 checksum + QCString md5 = computeMd5Signature( + root,gt,format,lrRank,renderParents,backArrows,theGraph); + if (checkAndUpdateMd5Signature(baseName,md5)) // graph needs to be regenerated + { + QFile f; + f.setName(baseName+".dot"); + if (f.open(IO_WriteOnly)) + { + QTextStream t(&f); + t << theGraph; + } + return TRUE; + } + return FALSE; +} + +#if 0 static bool findMaximalDotGraph(DotNode *root, int maxDist, const QCString &baseName, @@ -1750,6 +1955,7 @@ static bool findMaximalDotGraph(DotNode *root, } return TRUE; } +#endif QCString DotClassGraph::diskName() const { @@ -1810,28 +2016,17 @@ QCString DotClassGraph::writeGraph(QTextStream &out, baseName = convertNameToFile(diskName()); QCString imgExt = Config_getEnum("DOT_IMAGE_FORMAT"); - QCString md5 = computeMd5Signature(m_startNode, // root - m_graphType, // gt - format, // format - !isTBRank, // lrRank - m_graphType==DotNode::Inheritance, // renderParent - QMIN(m_recDepth,m_maxDistance), // maxDist - TRUE // backArrows - ); - if (checkAndUpdateMd5Signature(baseName,md5) || - !QFileInfo(baseName+".map").exists() - ) + + if (updateDotGraph(m_startNode, + m_graphType, + baseName, + format, + !isTBRank, + m_graphType==DotNode::Inheritance, + TRUE + ) + ) { - findMaximalDotGraph(m_startNode, // root - QMIN(m_recDepth,m_maxDistance), // maxDist - baseName, // baseName - thisDir, // thisDir - m_graphType, // gt - format, // format - !isTBRank, // lrRank - m_graphType==DotNode::Inheritance, // renderParents - TRUE // backArrows - ); if (format==BITMAP) // run dot to create a bitmap image { QCString dotArgs(maxCmdLine); @@ -1839,7 +2034,7 @@ QCString DotClassGraph::writeGraph(QTextStream &out, DotRunner dotRun(baseName+".dot"); dotRun.addJob(imgExt,imgName); - if (generateImageMap) dotRun.addJob("imap",baseName+".map"); + if (generateImageMap) dotRun.addJob(MAP_CMD,baseName+".map"); if (!dotRun.run()) { QDir::setCurrent(oldDir); @@ -1875,7 +2070,7 @@ QCString DotClassGraph::writeGraph(QTextStream &out, if (Config_getBool("DOT_CLEANUP")) thisDir.remove(baseName+".dot"); } - if (format==BITMAP && generateImageMap) // run dot to create a image map + if (format==BITMAP && generateImageMap) // produce HTML to include the image { QCString mapLabel = convertNameToFile(m_startNode->m_label+"_"+mapName); out << "<p><center><img src=\"" << relPath << baseName << "." @@ -1905,7 +2100,7 @@ QCString DotClassGraph::writeGraph(QTextStream &out, } //thisDir.remove(baseName+".map"); } - else if (format==EPS) // run dot to create a .eps image + else if (format==EPS) // produce tex to include the .eps image { int width,height; if (!readBoundingBoxEPS(baseName+".eps",&width,&height)) @@ -1954,7 +2149,7 @@ void DotClassGraph::writeDEF(QTextStream &t) int DotInclDepGraph::m_curNodeNumber = 0; -void DotInclDepGraph::buildGraph(DotNode *n,FileDef *fd,int distance) +void DotInclDepGraph::buildGraph(DotNode *n,FileDef *fd) { QList<IncludeInfo> *includeFiles = m_inverse ? fd->includedByFileList() : fd->includeFileList(); @@ -1987,49 +2182,107 @@ void DotInclDepGraph::buildGraph(DotNode *n,FileDef *fd,int distance) { n->addChild(bn,0,0,0); bn->addParent(n); - bn->setDistance(distance); } else { QCString tmp_url; if (bfd) tmp_url=doc || src ? bfd->getReference()+"$"+url : QCString(); + QCString tooltip = fd->briefDescriptionAsTooltip(); bn = new DotNode( m_curNodeNumber++, ii->includeName, + tooltip, tmp_url, - distance + 0 //distance ); - if (distance>m_maxDistance) m_maxDistance=distance; n->addChild(bn,0,0,0); bn->addParent(n); m_usedNodes->insert(in,bn); - // we use <=, i.s.o < to cause one more level than intended which is used to - // detect truncated nodes - if (bfd && distance<=m_recDepth) buildGraph(bn,bfd,distance+1); + if (bfd) buildGraph(bn,bfd); + } + } + } + } +} + +void DotInclDepGraph::determineVisibleNodes(QList<DotNode> &queue, int &maxNodes) +{ + while (queue.count()>0 && maxNodes>0) + { + DotNode *n = queue.take(0); + if (!n->isVisible()) // not yet processed + { + n->markAsVisible(); + maxNodes--; + // add direct children + if (n->m_children) + { + QListIterator<DotNode> li(*n->m_children); + DotNode *dn; + for (li.toFirst();(dn=li.current());++li) + { + queue.append(dn); + } + } + } + } +} + +void DotInclDepGraph::determineTruncatedNodes(QList<DotNode> &queue) +{ + while (queue.count()>0) + { + DotNode *n = queue.take(0); + if (n->isVisible() && n->isTruncated()==DotNode::Unknown) + { + bool truncated = FALSE; + if (n->m_children) + { + QListIterator<DotNode> li(*n->m_children); + DotNode *dn; + for (li.toFirst();(dn=li.current());++li) + { + if (!dn->isVisible()) + truncated = TRUE; + else + queue.append(dn); } } + n->markAsTruncated(truncated); } } } -DotInclDepGraph::DotInclDepGraph(FileDef *fd,int maxRecursionDepth,bool inverse) + +DotInclDepGraph::DotInclDepGraph(FileDef *fd,bool inverse) { m_maxDistance = 0; - m_recDepth = maxRecursionDepth; m_inverse = inverse; ASSERT(fd!=0); m_diskName = fd->getFileBase().copy(); QCString tmp_url=fd->getReference()+"$"+fd->getFileBase(); m_startNode = new DotNode(m_curNodeNumber++, fd->docName(), + "", tmp_url.data(), - 0, // distance TRUE // root node ); m_usedNodes = new QDict<DotNode>(1009); m_usedNodes->insert(fd->absFilePath(),m_startNode); - buildGraph(m_startNode,fd,1); + buildGraph(m_startNode,fd); + + int maxNodes = Config_getInt("DOT_GRAPH_MAX_NODES"); + int directChildNodes = 1; + if (m_startNode->m_children!=0) + directChildNodes+=m_startNode->m_children->count(); + if (directChildNodes>maxNodes) maxNodes=directChildNodes; + QList<DotNode> openNodeQueue; + openNodeQueue.append(m_startNode); + determineVisibleNodes(openNodeQueue,maxNodes); + openNodeQueue.clear(); + openNodeQueue.append(m_startNode); + determineTruncatedNodes(openNodeQueue); } DotInclDepGraph::~DotInclDepGraph() @@ -2072,28 +2325,16 @@ QCString DotInclDepGraph::writeGraph(QTextStream &out, if (m_inverse) mapName+="dep"; QCString imgExt = Config_getEnum("DOT_IMAGE_FORMAT"); - QCString md5 = computeMd5Signature(m_startNode, // root - DotNode::CallGraph, // gt - format, // format - TRUE, // lrRank - FALSE, // renderParents - QMIN(m_recDepth,m_maxDistance), // maxDist - FALSE // backArrows - ); - if (checkAndUpdateMd5Signature(baseName,md5) || - !QFileInfo(baseName+".map").exists() - ) + if (updateDotGraph(m_startNode, + DotNode::CallGraph, + baseName, + format, + TRUE, // lrRank + FALSE, // renderParents + m_inverse // backArrows + ) + ) { - findMaximalDotGraph(m_startNode, // root - QMIN(m_recDepth,m_maxDistance), // maxDist - baseName, // baseName - thisDir, // thisDir - DotNode::CallGraph, // gt - format, // format - TRUE, // lrRank - FALSE, // renderParents - m_inverse // backArrows - ); if (format==BITMAP) { // run dot to create a bitmap image @@ -2101,7 +2342,7 @@ QCString DotInclDepGraph::writeGraph(QTextStream &out, QCString imgName=baseName+"."+imgExt; DotRunner dotRun(baseName+".dot"); dotRun.addJob(imgExt,imgName); - if (generateImageMap) dotRun.addJob("imap",baseName+".map"); + if (generateImageMap) dotRun.addJob(MAP_CMD,baseName+".map"); if (!dotRun.run()) { QDir::setCurrent(oldDir); @@ -2197,10 +2438,110 @@ void DotInclDepGraph::writeXML(QTextStream &t) int DotCallGraph::m_curNodeNumber = 0; -DotCallGraph::DotCallGraph(MemberDef *md,int maxRecursionDepth,bool inverse) +void DotCallGraph::buildGraph(DotNode *n,MemberDef *md) +{ + LockingPtr<MemberSDict> refs = m_inverse ? md->getReferencedByMembers() : md->getReferencesMembers(); + if (!refs.isNull()) + { + MemberSDict::Iterator mri(*refs); + MemberDef *rmd; + for (;(rmd=mri.current());++mri) + { + if (rmd->isFunction()) + { + QCString uniqueId; + uniqueId=rmd->getReference()+"$"+ + rmd->getOutputFileBase()+"#"+rmd->anchor(); + DotNode *bn = m_usedNodes->find(uniqueId); + if (bn) // file is already a node in the graph + { + n->addChild(bn,0,0,0); + bn->addParent(n); + } + else + { + QCString name; + if (Config_getBool("HIDE_SCOPE_NAMES")) + { + name = rmd->getOuterScope()==m_scope ? + rmd->name() : rmd->qualifiedName(); + } + else + { + name = rmd->qualifiedName(); + } + QCString tooltip = rmd->briefDescriptionAsTooltip(); + bn = new DotNode( + m_curNodeNumber++, + linkToText(name,FALSE), + tooltip, + uniqueId, + 0 //distance + ); + n->addChild(bn,0,0,0); + bn->addParent(n); + m_usedNodes->insert(uniqueId,bn); + + buildGraph(bn,rmd); + } + } + } + } +} + +void DotCallGraph::determineVisibleNodes(QList<DotNode> &queue, int &maxNodes) +{ + while (queue.count()>0 && maxNodes>0) + { + DotNode *n = queue.take(0); + if (!n->isVisible()) // not yet processed + { + n->markAsVisible(); + maxNodes--; + // add direct children + if (n->m_children) + { + QListIterator<DotNode> li(*n->m_children); + DotNode *dn; + for (li.toFirst();(dn=li.current());++li) + { + queue.append(dn); + } + } + } + } +} + +void DotCallGraph::determineTruncatedNodes(QList<DotNode> &queue) +{ + while (queue.count()>0) + { + DotNode *n = queue.take(0); + if (n->isVisible() && n->isTruncated()==DotNode::Unknown) + { + bool truncated = FALSE; + if (n->m_children) + { + QListIterator<DotNode> li(*n->m_children); + DotNode *dn; + for (li.toFirst();(dn=li.current());++li) + { + if (!dn->isVisible()) + truncated = TRUE; + else + queue.append(dn); + } + } + n->markAsTruncated(truncated); + } + } +} + + + +DotCallGraph::DotCallGraph(MemberDef *md,bool inverse) { m_maxDistance = 0; - m_recDepth = maxRecursionDepth; m_inverse = inverse; m_diskName = md->getOutputFileBase()+"_"+md->anchor(); m_scope = md->getOuterScope(); @@ -2218,13 +2559,25 @@ DotCallGraph::DotCallGraph(MemberDef *md,int maxRecursionDepth,bool inverse) } m_startNode = new DotNode(m_curNodeNumber++, linkToText(name,FALSE), + "", uniqueId.data(), - 0, // distance TRUE // root node ); m_usedNodes = new QDict<DotNode>(1009); m_usedNodes->insert(uniqueId,m_startNode); - buildGraph(m_startNode,md,1); + buildGraph(m_startNode,md); + + int maxNodes = Config_getInt("DOT_GRAPH_MAX_NODES"); + int directChildNodes = 1; + if (m_startNode->m_children!=0) + directChildNodes+=m_startNode->m_children->count(); + if (directChildNodes>maxNodes) maxNodes=directChildNodes; + QList<DotNode> openNodeQueue; + openNodeQueue.append(m_startNode); + determineVisibleNodes(openNodeQueue,maxNodes); + openNodeQueue.clear(); + openNodeQueue.append(m_startNode); + determineTruncatedNodes(openNodeQueue); } DotCallGraph::~DotCallGraph() @@ -2251,28 +2604,16 @@ QCString DotCallGraph::writeGraph(QTextStream &out, GraphOutputFormat format, QCString mapName=baseName; QCString imgExt = Config_getEnum("DOT_IMAGE_FORMAT"); - QCString md5 = computeMd5Signature(m_startNode, // root - DotNode::CallGraph, // gt - format, // format - TRUE, // lrRank - FALSE, // renderParents - QMIN(m_recDepth,m_maxDistance), // maxDist - FALSE // backArrows - ); - if (checkAndUpdateMd5Signature(baseName,md5) || - !QFileInfo(baseName+".map").exists() - ) + if (updateDotGraph(m_startNode, + DotNode::CallGraph, + baseName, + format, + TRUE, // lrRank + FALSE, // renderParents + m_inverse // backArrows + ) + ) { - findMaximalDotGraph(m_startNode, // root - QMIN(m_recDepth,m_maxDistance), // maxDist - baseName, // baseName - thisDir, // thisDir - DotNode::CallGraph, // gt - format, // format - TRUE, // lrRank - FALSE, // renderParents - m_inverse // backArrows - ); if (format==BITMAP) { // run dot to create a bitmap image @@ -2280,7 +2621,7 @@ QCString DotCallGraph::writeGraph(QTextStream &out, GraphOutputFormat format, QCString imgName=baseName+"."+imgExt; DotRunner dotRun(baseName+".dot"); dotRun.addJob(imgExt,imgName); - if (generateImageMap) dotRun.addJob("imap",baseName+".map"); + if (generateImageMap) dotRun.addJob(MAP_CMD,baseName+".map"); if (!dotRun.run()) { QDir::setCurrent(oldDir); @@ -2357,59 +2698,6 @@ QCString DotCallGraph::writeGraph(QTextStream &out, GraphOutputFormat format, return baseName; } -void DotCallGraph::buildGraph(DotNode *n,MemberDef *md,int distance) -{ - LockingPtr<MemberSDict> refs = m_inverse ? md->getReferencedByMembers() : md->getReferencesMembers(); - if (!refs.isNull()) - { - MemberSDict::Iterator mri(*refs); - MemberDef *rmd; - for (;(rmd=mri.current());++mri) - { - if (rmd->isFunction()) - { - QCString uniqueId; - uniqueId=rmd->getReference()+"$"+ - rmd->getOutputFileBase()+"#"+rmd->anchor(); - DotNode *bn = m_usedNodes->find(uniqueId); - if (bn) // file is already a node in the graph - { - n->addChild(bn,0,0,0); - bn->addParent(n); - bn->setDistance(distance); - } - else - { - QCString name; - if (Config_getBool("HIDE_SCOPE_NAMES")) - { - name = rmd->getOuterScope()==m_scope ? - rmd->name() : rmd->qualifiedName(); - } - else - { - name = rmd->qualifiedName(); - } - bn = new DotNode( - m_curNodeNumber++, - linkToText(name,FALSE), - uniqueId, - distance - ); - if (distance>m_maxDistance) m_maxDistance=distance; - n->addChild(bn,0,0,0); - bn->addParent(n); - m_usedNodes->insert(uniqueId,bn); - - // we use <=, i.s.o < to cause one more level than intended which is used to - // detect truncated nodes - if (distance<=m_recDepth) buildGraph(bn,rmd,distance+1); - } - } - } - } -} - bool DotCallGraph::isTrivial() const { return m_startNode->m_children==0; @@ -2464,7 +2752,7 @@ QCString DotDirDeps::writeGraph(QTextStream &out, QCString imgName=baseName+"."+imgExt; DotRunner dotRun(baseName+".dot"); dotRun.addJob(imgExt,imgName); - if (generateImageMap) dotRun.addJob("imap",baseName+".map"); + if (generateImageMap) dotRun.addJob(MAP_CMD,baseName+".map"); if (!dotRun.run()) { QDir::setCurrent(oldDir); @@ -2609,6 +2897,12 @@ void generateGraphLegend(const char *path) QDir::setCurrent(oldDir); } +#undef PUTENV +#if defined(_WIN32) && (!defined(__BORLANDC__) || (__BORLANDC__ < 0x0550)) +#define PUTENV _putenv +#else +#define PUTENV putenv +#endif void writeDotGraphFromFile(const char *inFile,const char *outDir, const char *outFile,GraphOutputFormat format) @@ -2627,15 +2921,19 @@ void writeDotGraphFromFile(const char *inFile,const char *outDir, QDir::setCurrent(outDir); //printf("Going to dir %s\n",QDir::currentDirPath().data()); - //{ // copy input file to output dir. - // QFile inf(inFile,IO_ReadOnly); - // QFileInfo infinfo(inf); - // uint s = infinfo.size(); - // QByteArray a(s); - // inf.readBlock(a.data(),s); - // QFile outf(outDir,IO_WriteOnly); - // outf.writeBlock(a.data(),s); - //} + QCString env = getenv("DOTFONTPATH"); + if (env==".") // this path was set by doxygen, so dot can find the FreeSans.ttf font, + // for user defined graphs we use the default search path built into dot, + // unless the user has set the DOTFONTPATH as well. + { + // temporarily remove the DOTFONTPATH environment variable + // so dot will use the built-in search path. +#ifdef _WIN32 + SetEnvironmentVariable("DOTFONTPATH", 0) +#else + unsetenv("DOTFONTPATH"); +#endif + } QCString imgExt = Config_getEnum("DOT_IMAGE_FORMAT"); QCString imgName = (QCString)outFile+"."+imgExt; @@ -2648,7 +2946,7 @@ void writeDotGraphFromFile(const char *inFile,const char *outDir, if (!dotRun.run()) { QDir::setCurrent(oldDir); - return; + goto error; } // Added by Nils Strom if ( (format==EPS) && (Config_getBool("USE_PDFLATEX")) ) @@ -2664,6 +2962,17 @@ void writeDotGraphFromFile(const char *inFile,const char *outDir, if (format==BITMAP) checkDotResult(imgName); + if (env==".") + { + // restore the DOTFONTPATH variable again +#ifdef _WIN32 + SetEnvironmentVariable("DOTFONTPATH", env) +#else + setenv("DOTFONTPATH",env,1); +#endif + } + +error: QDir::setCurrent(oldDir); } @@ -2687,7 +2996,7 @@ QString getDotImageMapFromFile(const QString& inFile, const QString& outDir, //printf("Going to dir %s\n",QDir::currentDirPath().data()); DotRunner dotRun(inFile); - dotRun.addJob("imap",outFile); + dotRun.addJob(MAP_CMD,outFile); if (!dotRun.run()) { QDir::setCurrent(oldDir); @@ -2712,13 +3021,14 @@ DotGroupCollaboration::DotGroupCollaboration(GroupDef* gd) m_curNodeId = 0; QCString tmp_url = gd->getReference()+"$"+gd->getOutputFileBase(); m_usedNodes = new QDict<DotNode>(1009); - m_rootNode = new DotNode(m_curNodeId++, gd->groupTitle(), tmp_url, 0, TRUE ); + m_rootNode = new DotNode(m_curNodeId++, gd->groupTitle(), "", tmp_url, TRUE ); + m_rootNode->markAsVisible(); m_usedNodes->insert(gd->name(), m_rootNode ); m_edges.setAutoDelete(TRUE); m_diskName = gd->getOutputFileBase(); - buildGraph( gd, 0 ); + buildGraph( gd ); } DotGroupCollaboration::~DotGroupCollaboration() @@ -2726,7 +3036,7 @@ DotGroupCollaboration::~DotGroupCollaboration() delete m_usedNodes; } -void DotGroupCollaboration::buildGraph(GroupDef* gd,int) +void DotGroupCollaboration::buildGraph(GroupDef* gd) { QCString tmp_url; //=========================== @@ -2744,7 +3054,9 @@ void DotGroupCollaboration::buildGraph(GroupDef* gd,int) if ( !nnode ) { // add node tmp_url = d->getReference()+"$"+d->getOutputFileBase(); - nnode = new DotNode(m_curNodeId++, d->groupTitle(), tmp_url ); + QCString tooltip = d->briefDescriptionAsTooltip(); + nnode = new DotNode(m_curNodeId++, d->groupTitle(), tooltip, tmp_url ); + nnode->markAsVisible(); m_usedNodes->insert(d->name(), nnode ); } tmp_url = ""; @@ -2763,7 +3075,9 @@ void DotGroupCollaboration::buildGraph(GroupDef* gd,int) if ( !nnode ) { // add node tmp_url = def->getReference()+"$"+def->getOutputFileBase(); - nnode = new DotNode(m_curNodeId++, def->groupTitle(), tmp_url ); + QCString tooltip = def->briefDescriptionAsTooltip(); + nnode = new DotNode(m_curNodeId++, def->groupTitle(), tooltip, tmp_url ); + nnode->markAsVisible(); m_usedNodes->insert(def->name(), nnode ); } tmp_url = ""; @@ -2899,7 +3213,9 @@ void DotGroupCollaboration::addCollaborationMember( if ( nnode==0 ) { // add node tmp_str = d->getReference()+"$"+d->getOutputFileBase(); - nnode = new DotNode(m_curNodeId++, d->groupTitle(), tmp_str ); + QCString tooltip = d->briefDescriptionAsTooltip(); + nnode = new DotNode(m_curNodeId++, d->groupTitle(), tooltip, tmp_str ); + nnode->markAsVisible(); m_usedNodes->insert(d->name(), nnode ); } tmp_str = def->qualifiedName(); @@ -2941,7 +3257,7 @@ QCString DotGroupCollaboration::writeGraph( QTextStream &t, GraphOutputFormat fo // write other nodes. for (dni.toFirst();(pn=dni.current());++dni) { - pn->write(tdot,DotNode::Inheritance,format,TRUE,FALSE,1,FALSE,FALSE); + pn->write(tdot,DotNode::Inheritance,format,TRUE,FALSE,FALSE,FALSE); } // write edges @@ -2965,7 +3281,7 @@ QCString DotGroupCollaboration::writeGraph( QTextStream &t, GraphOutputFormat fo DotRunner dotRun(baseName+".dot"); dotRun.addJob(imgExt,imgName); - if (writeImageMap) dotRun.addJob("imap",mapName); + if (writeImageMap) dotRun.addJob(MAP_CMD,mapName); if (!dotRun.run()) { QDir::setCurrent(oldDir); |