My Project
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
Classes | Macros | Functions | Variables
dot.cpp File Reference
#include <stdlib.h>
#include <qdir.h>
#include <qfile.h>
#include <qqueue.h>
#include <qthread.h>
#include <qmutex.h>
#include <qwaitcondition.h>
#include "dot.h"
#include "doxygen.h"
#include "message.h"
#include "util.h"
#include "config.h"
#include "language.h"
#include "defargs.h"
#include "docparser.h"
#include "debug.h"
#include "pagedef.h"
#include "portable.h"
#include "dirdef.h"
#include "vhdldocgen.h"
#include "ftextstream.h"
#include "md5.h"
#include "memberlist.h"
#include "groupdef.h"
#include "classlist.h"
#include "filename.h"
#include "namespacedef.h"
#include "memberdef.h"
#include "membergroup.h"

Go to the source code of this file.

Classes

struct  EdgeProperties
 

Macros

#define MAP_CMD   "cmapx"
 
#define FONTNAME   getDotFontName()
 
#define FONTSIZE   getDotFontSize()
 

Functions

static QCString getDotFontName ()
 
static int getDotFontSize ()
 
static void writeGraphHeader (FTextStream &t, const QCString &title=QCString())
 
static void writeGraphFooter (FTextStream &t)
 
static QCString replaceRef (const QCString &buf, const QCString relPath, bool urlOnly, const QCString &context, const QCString &target=QCString())
 
static bool convertMapFile (FTextStream &t, const char *mapName, const QCString relPath, bool urlOnly=FALSE, const QCString &context=QCString())
 
static void setDotFontPath (const char *path)
 
static void unsetDotFontPath ()
 
static bool readBoundingBox (const char *fileName, int *width, int *height, bool isEps)
 
static bool writeVecGfxFigure (FTextStream &out, const QCString &baseName, const QCString &figureName)
 
static bool readSVGSize (const QCString &fileName, int *width, int *height)
 
static void writeSVGNotSupported (FTextStream &out)
 
static bool writeSVGFigureLink (FTextStream &out, const QCString &relPath, const QCString &baseName, const QCString &absImgName)
 
static void checkDotResult (const char *imgExt, const char *imgName)
 
static bool insertMapFile (FTextStream &out, const QCString &mapFile, const QCString &relPath, const QCString &mapLabel)
 
static void removeDotGraph (const QCString &dotName)
 
static bool checkAndUpdateMd5Signature (const QCString &baseName, const QCString &md5)
 
static bool checkDeliverables (const QCString &file1, const QCString &file2=QCString())
 
static void deleteNodes (DotNode *node, SDict< DotNode > *skipNodes=0)
 
static QCString convertLabel (const QCString &l)
 
static QCString escapeTooltip (const QCString &tooltip)
 
static void writeBoxMemberList (FTextStream &t, char prot, MemberList *ml, ClassDef *scope, bool isStatic=FALSE, const QDict< void > *skipNames=0)
 
static QCString stripProtectionPrefix (const QCString &s)
 
QCString computeMd5Signature (DotNode *root, DotNode::GraphType gt, GraphOutputFormat format, bool lrRank, bool renderParents, bool backArrows, const QCString &title, QCString &graphStr)
 
static bool updateDotGraph (DotNode *root, DotNode::GraphType gt, const QCString &baseName, GraphOutputFormat format, bool lrRank, bool renderParents, bool backArrows, const QCString &title=QCString())
 
static void writeDotDirDepGraph (FTextStream &t, DirDef *dd, bool linkRelations)
 
void generateGraphLegend (const char *path)
 
void writeDotGraphFromFile (const char *inFile, const char *outDir, const char *outFile, GraphOutputFormat format)
 
void writeDotImageMapFromFile (FTextStream &t, const QCString &inFile, const QCString &outDir, const QCString &relPath, const QCString &baseName, const QCString &context, int graphId)
 
void resetDotNodeNumbering ()
 

Variables

static const char svgZoomHeader []
 
static const char svgZoomFooter []
 
static const char * normalEdgeColorMap []
 
static const char * normalArrowStyleMap []
 
static const char * normalEdgeStyleMap []
 
static const char * umlEdgeColorMap []
 
static const char * umlArrowStyleMap []
 
static const char * umlEdgeStyleMap []
 
static EdgeProperties normalEdgeProps
 
static EdgeProperties umlEdgeProps
 
static QCString g_dotFontPath
 

Macro Definition Documentation

#define FONTNAME   getDotFontName()
#define FONTSIZE   getDotFontSize()
#define MAP_CMD   "cmapx"

Function Documentation

static bool checkAndUpdateMd5Signature ( const QCString &  baseName,
const QCString &  md5 
)
static

Checks if a file "baseName".md5 exists. If so the contents are compared with md5. If equal FALSE is returned. If the .md5 file does not exist or its contents are not equal to md5, a new .md5 is generated with the md5 string as contents.

Definition at line 689 of file dot.cpp.

Referenced by DotGfxHierarchyTable::createGraph(), generateGraphLegend(), updateDotGraph(), DotDirDeps::writeGraph(), and DotGroupCollaboration::writeGraph().

{
QFile f(baseName+".md5");
if (f.open(IO_ReadOnly))
{
// read checksum
QCString md5stored(33);
int bytesRead=f.readBlock(md5stored.rawData(),32);
md5stored[32]='\0';
// compare checksum
if (bytesRead==32 && md5==md5stored)
{
// bail out if equal
return FALSE;
}
}
f.close();
// create checksum file
if (f.open(IO_WriteOnly))
{
f.writeBlock(md5.data(),32);
f.close();
}
return TRUE;
}
static bool checkDeliverables ( const QCString &  file1,
const QCString &  file2 = QCString() 
)
static

Definition at line 716 of file dot.cpp.

Referenced by DotGfxHierarchyTable::createGraph(), generateGraphLegend(), DotClassGraph::writeGraph(), DotInclDepGraph::writeGraph(), DotCallGraph::writeGraph(), DotDirDeps::writeGraph(), and DotGroupCollaboration::writeGraph().

