Doxygen
dotgraph.cpp
浏览该文件的文档.
1 /******************************************************************************
2 *
3 * Copyright (C) 1997-2019 by Dimitri van Heesch.
4 *
5 * Permission to use, copy, modify, and distribute this software and its
6 * documentation under the terms of the GNU General Public License is hereby
7 * granted. No representations are made about the suitability of this software
8 * for any purpose. It is provided "as is" without express or implied warranty.
9 * See the GNU General Public License for more details.
10 *
11 * Documents produced by Doxygen are derivative works derived from the
12 * input used in their production; they are not affected by this license.
13 *
14 */
15 
16 #include <sstream>
17 
18 #include "config.h"
19 #include "doxygen.h"
20 #include "index.h"
21 #include "md5.h"
22 #include "message.h"
23 #include "util.h"
24 
25 #include "dot.h"
26 #include "dotrunner.h"
27 #include "dotgraph.h"
28 #include "dotnode.h"
29 #include "dotfilepatcher.h"
30 #include "fileinfo.h"
31 
32 #define MAP_CMD "cmapx"
33 
34 //QCString DotGraph::DOT_FONTNAME; // will be initialized in initDot
35 //int DotGraph::DOT_FONTSIZE; // will be initialized in initDot
36 
37 /*! Checks if a file "baseName".md5 exists. If so the contents
38 * are compared with \a md5. If equal FALSE is returned.
39 * The .md5 is created or updated after successful creation of the output file.
40 */
41 static bool sameMd5Signature(const QCString &baseName,
42  const QCString &md5)
43 {
44  bool same = false;
45  char md5stored[33];
46  md5stored[0]=0;
47  std::ifstream f(baseName.str()+".md5",std::ifstream::in | std::ifstream::binary);
48  if (f.is_open())
49  {
50  // read checksum
51  f.read(md5stored,32);
52  md5stored[32]='\0';
53  // compare checksum
54  if (!f.fail() && md5==md5stored)
55  {
56  same = true;
57  }
58  //printf("sameSignature(%s,%s==%s)=%d\n",qPrint(baseName),md5stored,qPrint(md5),same);
59  }
60  else
61  {
62  //printf("sameSignature(%s) not found\n",qPrint(baseName));
63  }
64  return same;
65 }
66 
67 static bool deliverablesPresent(const QCString &file1,const QCString &file2)
68 {
69  bool file1Ok = true;
70  bool file2Ok = true;
71  if (!file1.isEmpty())
72  {
73  FileInfo fi(file1.str());
74  file1Ok = (fi.exists() && fi.size()>0);
75  }
76  if (!file2.isEmpty())
77  {
78  FileInfo fi(file2.str());
79  file2Ok = (fi.exists() && fi.size()>0);
80  }
81  return file1Ok && file2Ok;
82 }
83 
84 static bool insertMapFile(TextStream &out,const QCString &mapFile,
85  const QCString &relPath,const QCString &mapLabel)
86 {
87  FileInfo fi(mapFile.str());
88  if (fi.exists() && fi.size()>0) // reuse existing map file
89  {
90  TextStream t;
91  DotFilePatcher::convertMapFile(t,mapFile,relPath,false);
92  if (!t.empty())
93  {
94  out << "<map name=\"" << mapLabel << "\" id=\"" << mapLabel << "\">\n";
95  out << t.str();
96  out << "</map>\n";
97  }
98  return true;
99  }
100  return false; // no map file yet, need to generate it
101 }
102 
103 //--------------------------------------------------------------------
104 
106 {
107  return m_baseName + ((m_graphFormat == GOF_BITMAP) ?
108  ("." + getDotImageExtension()) : (Config_getBool(USE_PDFLATEX) ? ".pdf" : ".eps"));
109 }
110 
112  TextStream& t, // output stream for the code file (html, ...)
113  GraphOutputFormat gf, // bitmap(png/svg) or ps(eps/pdf)
114  EmbeddedOutputFormat ef, // html, latex, ...
115  const QCString &path, // output folder
116  const QCString &fileName, // name of the code file (for code patcher)
117  const QCString &relPath, // output folder relative to code file
118  bool generateImageMap, // in case of bitmap, shall there be code generated?
119  int graphId) // number of this graph in the current code, used in svg code
120 {
121  m_graphFormat = gf;
122  m_textFormat = ef;
123  m_dir = Dir(path.str());
124  m_fileName = fileName;
125  m_relPath = relPath;
126  m_generateImageMap = generateImageMap;
127  m_graphId = graphId;
128 
129  m_absPath = m_dir.absPath() + "/";
131 
132  computeTheGraph();
133 
135 
137 
138  generateCode(t);
139 
140  return m_baseName;
141 }
142 
144 {
145  if (!m_dir.exists())
146  {
147  term("Output dir %s does not exist!\n", m_dir.path().c_str());
148  }
149 
150  char sigStr[33];
151  uchar md5_sig[16];
152  // calculate md5
153  MD5Buffer((const unsigned char*)m_theGraph.data(), m_theGraph.length(), md5_sig);
154  // convert result to a string
155  MD5SigToString(md5_sig, sigStr);
156 
157  // already queued files are processed again in case the output format has changed
158 
159  if (sameMd5Signature(absBaseName(), sigStr) &&
162  )
163  )
164  {
165  // all needed files are there
166  return FALSE;
167  }
168 
169  // need to rebuild the image
170 
171  // write .dot file because image was new or has changed
172  std::ofstream f(absDotName().str(),std::ofstream::out | std::ofstream::binary);
173  if (!f.is_open())
174  {
175  err("Could not open file %s for writing\n",qPrint(absDotName()));
176  return TRUE;
177  }
178  f << m_theGraph;
179  f.close();
180 
181  if (m_graphFormat == GOF_BITMAP)
182  {
183  // run dot to create a bitmap image
184  DotRunner * dotRun = DotManager::instance()->createRunner(absDotName(), sigStr);
185  dotRun->addJob(Config_getEnumAsString(DOT_IMAGE_FORMAT), absImgName(), absDotName(), 1);
186  if (m_generateImageMap) dotRun->addJob(MAP_CMD, absMapName(), absDotName(), 1);
187  }
188  else if (m_graphFormat == GOF_EPS)
189  {
190  // run dot to create a .eps image
191  DotRunner *dotRun = DotManager::instance()->createRunner(absDotName(), sigStr);
192  if (Config_getBool(USE_PDFLATEX))
193  {
194  dotRun->addJob("pdf",absImgName(),absDotName(),1);
195  }
196  else
197  {
198  dotRun->addJob("ps",absImgName(),absDotName(),1);
199  }
200  }
201  return TRUE;
202 }
203 
205 {
206  QCString imgExt = getDotImageExtension();
208  {
209  t << "<para>\n";
210  t << " <informalfigure>\n";
211  t << " <mediaobject>\n";
212  t << " <imageobject>\n";
213  t << " <imagedata";
214  t << " width=\"50%\" align=\"center\" valign=\"middle\" scalefit=\"0\" fileref=\"" << m_relPath << m_baseName << "." << imgExt << "\">";
215  t << "</imagedata>\n";
216  t << " </imageobject>\n";
217  t << " </mediaobject>\n";
218  t << " </informalfigure>\n";
219  t << "</para>\n";
220  }
221  else if (m_graphFormat==GOF_BITMAP && m_generateImageMap) // produce HTML to include the image
222  {
223  if (imgExt=="svg") // add link to SVG file without map file
224  {
225  if (!m_noDivTag) t << "<div class=\"center\">";
226  if (m_regenerate || !DotFilePatcher::writeSVGFigureLink(t,m_relPath,m_baseName,absImgName())) // need to patch the links in the generated SVG file
227  {
228  if (m_regenerate)
229  {
231  createFilePatcher(absImgName())->
232  addSVGConversion(m_relPath,FALSE,QCString(),m_zoomable,m_graphId);
233  }
234  int mapId = DotManager::instance()->
235  createFilePatcher(m_fileName)->
236  addSVGObject(m_baseName,absImgName(),m_relPath);
237  t << "<!-- SVG " << mapId << " -->\n";
238  }
239  if (!m_noDivTag) t << "</div>\n";
240  }
241  else // add link to bitmap file with image map
242  {
243  if (!m_noDivTag) t << "<div class=\"center\">";
244  t << "<img src=\"" << relImgName() << "\" border=\"0\" usemap=\"#" << correctId(getMapLabel()) << "\" alt=\"" << getImgAltText() << "\"/>";
245  if (!m_noDivTag) t << "</div>";
246  t << "\n";
248  {
249  int mapId = DotManager::instance()->
250  createFilePatcher(m_fileName)->
252  t << "<!-- MAP " << mapId << " -->\n";
253  }
254  }
255  }
256  else if (m_graphFormat==GOF_EPS) // produce tex to include the .eps image
257  {
259  {
260  int figId = DotManager::instance()->
261  createFilePatcher(m_fileName)->
262  addFigure(m_baseName,absBaseName(),FALSE /*TRUE*/);
263  t << "\n% FIG " << figId << "\n";
264  }
265  }
266 }
267 
269 {
270  int fontSize = Config_getInt(DOT_FONTSIZE);
271  QCString fontName = Config_getString(DOT_FONTNAME);
272  t << "digraph ";
273  if (title.isEmpty())
274  {
275  t << "\"Dot Graph\"";
276  }
277  else
278  {
279  t << "\"" << convertToXML(title) << "\"";
280  }
281  t << "\n{\n";
282  if (Config_getBool(INTERACTIVE_SVG)) // insert a comment to force regeneration when this
283  // option is toggled
284  {
285  t << " // INTERACTIVE_SVG=YES\n";
286  }
287  t << " // LATEX_PDF_SIZE\n"; // write placeholder for LaTeX PDF bounding box size replacement
288  if (Config_getBool(DOT_TRANSPARENT))
289  {
290  t << " bgcolor=\"transparent\";\n";
291  }
292  t << " edge [fontname=\"" << fontName << "\","
293  "fontsize=\"" << fontSize << "\","
294  "labelfontname=\"" << fontName << "\","
295  "labelfontsize=\"" << fontSize << "\"];\n";
296  t << " node [fontname=\"" << fontName << "\","
297  "fontsize=\"" << fontSize << "\",shape=record];\n";
298 }
299 
301 {
302  t << "}\n";
303 }
304 
306  GraphType gt,
307  GraphOutputFormat format,
308  const QCString &rank, // either "LR", "RL", or ""
309  bool renderParents,
310  bool backArrows,
311  const QCString &title,
312  QCString &graphStr)
313 {
314  //printf("computeMd5Signature\n");
315  TextStream md5stream;
316  writeGraphHeader(md5stream,title);
317  if (!rank.isEmpty())
318  {
319  md5stream << " rankdir=\"" << rank << "\";\n";
320  }
321  root->clearWriteFlag();
322  root->write(md5stream, gt, format, gt!=CallGraph && gt!=Dependency, TRUE, backArrows);
323  if (renderParents)
324  {
325  for (const auto &pn : root->parents())
326  {
327  if (pn->isVisible())
328  {
329  const auto &children = pn->children();
330  auto child_it = std::find(children.begin(),children.end(),root);
331  size_t index = child_it - children.begin();
332  root->writeArrow(md5stream, // stream
333  gt, // graph type
334  format, // output format
335  pn, // child node
336  &pn->edgeInfo()[index], // edge info
337  FALSE, // topDown?
338  backArrows // point back?
339  );
340  }
341  pn->write(md5stream, // stream
342  gt, // graph type
343  format, // output format
344  TRUE, // topDown?
345  FALSE, // toChildren?
346  backArrows // backward pointing arrows?
347  );
348  }
349  }
350  writeGraphFooter(md5stream);
351 
352  graphStr=md5stream.str();
353 }
354 
getDotImageExtension
QCString getDotImageExtension()
Definition: util.cpp:7032
DotGraph::m_graphId
int m_graphId
Definition: dotgraph.h:85
DotManager::instance
static DotManager * instance()
Definition: dot.cpp:77
DotGraph::m_urlOnly
bool m_urlOnly
Definition: dotgraph.h:94
DotGraph::computeGraph
static void computeGraph(DotNode *root, GraphType gt, GraphOutputFormat format, const QCString &rank, bool renderParents, bool backArrows, const QCString &title, QCString &graphStr)
Definition: dotgraph.cpp:305
fileinfo.h
DotNode::parents
const DotNodeRefVector & parents() const
Definition: dotnode.h:110
DotGraph::m_theGraph
QCString m_theGraph
Definition: dotgraph.h:89
DotGraph::m_dir
Dir m_dir
Definition: dotgraph.h:81
DotGraph::m_doNotAddImageToIndex
bool m_doNotAddImageToIndex
Definition: dotgraph.h:91
Dir
Class representing a directory in the file system
Definition: dir.h:68
DotRunner
Helper class to run dot from doxygen from multiple threads.
Definition: dotrunner.h:30
QCString::length
uint length() const
Returns the length of the string, not counting the 0-terminator.
Definition: qcstring.h:147
dotnode.h
DotGraph::getImgAltText
virtual QCString getImgAltText() const
Definition: dotgraph.h:68
DotNode::write
void write(TextStream &t, GraphType gt, GraphOutputFormat f, bool topDown, bool toChildren, bool backArrows) const
Definition: dotnode.cpp:532
QCString::isEmpty
bool isEmpty() const
Returns TRUE iff the string is empty
Definition: qcstring.h:144
DotGraph::relImgName
QCString relImgName() const
Definition: dotgraph.h:76
index.h
DotGraph::m_regenerate
bool m_regenerate
Definition: dotgraph.h:90
MAP_CMD
#define MAP_CMD
Definition: dotgraph.cpp:32
Doxygen::indexList
static IndexList * indexList
Definition: doxygen.h:114
DotManager::createRunner
DotRunner * createRunner(const QCString &absDotName, const QCString &md5Hash)
Definition: dot.cpp:120
DotFilePatcher::writeVecGfxFigure
static bool writeVecGfxFigure(TextStream &out, const QCString &baseName, const QCString &figureName)
Definition: dotfilepatcher.cpp:578
DotGraph::getMapLabel
virtual QCString getMapLabel() const =0
DotGraph::absBaseName
QCString absBaseName() const
Definition: dotgraph.h:72
DotGraph::generateCode
void generateCode(TextStream &t)
Definition: dotgraph.cpp:204
DotGraph::writeGraphFooter
static void writeGraphFooter(TextStream &t)
Definition: dotgraph.cpp:300
DotGraph::absDotName
QCString absDotName() const
Definition: dotgraph.h:73
QCString::str
std::string str() const
Definition: qcstring.h:442
err
void err(const char *fmt,...)
Definition: message.cpp:203
TextStream
Text streaming class that buffers data.
Definition: textstream.h:33
DotGraph::writeGraphHeader
static void writeGraphHeader(TextStream &t, const QCString &title=QCString())
Definition: dotgraph.cpp:268
TextStream::empty
bool empty() const
Returns true iff the buffer is empty
Definition: textstream.h:232
DotRunner::addJob
void addJob(const QCString &format, const QCString &output, const QCString &srcFile, int srcLine)
Adds an additional job to the run.
Definition: dotrunner.cpp:150
DotGraph::m_absPath
QCString m_absPath
Definition: dotgraph.h:87
dot.h
DotNode
A node in a dot graph
Definition: dotnode.h:56
DotGraph::absMapName
virtual QCString absMapName() const
Definition: dotgraph.h:66
Config_getInt
#define Config_getInt(name)
Definition: config.h:34
FileInfo::size
size_t size() const
Definition: fileinfo.cpp:23
uchar
unsigned char uchar
Definition: qcstring.h:38
FileInfo::exists
bool exists() const
Definition: fileinfo.cpp:30
Dir::path
std::string path() const
Definition: dir.cpp:176
DotGraph::m_textFormat
EmbeddedOutputFormat m_textFormat
Definition: dotgraph.h:80
message.h
IndexList::addImageFile
void addImageFile(const QCString &name)
Definition: index.h:105
EOF_DocBook
@ EOF_DocBook
Definition: dotgraph.h:28
GraphType
GraphType
Definition: dotgraph.h:29
deliverablesPresent
static bool deliverablesPresent(const QCString &file1, const QCString &file2)
Definition: dotgraph.cpp:67
Dir::absPath
std::string absPath() const
Definition: dir.cpp:305
doxygen.h
Config_getEnumAsString
#define Config_getEnumAsString(name)
Definition: config.h:36
Dependency
@ Dependency
Definition: dotgraph.h:29
DotFilePatcher::writeSVGFigureLink
static bool writeSVGFigureLink(TextStream &out, const QCString &relPath, const QCString &baseName, const QCString &absImgName)
Check if a reference to a SVG figure can be written and do so if possible.
Definition: dotfilepatcher.cpp:539
dotfilepatcher.h
DotGraph::m_graphFormat
GraphOutputFormat m_graphFormat
Definition: dotgraph.h:79
TRUE
#define TRUE
Definition: qcstring.h:36
DotNode::clearWriteFlag
void clearWriteFlag()
Definition: dotnode.cpp:765
dotrunner.h
TextStream::str
std::string str() const
Return the contents of the buffer as a std::string object
Definition: textstream.h:208
dotgraph.h
DotGraph::writeGraph
QCString writeGraph(TextStream &t, GraphOutputFormat gf, EmbeddedOutputFormat ef, const QCString &path, const QCString &fileName, const QCString &relPath, bool writeImageMap=TRUE, int graphId=-1)
Definition: dotgraph.cpp:111
DotNode::writeArrow
void writeArrow(TextStream &t, GraphType gt, GraphOutputFormat f, const DotNode *cn, const EdgeInfo *ei, bool topDown, bool pointBack=TRUE) const
Definition: dotnode.cpp:483
DotGraph::m_zoomable
bool m_zoomable
Definition: dotgraph.h:93
insertMapFile
static bool insertMapFile(TextStream &out, const QCString &mapFile, const QCString &relPath, const QCString &mapLabel)
Definition: dotgraph.cpp:84
GOF_BITMAP
@ GOF_BITMAP
Definition: dotgraph.h:27
CallGraph
@ CallGraph
Definition: dotgraph.h:29
DotGraph::m_fileName
QCString m_fileName
Definition: dotgraph.h:82
DotGraph::absImgName
QCString absImgName() const
Definition: dotgraph.h:75
Config_getBool
#define Config_getBool(name)
Definition: config.h:33
DotGraph::computeTheGraph
virtual void computeTheGraph()=0
DotGraph::imgName
QCString imgName() const
Definition: dotgraph.cpp:105
term
void term(const char *fmt,...)
Definition: message.cpp:220
FileInfo
Minimal replacement for QFileInfo.
Definition: fileinfo.h:22
qPrint
const char * qPrint(const char *s)
Definition: qcstring.h:589
DotGraph::getBaseName
virtual QCString getBaseName() const =0
Config_getString
#define Config_getString(name)
Definition: config.h:32
config.h
QCString::data
const char * data() const
Returns a pointer to the contents of the string in the form of a 0-terminated C string
Definition: qcstring.h:153
convertToXML
QCString convertToXML(const QCString &s, bool keepEntities)
Definition: util.cpp:3948
EmbeddedOutputFormat
EmbeddedOutputFormat
Definition: dotgraph.h:28
Dir::exists
bool exists() const
Definition: dir.cpp:199
GraphOutputFormat
GraphOutputFormat
Definition: dotgraph.h:27
DotGraph::m_noDivTag
bool m_noDivTag
Definition: dotgraph.h:92
DotGraph::prepareDotFile
bool prepareDotFile()
Definition: dotgraph.cpp:143
GOF_EPS
@ GOF_EPS
Definition: dotgraph.h:27
DotGraph::m_generateImageMap
bool m_generateImageMap
Definition: dotgraph.h:84
DotFilePatcher::convertMapFile
static bool convertMapFile(TextStream &t, const QCString &mapName, const QCString &relPath, bool urlOnly=FALSE, const QCString &context=QCString())
Definition: dotfilepatcher.cpp:214
DotGraph::m_relPath
QCString m_relPath
Definition: dotgraph.h:83
util.h
A bunch of utility functions.
sameMd5Signature
static bool sameMd5Signature(const QCString &baseName, const QCString &md5)
Definition: dotgraph.cpp:41
correctId
QCString correctId(const QCString &s)
Definition: util.cpp:3941
DotGraph::m_baseName
QCString m_baseName
Definition: dotgraph.h:88
FALSE
#define FALSE
Definition: qcstring.h:33
QCString
This is an alternative implementation of QCString.
Definition: qcstring.h:108