Skip to main content

The dotdirdeps.cpp File Reference

Included Headers

#include "dotdirdeps.h" #include "util.h" #include "doxygen.h" #include "config.h" #include "image.h" #include "dotnode.h" #include <algorithm> #include <iterator> #include <utility> #include <cstdint> #include <math.h> #include <cassert> #include <map> #include <memory> #include <string> #include <vector>

Classes Index

structDotDirProperty

Properties are used to format the directories in the graph distinctively. More...

classDotDirPropertyBuilder

Builder helper to create instances of the DotDirProperty struct. More...

Typedefs Index

usingDirDefMap = std::map< std::string, const DirDef * >
typedefstd::vector< std::pair< std::unique_ptr< DirRelation >, bool > > DirRelations

Elements consist of (1) directory relation and (2) whether it is pointing only to inherited dependees. More...

Functions Index

static QCStringgetDirectoryBackgroundColor (int depthIndex)

Returns a DOT color name according to the directory depth. More...

static const char *getDirectoryBorderColor (const DotDirProperty &property)

Returns a DOT color name according to the directory properties. More...

static std::stringgetDirectoryBorderStyle (const DotDirProperty &property)

Returns a DOT node style according to the directory properties. More...

static TextStream &common_attributes (TextStream &t, const DirDef *const dir, const DotDirProperty &prop)
static voiddrawDirectory (TextStream &t, const DirDef *const directory, const DotDirProperty &property, DirDefMap &directoriesInGraph, int startLevel)

Puts DOT code for drawing directory to stream and adds it to the list. More...

static boolisAtMaxDepth (const DirDef *const directory, const int startLevel)

Checks, if the directory is a the maximum drawn directory level. More...

static voiddrawClusterOpening (TextStream &outputStream, const DirDef *const directory, const DotDirProperty &directoryProperty, DirDefMap &directoriesInGraph, const bool isAncestor, int startLevel)

Writes DOT code for opening a cluster subgraph to stream. More...

static voiddrawClusterClosing (TextStream &t)
static voidaddDependencies (DirRelations &dependencies, const DirDef *const srcDir, bool isLeaf)

Assembles a list of the directory relations and whether or not they result from "inheritance". More...

static voiddrawTree (DirRelations &dependencies, TextStream &t, const DirDef *const directory, int startLevel, DirDefMap &directoriesInGraph, const bool isTreeRoot)

Recursively draws directory tree. More...

voidwriteDotDirDepGraph (TextStream &t, const DirDef *dd, bool linkRelations)

Write DOT code for directory dependency graph. More...

Typedefs

DirDefMap

using DirDefMap = std::map<std::string,const DirDef *>

Definition at line 34 of file dotdirdeps.cpp.

34using DirDefMap = std::map<std::string,const DirDef *>;

DirRelations

typedef std::vector< std::pair< std::unique_ptr<DirRelation>, bool> > DirRelations

Elements consist of (1) directory relation and (2) whether it is pointing only to inherited dependees.

Definition at line 61 of file dotdirdeps.cpp.

61typedef std::vector< std::pair< std::unique_ptr<DirRelation>, bool> > DirRelations;

Functions

addDependencies()

void addDependencies (DirRelations & dependencies, const DirDef *const srcDir, bool isLeaf)
static

Assembles a list of the directory relations and whether or not they result from "inheritance".

Parameters
dependencies

Array to add the dependencies to.

srcDir

is the source of the dependency.

isLeaf

true, if no children are drawn for this directory.

Definition at line 215 of file dotdirdeps.cpp.

215static void addDependencies(DirRelations &dependencies,const DirDef *const srcDir, bool isLeaf)
216{
217 for (const auto &usedDirectory : srcDir->usedDirs())
218 {
219 const auto dstDir = usedDirectory->dir();
220 if (!dstDir->isParentOf(srcDir) && (isLeaf || usedDirectory->hasDirectSrcDeps()))
221 {
222 QCString relationName;
223 relationName.sprintf("dir_%06d_%06d", srcDir->dirIndex(), dstDir->dirIndex());
224 bool directRelation = isLeaf ? usedDirectory->hasDirectDstDeps() : usedDirectory->hasDirectDeps();
225 dependencies.emplace_back(
226 std::make_unique<DirRelation>(relationName, srcDir, usedDirectory.get()),
227 directRelation);
228 }
229 }
230}

