Doxygen
Loading...
Searching...
No Matches
dotdirdeps.cpp File Reference
#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>
+ Include dependency graph for dotdirdeps.cpp:

Go to the source code of this file.

Classes

struct  DotDirProperty
 Properties are used to format the directories in the graph distinctively. More...
 
class  DotDirPropertyBuilder
 Builder helper to create instances of the DotDirProperty struct. More...
 

Typedefs

using DirDefMap = std::map<std::string,const DirDef *>
 
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.
 

Functions

static QCString getDirectoryBackgroundColor (int depthIndex)
 Returns a DOT color name according to the directory depth.
 
static const char * getDirectoryBorderColor (const DotDirProperty &property)
 Returns a DOT color name according to the directory properties.
 
static std::string getDirectoryBorderStyle (const DotDirProperty &property)
 Returns a DOT node style according to the directory properties.
 
static TextStreamcommon_attributes (TextStream &t, const DirDef *const dir, const DotDirProperty &prop)
 
static void drawDirectory (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.
 
static bool isAtMaxDepth (const DirDef *const directory, const int startLevel)
 Checks, if the directory is a the maximum drawn directory level.
 
static void drawClusterOpening (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.
 
static void drawClusterClosing (TextStream &t)
 
static void addDependencies (DirRelations &dependencies, const DirDef *const srcDir, bool isLeaf)
 Assembles a list of the directory relations and whether or not they result from "inheritance".
 
static void drawTree (DirRelations &dependencies, TextStream &t, const DirDef *const directory, int startLevel, DirDefMap &directoriesInGraph, const bool isTreeRoot)
 Recursively draws directory tree.
 
void writeDotDirDepGraph (TextStream &t, const DirDef *dd, bool linkRelations)
 Write DOT code for directory dependency graph.
 

Typedef Documentation

◆ DirDefMap

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

Definition at line 34 of file dotdirdeps.cpp.

◆ 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.

Function Documentation

◆ addDependencies()

static 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
dependenciesArray to add the dependencies to.
srcDiris the source of the dependency.
isLeaftrue, if no children are drawn for this directory.

Definition at line 215 of file dotdirdeps.cpp.

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}
virtual int dirIndex() const =0
virtual const UsedDirLinkedMap & usedDirs() const =0
This is an alternative implementation of QCString.
Definition qcstring.h:101
QCString & sprintf(const char *format,...)
Definition qcstring.cpp:29

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

Referenced by drawTree().

◆ common_attributes()

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

Definition at line 137 of file dotdirdeps.cpp.

138{
139 QCString url = dir->getOutputFileBase();
141 return t <<
142 "style=\"" << getDirectoryBorderStyle(prop) << "\", "
143 "URL=\"" << url << "\","
144 "tooltip=\"" << escapeTooltip(dir->briefDescriptionAsTooltip()) << "\"";
145}
virtual QCString briefDescriptionAsTooltip() const =0
virtual QCString getOutputFileBase() const =0
static std::string getDirectoryBorderStyle(const DotDirProperty &property)
Returns a DOT node style according to the directory properties.
QCString escapeTooltip(const QCString &tooltip)
Definition dotnode.cpp:99
void addHtmlExtensionIfMissing(QCString &fName)
Definition util.cpp:5243

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

Referenced by drawClusterOpening(), and drawDirectory().

◆ drawClusterClosing()

static void drawClusterClosing ( TextStream & t)
static

Definition at line 204 of file dotdirdeps.cpp.

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

Referenced by drawTree().

◆ drawClusterOpening()

static 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.

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}
virtual int level() const =0
virtual const QCString shortName() const =0
static QCString convertLabel(const QCString &, bool htmlLike=false)
Definition dotnode.cpp:196
const std::string & str() const
Definition qcstring.h:537
#define Config_getString(name)
Definition config.h:32
static TextStream & common_attributes(TextStream &t, const DirDef *const dir, const DotDirProperty &prop)
static QCString getDirectoryBackgroundColor(int depthIndex)
Returns a DOT color name according to the directory depth.
static const char * getDirectoryBorderColor(const DotDirProperty &property)
Returns a DOT color name according to the directory properties.

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

Referenced by drawTree(), and writeDotDirDepGraph().

◆ drawDirectory()

static 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
[in,out]tstream to which the DOT code is written to
[in]directorywill be mapped to a node in DOT code
[in]propertyare evaluated for formatting
[in,out]directoriesInGraphlists the directories which have been written to the output stream
[in]startLevelcurrent level to calculate relative distances from to determine the background color

Definition at line 155 of file dotdirdeps.cpp.

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()

static 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.

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}
virtual const DirList & subDirs() const =0
virtual bool hasSubdirs() const =0
Builder helper to create instances of the DotDirProperty struct.
DotDirPropertyBuilder & makeOriginal(bool b=true)
static bool isAtMaxDepth(const DirDef *const directory, const int startLevel)
Checks, if the directory is a the maximum drawn directory level.
static void drawClusterClosing(TextStream &t)
static void addDependencies(DirRelations &dependencies, const DirDef *const srcDir, bool isLeaf)
Assembles a list of the directory relations and whether or not they result from "inheritance".
static void drawDirectory(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.
static void drawClusterOpening(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.
static void drawTree(DirRelations &dependencies, TextStream &t, const DirDef *const directory, int startLevel, DirDefMap &directoriesInGraph, const bool isTreeRoot)
Recursively draws directory tree.
Properties are used to format the directories in the graph distinctively.

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

Referenced by drawTree().

◆ getDirectoryBackgroundColor()

static 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}
static void hsl2rgb(double h, double s, double l, double *pRed, double *pGreen, double *pBlue)
Definition image.cpp:368
#define Config_getInt(name)
Definition config.h:34
static constexpr auto hex

References Config_getInt, hex, and ColoredImage::hsl2rgb().

Referenced by drawClusterOpening(), and drawDirectory().

◆ getDirectoryBorderColor()

static 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.

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}
bool isTruncated
true has successors, none is drawn
bool isOrphaned
true if parent is not drawn

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

Referenced by drawClusterOpening(), and drawDirectory().

◆ getDirectoryBorderStyle()

static 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.

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}
bool isOriginal
true if is the directory for which the graph is drawn
bool isIncomplete
true if not all successors of a cluster are drawn

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

Referenced by common_attributes().

◆ isAtMaxDepth()

static 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.

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
tstream where the DOT code is written to
dddirectory for which the graph is generated for
linkRelationsif true, hyperlinks to the list of file dependencies are added

Definition at line 287 of file dotdirdeps.cpp.

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}
A model of a directory symbol.
Definition dirdef.h:110
virtual DirDef * parent() const =0
static DirRelationLinkedMap dirRelations
Definition doxygen.h:130
constexpr DocNodeVariant * parent(DocNodeVariant *n)
returns the parent node of a given node n or nullptr if the node has no parent.
Definition docnode.h:1324
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...
std::map< std::string, const DirDef * > DirDefMap

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

Referenced by DotDirDeps::computeTheGraph().