{
bool file1Ok = TRUE;
bool file2Ok = TRUE;
if (!file1.isEmpty())
{
QFileInfo fi(file1);
file1Ok = (fi.exists() && fi.size()>0);
}
if (!file2.isEmpty())
{
QFileInfo fi(file2);
file2Ok = (fi.exists() && fi.size()>0);
}
return file1Ok && file2Ok;
}
static void checkDotResult ( const char *  imgExt,
const char *  imgName 
)
static

Definition at line 620 of file dot.cpp.

References err(), and portable_fopen().

Referenced by DotRunner::run(), and writeDotGraphFromFile().

{
if (qstrcmp(imgExt,"png")==0)
{
FILE *f = portable_fopen(imgName,"rb");
if (f)
{
char data[4];
if (fread(data,1,4,f)==4)
{
if (!(data[1]=='P' && data[2]=='N' && data[3]=='G'))
{
err("Image `%s' produced by dot is not a valid PNG!\n"
"You should either select a different format "
"(DOT_IMAGE_FORMAT in the config file) or install a more "
"recent version of graphviz (1.7+)\n",imgName
);
}
}
else
{
err("Could not read image `%s' generated by dot!\n",imgName);
}
fclose(f);
}
else
{
err("Could not open image `%s' generated by dot!\n",imgName);
}
}
}
QCString computeMd5Signature ( DotNode root,
DotNode::GraphType  gt,
GraphOutputFormat  format,
bool  lrRank,
bool  renderParents,
bool  backArrows,
const QCString &  title,
QCString &  graphStr 
)

Computes a 16 byte md5 checksum for a given dot graph. The md5 checksum is returned as a 32 character ASCII string.

Definition at line 2990 of file dot.cpp.

References DotNode::CallGraph, DotNode::clearWriteFlag(), DotNode::Dependency, endl(), DotNode::isVisible(), DotNode::m_children, DotNode::m_edgeInfo, DotNode::m_parents, DotNode::write(), DotNode::writeArrow(), writeGraphFooter(), and writeGraphHeader().

Referenced by updateDotGraph().

{
//printf("computeMd5Signature\n");
QGString buf;
FTextStream md5stream(&buf);
writeGraphHeader(md5stream,title);
if (lrRank)
{
md5stream << " rankdir=\"LR\";" << endl;
}
root->clearWriteFlag();
root->write(md5stream,
gt,
format,
TRUE,
backArrows);
if (renderParents && root->m_parents)
{
QListIterator<DotNode> dnli(*root->m_parents);
DotNode *pn;
for (dnli.toFirst();(pn=dnli.current());++dnli)
{
if (pn->isVisible())
{
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?
);
}
pn->write(md5stream, // stream
gt, // graph type
format, // output format
TRUE, // topDown?
FALSE, // toChildren?
backArrows // backward pointing arrows?
);
}
}
writeGraphFooter(md5stream);
uchar md5_sig[16];
QCString sigStr(33);
MD5Buffer((const unsigned char *)buf.data(),buf.length(),md5_sig);
MD5SigToString(md5_sig,sigStr.rawData(),33);
graphStr=buf.data();
//printf("md5: %s | file: %s\n",sigStr,baseName.data());
return sigStr;
}
static QCString convertLabel ( const QCString &  l)
static

Definition at line 1522 of file dot.cpp.

Referenced by DotGroupCollaboration::Edge::write(), DotNode::writeArrow(), DotNode::writeBox(), and writeBoxMemberList().

{
QCString result;
QCString bBefore("\\_/<({[: =-+@%#~?$"); // break before character set
QCString bAfter(">]),:;|"); // break after character set
const char *p=l.data();
if (p==0) return result;
char c,pc=0;
char cs[2];
cs[1]=0;
int len=l.length();
int charsLeft=len;
int sinceLast=0;
int foldLen=17; // ideal text length
while ((c=*p++))
{
QCString replacement;
switch(c)
{
case '\\': replacement="\\\\"; break;
case '\n': replacement="\\n"; break;
case '<': replacement="\\<"; break;
case '>': replacement="\\>"; break;
case '|': replacement="\\|"; break;
case '{': replacement="\\{"; break;
case '}': replacement="\\}"; break;
case '"': replacement="\\\""; break;
default: cs[0]=c; replacement=cs; break;
}
// Some heuristics to insert newlines to prevent too long
// boxes and at the same time prevent ugly breaks
if (c=='\n')
{
result+=replacement;
foldLen = (3*foldLen+sinceLast+2)/4;
sinceLast=1;
}
else if ((pc!=':' || c!=':') && charsLeft>foldLen/3 && sinceLast>foldLen && bBefore.contains(c))
{
result+="\\l";
result+=replacement;
foldLen = (foldLen+sinceLast+1)/2;
sinceLast=1;
}
else if (charsLeft>1+foldLen/4 && sinceLast>foldLen+foldLen/3 &&
!isupper(c) && isupper(*p))
{
result+=replacement;
result+="\\l";
foldLen = (foldLen+sinceLast+1)/2;
sinceLast=0;
}
else if (charsLeft>foldLen/3 && sinceLast>foldLen && bAfter.contains(c) && (c!=':' || *p!=':'))
{
result+=replacement;
result+="\\l";
foldLen = (foldLen+sinceLast+1)/2;
sinceLast=0;
}
else
{
result+=replacement;
sinceLast++;
}
charsLeft--;
pc=c;
}
return result;
}
static bool convertMapFile ( FTextStream t,
const char *  mapName,
const QCString  relPath,
bool  urlOnly = FALSE,
const QCString &  context = QCString() 
)
static

converts the rectangles in a client site image map into a stream

Parameters
tthe stream to which the result is written.
mapNamethe name of the map file.
relPaththe relative path to the root of the output directory (used in case CREATE_SUBDIRS is enabled).
urlOnlyif FALSE the url field in the map contains an external references followed by a $ and then the URL.
contextthe context (file, class, or namespace) in which the map file was found
Returns
TRUE if successful.

Definition at line 370 of file dot.cpp.

References err(), and replaceRef().