References DirDef::dirIndex, QCString::sprintf and DirDef::usedDirs.

Referenced by drawTree.

common_attributes()

TextStream & common_attributes (TextStream & t, const DirDef *const dir, const DotDirProperty & prop)
static

Definition at line 137 of file dotdirdeps.cpp.

137static TextStream &common_attributes(TextStream &t, const DirDef *const dir, const DotDirProperty &prop)
138{
139 QCString url = dir->getOutputFileBase();
141 return t <<
142 "style=\"" << getDirectoryBorderStyle(prop) << "\", "
143 "URL=\"" << url << "\","
144 "tooltip=\"" << escapeTooltip(dir->briefDescriptionAsTooltip()) << "\"";
145}

References addHtmlExtensionIfMissing, Definition::briefDescriptionAsTooltip, escapeTooltip, getDirectoryBorderStyle and Definition::getOutputFileBase.

Referenced by drawClusterOpening and drawDirectory.

drawClusterClosing()

void drawClusterClosing (TextStream & t)
static

Definition at line 204 of file dotdirdeps.cpp.

205{
206 t << " }\n";
207}

Referenced by drawTree.

drawClusterOpening()

void drawClusterOpening (TextStream & outputStream, const DirDef *const directory, const DotDirProperty & directoryProperty, DirDefMap & directoriesInGraph, const bool isAncestor, int startLevel)
static

Writes DOT code for opening a cluster subgraph to stream.

Ancestor clusters directly get a label. Other clusters get a plain text node with a label instead. This is because the plain text node can be used to draw dependency relationships.

Definition at line 179 of file dotdirdeps.cpp.

179static void drawClusterOpening(TextStream &outputStream, const DirDef *const directory,
180 const DotDirProperty &directoryProperty, DirDefMap &directoriesInGraph, const bool isAncestor,int startLevel)
181{
182 outputStream << " subgraph cluster" << directory->getOutputFileBase() << " {\n"
183 " graph [ "
184 "bgcolor=\"" << getDirectoryBackgroundColor(directory->level()-startLevel) << "\", "
185 "pencolor=\"" << getDirectoryBorderColor(directoryProperty) << "\", "
186 "label=\"";
187 if (isAncestor)
188 {
189 outputStream << DotNode::convertLabel(directory->shortName());
190 }
191 outputStream << "\", "
192 << Config_getString(DOT_COMMON_ATTR) << " ";
193 common_attributes(outputStream, directory, directoryProperty)
194 << "]\n";
195 if (!isAncestor)
196 {
197 outputStream << " " << directory->getOutputFileBase() << " [shape=plaintext, "
198 "label=\"" << DotNode::convertLabel(directory->shortName()) << "\""
199 "];\n";
200 directoriesInGraph.emplace(directory->getOutputFileBase().str(), directory);
201 }
202}

References common_attributes, Config_getString, DotNode::convertLabel, getDirectoryBackgroundColor, getDirectoryBorderColor, Definition::getOutputFileBase, DirDef::level, DirDef::shortName and QCString::str.

Referenced by drawTree and writeDotDirDepGraph.

drawDirectory()

void drawDirectory (TextStream & t, const DirDef *const directory, const DotDirProperty & property, DirDefMap & directoriesInGraph, int startLevel)
static

Puts DOT code for drawing directory to stream and adds it to the list.

Parameters
[inout] t

stream to which the DOT code is written to

[in] directory

will be mapped to a node in DOT code

[in] property

are evaluated for formatting

[inout] directoriesInGraph

lists the directories which have been written to the output stream

[in] startLevel

current level to calculate relative distances from to determine the background color

Definition at line 155 of file dotdirdeps.cpp.

155static void drawDirectory(TextStream &t, const DirDef *const directory, const DotDirProperty &property,
156 DirDefMap &directoriesInGraph,int startLevel)
157{
158 t << " " << directory->getOutputFileBase() << " ["
159 "label=\"" << DotNode::convertLabel(directory->shortName()) << "\", "
160 "fillcolor=\"" << getDirectoryBackgroundColor(directory->level()-startLevel) << "\", "
161 "color=\"" << getDirectoryBorderColor(property) << "\", ";
162 common_attributes(t, directory, property)
163 << "];\n";
164 directoriesInGraph.emplace(directory->getOutputFileBase().str(), directory);
165}

References common_attributes, DotNode::convertLabel, getDirectoryBackgroundColor, getDirectoryBorderColor, Definition::getOutputFileBase, DirDef::level, DirDef::shortName and QCString::str.

Referenced by drawTree.

drawTree()

void drawTree (DirRelations & dependencies, TextStream & t, const DirDef *const directory, int startLevel, DirDefMap & directoriesInGraph, const bool isTreeRoot)
static

Recursively draws directory tree.

Definition at line 233 of file dotdirdeps.cpp.

233static void drawTree(DirRelations &dependencies, TextStream &t, const DirDef *const directory,
234 int startLevel, DirDefMap &directoriesInGraph, const bool isTreeRoot)
235{
236 if (!directory->hasSubdirs())
237 {
238 const DotDirProperty directoryProperty = DotDirPropertyBuilder().makeOriginal(isTreeRoot);
239 drawDirectory(t, directory, directoryProperty, directoriesInGraph,startLevel);
240 addDependencies(dependencies, directory, true);
241 }
242 else
243 {
244 if (isAtMaxDepth(directory, startLevel)) // maximum nesting level reached
245 {
246 const DotDirProperty directoryProperty = DotDirPropertyBuilder().makeOriginal(isTreeRoot);
247 drawDirectory(t, directory, directoryProperty, directoriesInGraph,startLevel);
248 addDependencies(dependencies, directory, true);
249 }
250 else // start a new nesting level
251 {
252 // open cluster
253 {
254 const DotDirProperty directoryProperty = DotDirPropertyBuilder().makeOriginal(isTreeRoot);
255 drawClusterOpening(t, directory, directoryProperty, directoriesInGraph, false, startLevel);
256 addDependencies(dependencies, directory, false);
257 }
258
259 // process all sub directories
260 for (const auto subDirectory : directory->subDirs())
261 {
262 drawTree(dependencies, t, subDirectory, startLevel, directoriesInGraph, false);
263 }
264
265 // close cluster
266 {
268 }
269 }
270 }
271}

References addDependencies, drawClusterClosing, drawClusterOpening, drawDirectory, drawTree, DirDef::hasSubdirs, isAtMaxDepth, DotDirPropertyBuilder::makeOriginal and DirDef::subDirs.

Referenced by drawTree.

getDirectoryBackgroundColor()

QCString getDirectoryBackgroundColor (int depthIndex)
static

Returns a DOT color name according to the directory depth.

Definition at line 64 of file dotdirdeps.cpp.

65{
66 int hue = Config_getInt(HTML_COLORSTYLE_HUE);
67 int sat = Config_getInt(HTML_COLORSTYLE_SAT);
68 int gamma = Config_getInt(HTML_COLORSTYLE_GAMMA);
69 assert(depthIndex>=0 && depthIndex<=Config_getInt(DIR_GRAPH_MAX_DEPTH));
70 float fraction = static_cast<float>(depthIndex)/static_cast<float>(Config_getInt(DIR_GRAPH_MAX_DEPTH));
71 const char hex[] = "0123456789abcdef";
72 int range = 0x40; // range from darkest color to lightest color
73 int luma = 0xef-static_cast<int>(fraction*static_cast<float>(range)); // interpolation
74 double r=0, g=0, b=0;
75 ColoredImage::hsl2rgb(hue/360.0,sat/255.0,
76 pow(luma/255.0,gamma/100.0),&r,&g,&b);
77 int red = static_cast<int>(r*255.0);
78 int green = static_cast<int>(g*255.0);
79 int blue = static_cast<int>(b*255.0);
80 assert(red>=0 && red<=255);
81 assert(green>=0 && green<=255);
82 assert(blue>=0 && blue<=255);
83 char colStr[8];
84 colStr[0]='#';
85 colStr[1]=hex[red>>4];
86 colStr[2]=hex[red&0xf];
87 colStr[3]=hex[green>>4];
88 colStr[4]=hex[green&0xf];
89 colStr[5]=hex[blue>>4];
90 colStr[6]=hex[blue&0xf];
91 colStr[7]=0;
92 //printf("i=%d max=%d fraction=%f luma=%d %02x %02x %02x -> color=%s\n",
93 // depthIndex,Config_getInt(DIR_GRAPH_MAX_DEPTH),fraction,luma,red,green,blue,colStr);
94 return colStr;
95}