Referenced by insertMapFile(), DotFilePatcher::run(), and writeDotImageMapFromFile().

{
QFile f(mapName);
if (!f.open(IO_ReadOnly))
{
err("problems opening map file %s for inclusion in the docs!\n"
"If you installed Graphviz/dot after a previous failing run, \n"
"try deleting the output directory and rerun doxygen.\n",mapName);
return FALSE;
}
const int maxLineLen=10240;
while (!f.atEnd()) // foreach line
{
QCString buf(maxLineLen);
int numBytes = f.readLine(buf.rawData(),maxLineLen);
if (numBytes>0)
{
buf.resize(numBytes+1);
if (buf.left(5)=="<area")
{
t << replaceRef(buf,relPath,urlOnly,context);
}
}
}
return TRUE;
}
static void deleteNodes ( DotNode node,
SDict< DotNode > *  skipNodes = 0 
)
static

helper function that deletes all nodes in a connected graph, given one of the graph's nodes

Definition at line 1401 of file dot.cpp.

References DotNode::deleteNode().

Referenced by DotCallGraph::~DotCallGraph(), DotClassGraph::~DotClassGraph(), and DotInclDepGraph::~DotInclDepGraph().

{
//printf("deleteNodes skipNodes=%p\n",skipNodes);
static DotNodeList deletedNodes;
deletedNodes.setAutoDelete(TRUE);
node->deleteNode(deletedNodes,skipNodes); // collect nodes to be deleted.
deletedNodes.clear(); // actually remove the nodes.
}
static QCString escapeTooltip ( const QCString &  tooltip)
static

Definition at line 1592 of file dot.cpp.

Referenced by DotNode::writeBox().

{
QCString result;
const char *p=tooltip.data();
if (p==0) return result;
char c;
while ((c=*p++))
{
switch(c)
{
case '"': result+="\\\""; break;
default: result+=c; break;
}
}
return result;
}
void generateGraphLegend ( const char *  path)

Generated a graphs legend page

Definition at line 4072 of file dot.cpp.

References IndexList::addImageFile(), DotRunner::addJob(), DotManager::addRun(), DotManager::addSVGObject(), checkAndUpdateMd5Signature(), checkDeliverables(), Config_getEnum, Config_getString, err(), FONTNAME, FONTSIZE, getDotImageExtension(), Doxygen::htmlFileExtension, Doxygen::indexList, DotManager::instance(), removeDotGraph(), theTranslator, Translator::trLegendTitle(), writeGraphFooter(), and writeGraphHeader().

Referenced by writeGraphInfo().

{
QDir d(path);
// store the original directory
if (!d.exists())
{
err("Output dir %s does not exist!\n",path); exit(1);
}
QGString theGraph;
FTextStream md5stream(&theGraph);
md5stream << " Node9 [shape=\"box\",label=\"Inherited\",fontsize=\"" << FONTSIZE << "\",height=0.2,width=0.4,fontname=\"" << FONTNAME << "\",fillcolor=\"grey75\",style=\"filled\" fontcolor=\"black\"];\n";
md5stream << " Node10 -> Node9 [dir=\"back\",color=\"midnightblue\",fontsize=\"" << FONTSIZE << "\",style=\"solid\",fontname=\"" << FONTNAME << "\"];\n";
md5stream << " Node10 [shape=\"box\",label=\"PublicBase\",fontsize=\"" << FONTSIZE << "\",height=0.2,width=0.4,fontname=\"" << FONTNAME << "\",color=\"black\",URL=\"$classPublicBase" << Doxygen::htmlFileExtension << "\"];\n";
md5stream << " Node11 -> Node10 [dir=\"back\",color=\"midnightblue\",fontsize=\"" << FONTSIZE << "\",style=\"solid\",fontname=\"" << FONTNAME << "\"];\n";
md5stream << " Node11 [shape=\"box\",label=\"Truncated\",fontsize=\"" << FONTSIZE << "\",height=0.2,width=0.4,fontname=\"" << FONTNAME << "\",color=\"red\",URL=\"$classTruncated" << Doxygen::htmlFileExtension << "\"];\n";
md5stream << " Node13 -> Node9 [dir=\"back\",color=\"darkgreen\",fontsize=\"" << FONTSIZE << "\",style=\"solid\",fontname=\"" << FONTNAME << "\"];\n";
md5stream << " Node13 [shape=\"box\",label=\"ProtectedBase\",fontsize=\"" << FONTSIZE << "\",height=0.2,width=0.4,fontname=\"" << FONTNAME << "\",color=\"black\",URL=\"$classProtectedBase" << Doxygen::htmlFileExtension << "\"];\n";
md5stream << " Node14 -> Node9 [dir=\"back\",color=\"firebrick4\",fontsize=\"" << FONTSIZE << "\",style=\"solid\",fontname=\"" << FONTNAME << "\"];\n";
md5stream << " Node14 [shape=\"box\",label=\"PrivateBase\",fontsize=\"" << FONTSIZE << "\",height=0.2,width=0.4,fontname=\"" << FONTNAME << "\",color=\"black\",URL=\"$classPrivateBase" << Doxygen::htmlFileExtension << "\"];\n";
md5stream << " Node15 -> Node9 [dir=\"back\",color=\"midnightblue\",fontsize=\"" << FONTSIZE << "\",style=\"solid\",fontname=\"" << FONTNAME << "\"];\n";
md5stream << " Node15 [shape=\"box\",label=\"Undocumented\",fontsize=\"" << FONTSIZE << "\",height=0.2,width=0.4,fontname=\"" << FONTNAME << "\",color=\"grey75\"];\n";
md5stream << " Node16 -> Node9 [dir=\"back\",color=\"midnightblue\",fontsize=\"" << FONTSIZE << "\",style=\"solid\",fontname=\"" << FONTNAME << "\"];\n";
md5stream << " Node16 [shape=\"box\",label=\"Templ< int >\",fontsize=\"" << FONTSIZE << "\",height=0.2,width=0.4,fontname=\"" << FONTNAME << "\",color=\"black\",URL=\"$classTempl" << Doxygen::htmlFileExtension << "\"];\n";
md5stream << " Node17 -> Node16 [dir=\"back\",color=\"orange\",fontsize=\"" << FONTSIZE << "\",style=\"dashed\",label=\"< int >\",fontname=\"" << FONTNAME << "\"];\n";
md5stream << " Node17 [shape=\"box\",label=\"Templ< T >\",fontsize=\"" << FONTSIZE << "\",height=0.2,width=0.4,fontname=\"" << FONTNAME << "\",color=\"black\",URL=\"$classTempl" << Doxygen::htmlFileExtension << "\"];\n";
md5stream << " Node18 -> Node9 [dir=\"back\",color=\"darkorchid3\",fontsize=\"" << FONTSIZE << "\",style=\"dashed\",label=\"m_usedClass\",fontname=\"" << FONTNAME << "\"];\n";
md5stream << " Node18 [shape=\"box\",label=\"Used\",fontsize=\"" << FONTSIZE << "\",height=0.2,width=0.4,fontname=\"" << FONTNAME << "\",color=\"black\",URL=\"$classUsed" << Doxygen::htmlFileExtension << "\"];\n";
writeGraphFooter(md5stream);
uchar md5_sig[16];
QCString sigStr(33);
MD5Buffer((const unsigned char *)theGraph.data(),theGraph.length(),md5_sig);
MD5SigToString(md5_sig,sigStr.rawData(),33);
QCString absBaseName = (QCString)path+"/graph_legend";
QCString absDotName = absBaseName+".dot";
QCString imgExt = getDotImageExtension();
QCString imgFmt = Config_getEnum(DOT_IMAGE_FORMAT);
QCString imgName = "graph_legend."+imgExt;
QCString absImgName = absBaseName+"."+imgExt;
if (checkAndUpdateMd5Signature(absBaseName,sigStr) ||
!checkDeliverables(absImgName))
{
QFile dotFile(absDotName);
if (!dotFile.open(IO_WriteOnly))
{
err("Could not open file %s for writing\n",dotFile.name().data());
return;
}
FTextStream dotText(&dotFile);
dotText << theGraph;
dotFile.close();
// run dot to generate the a bitmap image from the graph
DotRunner *dotRun = new DotRunner(absDotName,d.absPath().data(),TRUE,absImgName);
dotRun->addJob(imgFmt,absImgName);
}
else
{
removeDotGraph(absDotName);
}
if (imgExt=="svg")
{
absBaseName+Config_getString(HTML_FILE_EXTENSION),
"graph_legend",
absImgName,QCString());
}
}
static QCString getDotFontName ( )
static