References Config_getInt, hex and ColoredImage::hsl2rgb.

Referenced by drawClusterOpening and drawDirectory.

getDirectoryBorderColor()

const char * getDirectoryBorderColor (const DotDirProperty & property)
static

Returns a DOT color name according to the directory properties.

Definition at line 98 of file dotdirdeps.cpp.

98static const char* getDirectoryBorderColor(const DotDirProperty &property)
99{
100 if (property.isTruncated && property.isOrphaned)
101 {
102 return "red";
103 }
104 else if (property.isTruncated)
105 {
106 return "red";
107 }
108 else if (property.isOrphaned)
109 {
110 return "grey50";
111 }
112 else
113 {
114 return "grey25";
115 }
116}

References DotDirProperty::isOrphaned and DotDirProperty::isTruncated.

Referenced by drawClusterOpening and drawDirectory.

getDirectoryBorderStyle()

std::string getDirectoryBorderStyle (const DotDirProperty & property)
static

Returns a DOT node style according to the directory properties.

Definition at line 119 of file dotdirdeps.cpp.

119static std::string getDirectoryBorderStyle(const DotDirProperty &property)
120{
121 std::string style = "filled";
122 if (property.isOriginal)
123 {
124 style += ",bold";
125 }
126 if (property.isIncomplete)
127 {
128 style += ",dashed";
129 }
130 else if (property.isTruncated && property.isOrphaned)
131 {
132 style += ",dashed";
133 }
134 return style;
135}

References DotDirProperty::isIncomplete, DotDirProperty::isOriginal, DotDirProperty::isOrphaned and DotDirProperty::isTruncated.

Referenced by common_attributes.

isAtMaxDepth()

bool isAtMaxDepth (const DirDef *const directory, const int startLevel)
static

Checks, if the directory is a the maximum drawn directory level.

Definition at line 168 of file dotdirdeps.cpp.

168static bool isAtMaxDepth(const DirDef *const directory, const int startLevel)
169{
170 return (directory->level() - startLevel) >= Config_getInt(DIR_GRAPH_MAX_DEPTH);
171}

References Config_getInt and DirDef::level.

Referenced by drawTree.

writeDotDirDepGraph()

void writeDotDirDepGraph (TextStream & t, const DirDef * dd, bool linkRelations)

Write DOT code for directory dependency graph.

Code is generated for a directory. Successors (sub-directories) of this directory are recursively drawn. Recursion is limited by DIR_GRAPH_MAX_DEPTH. The dependencies of those directories are drawn.

If a dependee is not part of directory tree above, then the dependency is drawn to the first parent of the dependee, whose parent is an ancestor (sub-directory) of the original directory.

Parameters
t

stream where the DOT code is written to

dd

directory for which the graph is generated for

linkRelations

if true, hyperlinks to the list of file dependencies are added

Definition at line 287 of file dotdirdeps.cpp.

287void writeDotDirDepGraph(TextStream &t,const DirDef *dd,bool linkRelations)
288{
289 DirDefMap dirsInGraph;
290
291 dirsInGraph.emplace(dd->getOutputFileBase().str(),dd);
292
293 std::vector<const DirDef *> usedDirsNotDrawn, usedDirsDrawn;
294 for (const auto& usedDir : dd->usedDirs())
295 {
296 usedDirsNotDrawn.push_back(usedDir->dir());
297 }
298
299 auto moveDrawnDirs = [&usedDirsDrawn,&usedDirsNotDrawn](const std::vector<const DirDef *>::iterator &newEnd)
300 {
301 // usedDirsNotDrawn is split into two segments: [begin()....newEnd-1] and [newEnd....end()]
302 // where the second segment starting at newEnd has been drawn, so append this segment to the usedDirsDrawn list and
303 // remove it from the usedDirsNotDrawn list.
304 std::move(newEnd, std::end(usedDirsNotDrawn), std::back_inserter(usedDirsDrawn));
305 usedDirsNotDrawn.erase(newEnd, usedDirsNotDrawn.end());
306 };
307
308 // if dd has a parent draw it as the outer layer
309 const auto parent = dd->parent();
310 if (parent)
311 {
312 const DotDirProperty parentDirProperty = DotDirPropertyBuilder().
313 makeIncomplete().
314 makeOrphaned(parent->parent()!=nullptr);
315 drawClusterOpening(t, parent, parentDirProperty, dirsInGraph, true, parent->level());
316
317 {
318 // draw all directories which have `dd->parent()` as parent and `dd` as dependent
319 const auto newEnd = std::stable_partition(usedDirsNotDrawn.begin(), usedDirsNotDrawn.end(),
320 [&](const DirDef *const usedDir)
321 {
322 if (dd!=usedDir && dd->parent()==usedDir->parent()) // usedDir and dd share the same parent
323 {
324 const DotDirProperty usedDirProperty = DotDirPropertyBuilder().makeTruncated(usedDir->hasSubdirs());
325 drawDirectory(t, usedDir, usedDirProperty, dirsInGraph, parent->level());
326 return false; // part of the drawn partition
327 }
328 return true; // part of the not-drawn partition
329 });
330 moveDrawnDirs(newEnd);
331 }
332 }
333
334 // draw the directory tree with dd as root
335 DirRelations dependencies;
336 drawTree(dependencies, t, dd, dd->level(), dirsInGraph, true);
337
338 if (parent)
339 {
341 }
342
343 // add nodes for other used directories (i.e. outside of the cluster of directories directly connected to dd)
344 {
345 const auto newEnd = std::stable_partition(usedDirsNotDrawn.begin(), usedDirsNotDrawn.end(),
346 [&](const DirDef *const usedDir) // for each used dir (=directly used or a parent of a directly used dir)
347 {
348 const DirDef *dir=dd;
349 while (dir)
350 {
351 if (dir!=usedDir && dir->parent()==usedDir->parent()) // include if both have the same parent (or no parent)
352 {
353 const DotDirProperty usedDirProperty = DotDirPropertyBuilder().
354 makeOrphaned(usedDir->parent()!=nullptr).
355 makeTruncated(usedDir->hasSubdirs()).
356 makePeripheral();
357 drawDirectory(t, usedDir, usedDirProperty, dirsInGraph, dir->level());
358 return false; // part of the drawn partition
359 }
360 dir=dir->parent();
361 }
362 return true; // part of the not-drawn partition
363 });
364 moveDrawnDirs(newEnd);
365 }
366
367 // add relations between all selected directories
368 {
369 for (const auto &relationPair : dependencies)
370 {
371 const auto &relation = relationPair.first;
372 const bool directRelation = relationPair.second;
373 const auto udir = relation->destination();
374 const auto usedDir = udir->dir();
375 const bool destIsSibling = std::find(std::begin(usedDirsDrawn), std::end(usedDirsDrawn), usedDir) != std::end(usedDirsDrawn);
376 const bool destIsDrawn = dirsInGraph.find(usedDir->getOutputFileBase().str())!=dirsInGraph.end(); // only point to nodes that are in the graph
377 const bool atMaxDepth = isAtMaxDepth(usedDir, dd->level());
378
379 if (destIsSibling || (destIsDrawn && (directRelation || atMaxDepth)))
380 {
381 const auto relationName = relation->getOutputFileBase();
382 const auto dir = relation->source();
383 Doxygen::dirRelations.add(relationName,
384 std::make_unique<DirRelation>(
385 relationName,dir,udir));
386 size_t nrefs = udir->filePairs().size();
387 t << " " << dir->getOutputFileBase() << "->"
388 << usedDir->getOutputFileBase();
389 t << " [headlabel=\"" << nrefs << "\", labeldistance=1.5";
390 if (linkRelations)
391 {
392 QCString fn = relationName;
394 t << " headhref=\"" << fn << "\"";
395 t << " href=\"" << fn << "\"";
396 }
397 t << " color=\"steelblue1\" fontcolor=\"steelblue1\"];\n";
398 }
399 }
400 }
401}

References drawClusterOpening, Definition::getOutputFileBase, DirDef::parent, parent, QCString::str and DirDef::usedDirs.

Referenced by DotDirDeps::computeTheGraph.


Generated via doxygen2docusaurus by Doxygen 1.14.0.