Definition at line 233 of file dot.cpp.

References Config_getString.

{
static QCString dotFontName = Config_getString(DOT_FONTNAME);
if (dotFontName.isEmpty())
{
//dotFontName="FreeSans.ttf";
dotFontName="Helvetica";
}
return dotFontName;
}
static int getDotFontSize ( )
static

Definition at line 244 of file dot.cpp.

References Config_getInt.

{
static int dotFontSize = Config_getInt(DOT_FONTSIZE);
if (dotFontSize<4) dotFontSize=4;
return dotFontSize;
}
static bool insertMapFile ( FTextStream out,
const QCString &  mapFile,
const QCString &  relPath,
const QCString &  mapLabel 
)
static

Definition at line 652 of file dot.cpp.

References convertMapFile(), and endl().

Referenced by DotGfxHierarchyTable::createGraph(), DotClassGraph::writeGraph(), DotInclDepGraph::writeGraph(), DotCallGraph::writeGraph(), DotDirDeps::writeGraph(), and DotGroupCollaboration::writeGraph().

{
QFileInfo fi(mapFile);
if (fi.exists() && fi.size()>0) // reuse existing map file
{
QGString tmpstr;
FTextStream tmpout(&tmpstr);
convertMapFile(tmpout,mapFile,relPath);
if (!tmpstr.isEmpty())
{
out << "<map name=\"" << mapLabel << "\" id=\"" << mapLabel << "\">" << endl;
out << tmpstr;
out << "</map>" << endl;
}
return TRUE;
}
return FALSE; // no map file yet, need to generate it
}
static bool readBoundingBox ( const char *  fileName,
int *  width,
int *  height,
bool  isEps 
)
static

Definition at line 437 of file dot.cpp.

References err().

Referenced by writeVecGfxFigure().

{
QCString bb = isEps ? QCString("%%PageBoundingBox:") : QCString("/MediaBox [");
QFile f(fileName);
if (!f.open(IO_ReadOnly|IO_Raw))
{
//printf("readBoundingBox: could not open %s\n",fileName);
return FALSE;
}
const int maxLineLen=1024;
char buf[maxLineLen];
while (!f.atEnd())
{
int numBytes = f.readLine(buf,maxLineLen-1); // read line
if (numBytes>0)
{
buf[numBytes]='\0';
const char *p = strstr(buf,bb);
if (p) // found PageBoundingBox or /MediaBox string
{
int x,y;
if (sscanf(p+bb.length(),"%d %d %d %d",&x,&y,width,height)!=4)
{
//printf("readBoundingBox sscanf fail\n");
return FALSE;
}
return TRUE;
}
}
else // read error!
{
//printf("Read error %d!\n",numBytes);
return FALSE;
}
}
err("Failed to extract bounding box from generated diagram file %s\n",fileName);
return FALSE;
}
static bool readSVGSize ( const QCString &  fileName,
int *  width,
int *  height 
)
static

Definition at line 530 of file dot.cpp.

Referenced by writeSVGFigureLink().

{
bool found=FALSE;
QFile f(fileName);
if (!f.open(IO_ReadOnly))
{
return FALSE;
}
const int maxLineLen=4096;
char buf[maxLineLen];
while (!f.atEnd() && !found)
{
int numBytes = f.readLine(buf,maxLineLen-1); // read line
if (numBytes>0)
{
buf[numBytes]='\0';
if (qstrncmp(buf,"<!--zoomable ",13)==0)
{
*width=-1;
*height=-1;
sscanf(buf,"<!--zoomable %d",height);
//printf("Found zoomable for %s!\n",fileName.data());
found=TRUE;
}
else if (sscanf(buf,"<svg width=\"%dpt\" height=\"%dpt\"",width,height)==2)
{
//printf("Found fixed size %dx%d for %s!\n",*width,*height,fileName.data());
found=TRUE;
}
}
else // read error!
{
//printf("Read error %d!\n",numBytes);
return FALSE;
}
}
return TRUE;
}
static void removeDotGraph ( const QCString &  dotName)
static

Definition at line 672 of file dot.cpp.

References Config_getBool.

Referenced by DotGfxHierarchyTable::createGraph(), generateGraphLegend(), DotClassGraph::writeGraph(), DotInclDepGraph::writeGraph(), DotCallGraph::writeGraph(), DotDirDeps::writeGraph(), and DotGroupCollaboration::writeGraph().

{
static bool dotCleanUp = Config_getBool(DOT_CLEANUP);
if (dotCleanUp)
{
QDir d;
d.remove(dotName);
}
}
static QCString replaceRef ( const QCString &  buf,
const QCString  relPath,
bool  urlOnly,
const QCString &  context,
const QCString &  target = QCString() 
)
static

Definition at line 286 of file dot.cpp.

References DocRef::anchor(), externalLinkTarget(), externalRef(), DocRef::file(), Doxygen::htmlFileExtension, and DocRef::ref().

Referenced by convertMapFile(), and DotFilePatcher::run().

{
// search for href="...", store ... part in link
QCString href = "href";
//bool isXLink=FALSE;
int len = 6;
int indexS = buf.find("href=\""), indexE;
if (indexS>5 && buf.find("xlink:href=\"")!=-1) // XLink href (for SVG)
{
indexS-=6;
len+=6;
href.prepend("xlink:");
//isXLink=TRUE;
}
if (indexS>=0 && (indexE=buf.find('"',indexS+len))!=-1)
{
QCString link = buf.mid(indexS+len,indexE-indexS-len);
QCString result;
if (urlOnly) // for user defined dot graphs
{
if (link.left(5)=="\\ref " || link.left(5)=="@ref ") // \ref url
{
result=href+"=\"";
// fake ref node to resolve the url
DocRef *df = new DocRef( (DocNode*) 0, link.mid(5), context );
result+=externalRef(relPath,df->ref(),TRUE);
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 = externalLinkTarget() + externalRef(relPath,ref,FALSE);
}
result+= href+"=\"";
result+=externalRef(relPath,ref,TRUE);
result+= url + "\"";
}
else // should not happen, but handle properly anyway
{
result = href+"=\"" + link + "\"";
}
}
if (!target.isEmpty())
{
result+=" target=\""+target+"\"";
}
QCString leftPart = buf.left(indexS);
QCString rightPart = buf.mid(indexE+1);
return leftPart + result + rightPart;
}
else
{
return buf;
}
}
void resetDotNodeNumbering ( )
static void setDotFontPath ( const char *  path)
static

Definition at line 402 of file dot.cpp.

References Config_getString, portable_getenv(), portable_pathListSeparator(), portable_setenv(), and portable_unsetenv().

Referenced by DotManager::run().

{
ASSERT(g_dotFontPath.isEmpty());
g_dotFontPath = portable_getenv("DOTFONTPATH");
QCString newFontPath = Config_getString(DOT_FONTPATH);
QCString spath = path;
if (!newFontPath.isEmpty() && !spath.isEmpty())
{
newFontPath.prepend(spath+portable_pathListSeparator());
}
else if (newFontPath.isEmpty() && !spath.isEmpty())
{
newFontPath=path;
}
else
{
portable_unsetenv("DOTFONTPATH");
return;
}
portable_setenv("DOTFONTPATH",newFontPath);
}
static QCString stripProtectionPrefix ( const QCString &  s)
static

Definition at line 1668 of file dot.cpp.

Referenced by DotNode::writeBox().

{
if (!s.isEmpty() && (s[0]=='-' || s[0]=='+' || s[0]=='~' || s[0]=='#'))
{
return s.mid(1);
}
else
{
return s;
}
}
static void unsetDotFontPath ( )
static

Definition at line 424 of file dot.cpp.

References portable_setenv(), and portable_unsetenv().

Referenced by DotManager::run().

{
if (g_dotFontPath.isEmpty())
{
portable_unsetenv("DOTFONTPATH");
}
else
{
}
}
static bool updateDotGraph ( DotNode root,
DotNode::GraphType  gt,
const QCString &  baseName,
GraphOutputFormat  format,
bool  lrRank,
bool  renderParents,
bool  backArrows,
const QCString &  title = QCString() 
)
static

Definition at line 3051 of file dot.cpp.

References checkAndUpdateMd5Signature(), and computeMd5Signature().

Referenced by DotClassGraph::writeGraph(), DotInclDepGraph::writeGraph(), and DotCallGraph::writeGraph().

{
QCString theGraph;
// TODO: write graph to theGraph, then compute md5 checksum
QCString md5 = computeMd5Signature(
root,gt,format,lrRank,renderParents,
backArrows,title,theGraph);
QFile f(baseName+".dot");
if (f.open(IO_WriteOnly))
{
FTextStream t(&f);
t << theGraph;
}
return checkAndUpdateMd5Signature(baseName,md5); // graph needs to be regenerated
}
static void writeBoxMemberList ( FTextStream t,
char  prot,
MemberList ml,
ClassDef scope,
bool  isStatic = FALSE,
const QDict< void > *  skipNames = 0 
)
static

Definition at line 1609 of file dot.cpp.

References Config_getInt, convertLabel(), MemberDef::getClassDef(), MemberList::getMemberGroupList(), MemberDef::isFunction(), MemberDef::isObjCMethod(), MemberDef::isSignal(), MemberDef::isSlot(), MemberGroup::members(), Definition::name(), theTranslator, and Translator::trAndMore().

Referenced by DotNode::writeBox().

{
(void)isStatic;
if (ml)
{
MemberListIterator mlia(*ml);
MemberDef *mma;
int totalCount=0;
for (mlia.toFirst();(mma = mlia.current());++mlia)
{
if (mma->getClassDef()==scope &&
(skipNames==0 || skipNames->find(mma->name())==0))
{
totalCount++;
}
}
int count=0;
for (mlia.toFirst();(mma = mlia.current());++mlia)
{
if (mma->getClassDef() == scope &&
(skipNames==0 || skipNames->find(mma->name())==0))
{
static int limit = Config_getInt(UML_LIMIT_NUM_FIELDS);
if (limit>0 && (totalCount>limit*3/2 && count>=limit))
{
t << theTranslator->trAndMore(QCString().sprintf("%d",totalCount-count)) << "\\l";
break;
}
else
{
t << prot << " ";
t << convertLabel(mma->name());
if (!mma->isObjCMethod() &&
(mma->isFunction() || mma->isSlot() || mma->isSignal())) t << "()";
t << "\\l";
count++;
}
}
}
// write member groups within the memberlist
if (mgl)
{
for (mgli.toFirst();(mg=mgli.current());++mgli)
{
if (mg->members())
{
writeBoxMemberList(t,prot,mg->members(),scope,isStatic,skipNames);
}
}
}
}
}
void writeDotDirDepGraph ( FTextStream t,
DirDef dd,
bool  linkRelations 
)
static

Definition at line 4719 of file dot.cpp.

References SDict< T >::append(), Config_getBool, DirDef::dirCount(), Doxygen::dirRelations, DirDef::displayName(), FONTNAME, FONTSIZE, DirDef::getOutputFileBase(), Doxygen::htmlFileExtension, DirDef::isCluster(), DirDef::isParentOf(), DirDef::parent(), DirDef::shortName(), DirDef::subDirs(), and DirDef::usedDirs().

Referenced by DotDirDeps::writeGraph().

{
t << "digraph \"" << dd->displayName() << "\" {\n";
if (Config_getBool(DOT_TRANSPARENT))
{
t << " bgcolor=transparent;\n";
}
t << " compound=true\n";
t << " node [ fontsize=\"" << FONTSIZE << "\", fontname=\"" << FONTNAME << "\"];\n";
t << " edge [ labelfontsize=\"" << FONTSIZE << "\", labelfontname=\"" << FONTNAME << "\"];\n";
QDict<DirDef> dirsInGraph(257);
dirsInGraph.insert(dd->getOutputFileBase(),dd);
if (dd->parent())
{
t << " subgraph cluster" << dd->parent()->getOutputFileBase() << " {\n";
t << " graph [ bgcolor=\"#ddddee\", pencolor=\"black\", label=\""
<< dd->parent()->shortName()
<< "\" fontname=\"" << FONTNAME << "\", fontsize=\"" << FONTSIZE << "\", URL=\"";
t << "\"]\n";
}
if (dd->isCluster())
{
t << " subgraph cluster" << dd->getOutputFileBase() << " {\n";
t << " graph [ bgcolor=\"#eeeeff\", pencolor=\"black\", label=\"\""
<< "\"];\n";
t << " " << dd->getOutputFileBase() << " [shape=plaintext label=\""
<< dd->shortName() << "\"];\n";
// add nodes for sub directories
QListIterator<DirDef> sdi(dd->subDirs());
DirDef *sdir;
for (sdi.toFirst();(sdir=sdi.current());++sdi)
{
t << " " << sdir->getOutputFileBase() << " [shape=box label=\""
<< sdir->shortName() << "\"";
if (sdir->isCluster())
{
t << " color=\"red\"";
}
else
{
t << " color=\"black\"";
}
t << " fillcolor=\"white\" style=\"filled\"";
t << " URL=\"" << sdir->getOutputFileBase()
t << "];\n";
dirsInGraph.insert(sdir->getOutputFileBase(),sdir);
}
t << " }\n";
}
else
{
t << " " << dd->getOutputFileBase() << " [shape=box, label=\""
<< dd->shortName() << "\", style=\"filled\", fillcolor=\"#eeeeff\","
<< " pencolor=\"black\", URL=\"" << dd->getOutputFileBase()
}
if (dd->parent())
{
t << " }\n";
}
// add nodes for other used directories
QDictIterator<UsedDir> udi(*dd->usedDirs());
UsedDir *udir;
//printf("*** For dir %s\n",shortName().data());
for (udi.toFirst();(udir=udi.current());++udi)
// for each used dir (=directly used or a parent of a directly used dir)
{
const DirDef *usedDir=udir->dir();
DirDef *dir=dd;
while (dir)
{
//printf("*** check relation %s->%s same_parent=%d !%s->isParentOf(%s)=%d\n",
// dir->shortName().data(),usedDir->shortName().data(),
// dir->parent()==usedDir->parent(),
// usedDir->shortName().data(),
// shortName().data(),
// !usedDir->isParentOf(this)
// );
if (dir!=usedDir && dir->parent()==usedDir->parent() &&
!usedDir->isParentOf(dd))
// include if both have the same parent (or no parent)
{
t << " " << usedDir->getOutputFileBase() << " [shape=box label=\""
<< usedDir->shortName() << "\"";
if (usedDir->isCluster())
{
if (!Config_getBool(DOT_TRANSPARENT))
{
t << " fillcolor=\"white\" style=\"filled\"";
}
t << " color=\"red\"";
}
t << " URL=\"" << usedDir->getOutputFileBase()
dirsInGraph.insert(usedDir->getOutputFileBase(),usedDir);
break;
}
dir=dir->parent();
}
}
// add relations between all selected directories
DirDef *dir;
QDictIterator<DirDef> di(dirsInGraph);
for (di.toFirst();(dir=di.current());++di) // foreach dir in the graph
{
QDictIterator<UsedDir> udi(*dir->usedDirs());
UsedDir *udir;
for (udi.toFirst();(udir=udi.current());++udi) // foreach used dir
{
const DirDef *usedDir=udir->dir();
if ((dir!=dd || !udir->inherited()) && // only show direct dependendies for this dir
(usedDir!=dd || !udir->inherited()) && // only show direct dependendies for this dir
!usedDir->isParentOf(dir) && // don't point to own parent
dirsInGraph.find(usedDir->getOutputFileBase())) // only point to nodes that are in the graph
{
QCString relationName;
relationName.sprintf("dir_%06d_%06d",dir->dirCount(),usedDir->dirCount());
if (Doxygen::dirRelations.find(relationName)==0)
{
// new relation
new DirRelation(relationName,dir,udir));
}
int nrefs = udir->filePairs().count();
t << " " << dir->getOutputFileBase() << "->"
<< usedDir->getOutputFileBase();
t << " [headlabel=\"" << nrefs << "\", labeldistance=1.5";
if (linkRelations)
{
t << " headhref=\"" << relationName << Doxygen::htmlFileExtension << "\"";
}
t << "];\n";
}
}
}
t << "}\n";
}
void writeDotGraphFromFile ( const char *  inFile,
const char *  outDir,
const char *  outFile,
GraphOutputFormat  format 
)

Definition at line 4148 of file dot.cpp.

References IndexList::addImageFile(), DotRunner::addJob(), checkDotResult(), Config_getBool, Config_getEnum, err(), getDotImageExtension(), GOF_BITMAP, and Doxygen::indexList.

Referenced by DocbookDocVisitor::startDotFile(), LatexDocVisitor::startDotFile(), HtmlDocVisitor::writeDotFile(), RTFDocVisitor::writeDotFile(), and DocbookDocVisitor::writeDotFile().

{
QDir d(outDir);
if (!d.exists())
{
err("Output dir %s does not exist!\n",outDir); exit(1);
}
QCString imgExt = getDotImageExtension();
QCString imgFmt = Config_getEnum(DOT_IMAGE_FORMAT);
QCString imgName = (QCString)outFile+"."+imgExt;
QCString absImgName = d.absPath().utf8()+"/"+imgName;
QCString absOutFile = d.absPath().utf8()+"/"+outFile;
DotRunner dotRun(inFile,d.absPath().data(),FALSE,absImgName);
if (format==GOF_BITMAP)
dotRun.addJob(imgFmt,absImgName);
else // format==GOF_EPS
{
if (Config_getBool(USE_PDFLATEX))
{
dotRun.addJob("pdf",absOutFile+".pdf");
}
else
{
dotRun.addJob("ps",absOutFile+".eps");
}
}
dotRun.preventCleanUp();
if (!dotRun.run())
{
return;
}
if (format==GOF_BITMAP) checkDotResult(getDotImageExtension(),absImgName);
}
void writeDotImageMapFromFile ( FTextStream t,
const QCString &  inFile,
const QCString &  outDir,
const QCString &  relPath,
const QCString &  baseName,
const QCString &  context,
int  graphId 
)

Writes user defined image map to the output.

Parameters
ttext stream to write to
inFilejust the basename part of the filename
outDiroutput directory
relPathrelative path the to root of the output dir
baseNamethe base name of the output files
contextthe scope in which this graph is found (for resolving links)
graphIda unique id for this graph, use for dynamic sections

Definition at line 4200 of file dot.cpp.

References DotRunner::addJob(), DotFilePatcher::addSVGConversion(), Config_getEnum, convertMapFile(), endl(), err(), getDotImageExtension(), MAP_CMD, DotFilePatcher::run(), and writeSVGFigureLink().

Referenced by HtmlDocVisitor::writeDotFile().

{
QDir d(outDir);
if (!d.exists())
{
err("Output dir %s does not exist!\n",outDir.data()); exit(1);
}
QCString mapName = baseName+".map";
QCString imgExt = getDotImageExtension();
QCString imgFmt = Config_getEnum(DOT_IMAGE_FORMAT);
QCString imgName = baseName+"."+imgExt;
QCString absOutFile = d.absPath().utf8()+"/"+mapName;
DotRunner dotRun(inFile,d.absPath().data(),FALSE);
dotRun.addJob(MAP_CMD,absOutFile);
dotRun.preventCleanUp();
if (!dotRun.run())
{
return;
}
if (imgExt=="svg") // vector graphics
{
//writeSVGFigureLink(t,relPath,inFile,inFile+".svg");
//DotFilePatcher patcher(inFile+".svg");
QCString svgName=outDir+"/"+baseName+".svg";
writeSVGFigureLink(t,relPath,baseName,svgName);
DotFilePatcher patcher(svgName);
patcher.addSVGConversion(relPath,TRUE,context,TRUE,graphId);
patcher.run();
}
else // bitmap graphics
{
t << "<img src=\"" << relPath << imgName << "\" alt=\""
<< imgName << "\" border=\"0\" usemap=\"#" << mapName << "\"/>" << endl
<< "<map name=\"" << mapName << "\" id=\"" << mapName << "\">";
convertMapFile(t, absOutFile, relPath ,TRUE, context);
t << "</map>" << endl;
}
d.remove(absOutFile);
}
static void writeGraphFooter ( FTextStream t)
static

Definition at line 281 of file dot.cpp.

References endl().

Referenced by computeMd5Signature(), DotGfxHierarchyTable::createGraph(), generateGraphLegend(), and DotGroupCollaboration::writeGraph().

{
t << "}" << endl;
}
static void writeGraphHeader ( FTextStream t,
const QCString &  title = QCString() 
)
static

Definition at line 251 of file dot.cpp.

References Config_getBool, convertToXML(), endl(), FONTNAME, and FONTSIZE.

Referenced by computeMd5Signature(), DotGfxHierarchyTable::createGraph(), and generateGraphLegend().

{
static bool interactiveSVG = Config_getBool(INTERACTIVE_SVG);
t << "digraph ";
if (title.isEmpty())
{
t << "\"Dot Graph\"";
}
else
{
t << "\"" << convertToXML(title) << "\"";
}
t << endl << "{" << endl;
if (interactiveSVG) // insert a comment to force regeneration when this
// option is toggled
{
t << " // INTERACTIVE_SVG=YES\n";
}
if (Config_getBool(DOT_TRANSPARENT))
{
t << " bgcolor=\"transparent\";" << endl;
}
t << " edge [fontname=\"" << FONTNAME << "\","
"fontsize=\"" << FONTSIZE << "\","
"labelfontname=\"" << FONTNAME << "\","
"labelfontsize=\"" << FONTSIZE << "\"];\n";
t << " node [fontname=\"" << FONTNAME << "\","
"fontsize=\"" << FONTSIZE << "\",shape=record];\n";
}
static bool writeSVGFigureLink ( FTextStream out,
const QCString &  relPath,
const QCString &  baseName,
const QCString &  absImgName 
)
static

Definition at line 576 of file dot.cpp.

References readSVGSize(), and writeSVGNotSupported().

Referenced by DotGfxHierarchyTable::createGraph(), DotFilePatcher::run(), writeDotImageMapFromFile(), DotClassGraph::writeGraph(), DotInclDepGraph::writeGraph(), DotCallGraph::writeGraph(), DotDirDeps::writeGraph(), and DotGroupCollaboration::writeGraph().

{
int width=600,height=600;
if (!readSVGSize(absImgName,&width,&height))
{
return FALSE;
}
if (width==-1)
{
if (height<=60)
height=300;
else
height+=300; // add some extra space for zooming
if (height>600) height=600; // clip to maximum height of 600 pixels
out << "<div class=\"zoom\">";
//out << "<object type=\"image/svg+xml\" data=\""
//out << "<embed type=\"image/svg+xml\" src=\""
out << "<iframe scrolling=\"no\" frameborder=\"0\" src=\""
<< relPath << baseName << ".svg\" width=\"100%\" height=\"" << height << "\">";
}
else
{
//out << "<object type=\"image/svg+xml\" data=\""
//out << "<embed type=\"image/svg+xml\" src=\""
out << "<iframe scrolling=\"no\" frameborder=\"0\" src=\""
<< relPath << baseName << ".svg\" width=\""
<< ((width*96+48)/72) << "\" height=\""
<< ((height*96+48)/72) << "\">";
}
//out << "</object>";
//out << "</embed>";
out << "</iframe>";
if (width==-1)
{
out << "</div>";
}
return TRUE;
}
static void writeSVGNotSupported ( FTextStream out)
static

Definition at line 569 of file dot.cpp.

Referenced by writeSVGFigureLink().

{
out << "<p><b>This browser is not able to show SVG: try Firefox, Chrome, Safari, or Opera instead.</b></p>";
}
static bool writeVecGfxFigure ( FTextStream out,
const QCString &  baseName,
const QCString &  figureName 
)
static

Definition at line 476 of file dot.cpp.

References Config_getBool, and readBoundingBox().

Referenced by DotFilePatcher::run(), DotClassGraph::writeGraph(), DotInclDepGraph::writeGraph(), DotCallGraph::writeGraph(), DotDirDeps::writeGraph(), and DotGroupCollaboration::writeGraph().

{
int width=400,height=550;
static bool usePdfLatex = Config_getBool(USE_PDFLATEX);
if (usePdfLatex)
{
if (!readBoundingBox(figureName+".pdf",&width,&height,FALSE))
{
//printf("writeVecGfxFigure()=0\n");
return FALSE;
}
}
else
{
if (!readBoundingBox(figureName+".eps",&width,&height,TRUE))
{
//printf("writeVecGfxFigure()=0\n");
return FALSE;
}
}
//printf("Got PDF/EPS size %d,%d\n",width,height);
int maxWidth = 350; /* approx. page width in points, excl. margins */
int maxHeight = 550; /* approx. page height in points, excl. margins */
out << "\\nopagebreak\n"
"\\begin{figure}[H]\n"
"\\begin{center}\n"
"\\leavevmode\n";
if (width>maxWidth || height>maxHeight) // figure too big for page
{
// c*width/maxWidth > c*height/maxHeight, where c=maxWidth*maxHeight>0
if (width*maxHeight>height*maxWidth)
{
out << "\\includegraphics[width=" << maxWidth << "pt]";
}
else
{
out << "\\includegraphics[height=" << maxHeight << "pt]";
}
}
else
{
out << "\\includegraphics[width=" << width << "pt]";
}
out << "{" << baseName << "}\n"
"\\end{center}\n"
"\\end{figure}\n";
//printf("writeVecGfxFigure()=1\n");
return TRUE;
}

Variable Documentation

QCString g_dotFontPath
static

Definition at line 400 of file dot.cpp.

const char* normalArrowStyleMap[]
static
Initial value:
=
{
"empty",
"empty",
"empty",
"open",
0,
0
}

Definition at line 171 of file dot.cpp.

const char* normalEdgeColorMap[]
static
Initial value:
=
{
"midnightblue",
"darkgreen",
"firebrick4",
"darkorchid3",
"grey75",
"orange",
"orange"
}

mapping from protection levels to color names

Definition at line 160 of file dot.cpp.

EdgeProperties normalEdgeProps
static
Initial value:

Definition at line 222 of file dot.cpp.

Referenced by DotNode::writeArrow().

const char* normalEdgeStyleMap[]
static
Initial value:
=
{
"solid",
"dashed"
}

Definition at line 181 of file dot.cpp.

const char svgZoomFooter[]
static

Definition at line 103 of file dot.cpp.

Referenced by DotFilePatcher::run().

const char svgZoomHeader[]
static

Definition at line 59 of file dot.cpp.

Referenced by DotFilePatcher::run().

const char* umlArrowStyleMap[]
static
Initial value:
=
{
"onormal",
"onormal",
"onormal",
"odiamond",
0,
0
}

Definition at line 198 of file dot.cpp.

const char* umlEdgeColorMap[]
static
Initial value:
=
{
"midnightblue",
"darkgreen",
"firebrick4",
"grey25",
"grey75",
"orange",
"orange"
}

Definition at line 187 of file dot.cpp.

EdgeProperties umlEdgeProps
static
Initial value:

Definition at line 227 of file dot.cpp.

const char* umlEdgeStyleMap[]
static
Initial value:
=
{
"solid",
"solid"
}

Definition at line 208 of file dot.cpp.