Doxygen
Loading...
Searching...
No Matches
dotclassgraph.cpp
Go to the documentation of this file.
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 <algorithm>
17
18#include "containers.h"
19#include "dotclassgraph.h"
20#include "dotnode.h"
21#include "textstream.h"
22
23#include "config.h"
24#include "util.h"
25
27 const QCString &label,const QCString &usedName,const QCString &templSpec,bool base,int distance)
28{
29 if (Config_getBool(HIDE_UNDOC_CLASSES) && !cd->isLinkable()) return;
30
32 QCString className;
33 QCString fullName;
34 if (cd->isAnonymous())
35 {
36 className="anonymous:";
37 className+=label;
38 fullName = className;
39 }
40 else if (!usedName.isEmpty()) // name is a typedef
41 {
42 className=usedName;
43 fullName = className;
44 }
45 else if (!templSpec.isEmpty()) // name has a template part
46 {
47 className=insertTemplateSpecifierInScope(cd->displayName(),templSpec);
48 fullName =insertTemplateSpecifierInScope(cd->name(),templSpec);
49 }
50 else // just a normal name
51 {
52 className=cd->displayName();
53 fullName = cd->name();
54 }
55 //printf("DotClassGraph::addClass(class='%s',parent=%s,prot=%d,label=%s,dist=%d,usedName=%s,templSpec=%s,base=%d)\n",
56 // qPrint(className),qPrint(n->label()),prot,label,distance,usedName,templSpec,base);
57 auto it = m_usedNodes.find(fullName.str());
58 if (it!=m_usedNodes.end()) // class already inserted
59 {
60 DotNode *bn = it->second;
61 if (base)
62 {
63 n->addChild(bn,color,edgeStyle,label);
64 bn->addParent(n);
65 }
66 else
67 {
68 bn->addChild(n,color,edgeStyle,label);
69 n->addParent(bn);
70 }
71 bn->setDistance(distance);
72 //printf(" add exiting node %s of %s\n",qPrint(bn->label()),qPrint(n->label()));
73 }
74 else // new class
75 {
76 QCString displayName=className;
77 if (Config_getBool(HIDE_SCOPE_NAMES)) displayName=stripScope(displayName);
78 QCString tmp_url;
79 if (cd->isLinkable() && !cd->isHidden())
80 {
81 tmp_url=cd->getReference()+"$"+cd->getOutputFileBase();
82 if (!cd->anchor().isEmpty())
83 {
84 tmp_url+="#"+cd->anchor();
85 }
86 }
87 QCString tooltip = cd->briefDescriptionAsTooltip();
88 DotNode *bn = new DotNode(this,
89 displayName,
90 tooltip,
91 tmp_url,
92 FALSE, // rootNode
93 cd
94 );
95 if (base)
96 {
97 n->addChild(bn,color,edgeStyle,label);
98 bn->addParent(n);
99 }
100 else
101 {
102 bn->addChild(n,color,edgeStyle,label);
103 n->addParent(bn);
104 }
105 bn->setDistance(distance);
106 m_usedNodes.emplace(fullName.str(),bn);
107 //printf(" add new child node '%s' to %s hidden=%d url=%s\n",
108 // qPrint(className),qPrint(n->label()),cd->isHidden(),qPrint(tmp_url));
109
110 buildGraph(cd,bn,base,distance+1);
111 }
112}
113
115{
116 while (!queue.empty())
117 {
118 DotNode *n = queue.front();
119 queue.pop_front();
120 if (n->isVisible() && n->isTruncated()==DotNode::Unknown)
121 {
122 bool truncated = FALSE;
123 for (const auto &dn : n->children())
124 {
125 if (!dn->isVisible())
126 truncated = TRUE;
127 else
128 queue.push_back(dn);
129 }
130 if (includeParents)
131 {
132 for (const auto &dn : n->parents())
133 {
134 if (!dn->isVisible())
135 truncated = TRUE;
136 else
137 queue.push_back(dn);
138 }
139 }
140 n->markAsTruncated(truncated);
141 }
142 }
143}
144
146 int maxNodes,bool includeParents)
147{
148 DotNodeDeque childQueue;
149 DotNodeDeque parentQueue;
150 std::vector<size_t> childTreeWidth;
151 std::vector<size_t> parentTreeWidth;
152 childQueue.push_back(rootNode);
153 if (includeParents) parentQueue.push_back(rootNode);
154 bool firstNode=TRUE; // flag to force reprocessing rootNode in the parent loop
155 // despite being marked visible in the child loop
156 while ((!childQueue.empty() || !parentQueue.empty()) && maxNodes>0)
157 {
158 if (!childQueue.empty())
159 {
160 DotNode *n = childQueue.front();
161 childQueue.pop_front();
162 size_t distance = n->distance();
163 if (!n->isVisible() && distance<=static_cast<size_t>(Config_getInt(MAX_DOT_GRAPH_DEPTH))) // not yet processed
164 {
165 if (distance>0)
166 {
167 size_t oldSize=childTreeWidth.size();
168 if (distance>oldSize)
169 {
170 childTreeWidth.resize(std::max(childTreeWidth.size(),distance));
171 for (size_t i=oldSize;i<distance;i++) childTreeWidth[i]=0;
172 }
173 childTreeWidth[distance-1]+=n->label().length();
174 }
175 n->markAsVisible();
176 maxNodes--;
177 // add direct children
178 for (const auto &dn : n->children())
179 {
180 childQueue.push_back(dn);
181 }
182 }
183 }
184 if (includeParents && !parentQueue.empty())
185 {
186 DotNode *n = parentQueue.front();
187 parentQueue.pop_front();
188 if ((!n->isVisible() || firstNode) && n->distance()<=Config_getInt(MAX_DOT_GRAPH_DEPTH)) // not yet processed
189 {
190 firstNode=FALSE;
191 size_t distance = n->distance();
192 if (distance>0)
193 {
194 size_t oldSize = parentTreeWidth.size();
195 if (distance>oldSize)
196 {
197 parentTreeWidth.resize(std::max(parentTreeWidth.size(),distance));
198 for (size_t i=oldSize;i<distance;i++) parentTreeWidth[i]=0;
199 }
200 parentTreeWidth[distance-1]+=n->label().length();
201 }
202 n->markAsVisible();
203 maxNodes--;
204 // add direct parents
205 for (const auto &dn : n->parents())
206 {
207 parentQueue.push_back(dn);
208 }
209 }
210 }
211 }
212 if (Config_getBool(UML_LOOK)) return FALSE; // UML graph are always top to bottom
213 size_t maxWidth=0;
214 size_t maxHeight=std::max(childTreeWidth.size(),parentTreeWidth.size());
215 for (size_t i=0;i<childTreeWidth.size();i++)
216 {
217 if (childTreeWidth.at(i)>maxWidth) maxWidth=childTreeWidth.at(i);
218 }
219 for (size_t i=0;i<parentTreeWidth.size();i++)
220 {
221 if (parentTreeWidth.at(i)>maxWidth) maxWidth=parentTreeWidth.at(i);
222 }
223 //printf("max tree width=%d, max tree height=%d\n",maxWidth,maxHeight);
224 return maxWidth>80 && maxHeight<12; // used metric to decide to render the tree
225 // from left to right instead of top to bottom,
226 // with the idea to render very wide trees in
227 // left to right order.
228}
229
231{
232 QCString label;
233 int count=1;
234 int maxLabels=10;
235 auto it = std::begin(ss), e = std::end(ss);
236 if (it!=e) // set not empty
237 {
238 label += (*it++).c_str();
239 for (; it!=e && count < maxLabels ; ++it,++count)
240 {
241 label += '\n';
242 label += (*it).c_str();
243 }
244 if (count==maxLabels) label+="\n...";
245 }
246 return label;
247}
248
249void DotClassGraph::buildGraph(const ClassDef *cd,DotNode *n,bool base,int distance)
250{
251 //printf("DocClassGraph::buildGraph(%s,distance=%d,base=%d)\n",
252 // qPrint(cd->name()),distance,base);
253 // ---- Add inheritance relations
254
256 {
257 for (const auto &bcd : base ? cd->baseClasses() : cd->subClasses())
258 {
259 //printf("-------- inheritance relation %s->%s templ='%s'\n",
260 // qPrint(cd->name()),qPrint(bcd->classDef->name()),qPrint(bcd->templSpecifiers));
261 addClass(bcd.classDef,n,EdgeInfo::protectionToColor(bcd.prot),QCString(),bcd.usedName,bcd.templSpecifiers,base,distance);
262 }
263 }
265 {
266 // ---- Add usage relations
267
268 const UsesClassList &list = base ? cd->usedImplementationClasses() :
270 for (const auto &ucd : list)
271 {
272 //printf("addClass: %s templSpec=%s\n",qPrint(ucd.classDef->name()),qPrint(ucd.templSpecifiers));
273 addClass(ucd.classDef,n,EdgeInfo::Purple,joinLabels(ucd.accessors),QCString(),
274 ucd.templSpecifiers,base,distance);
275 }
276 }
277 if (Config_getBool(TEMPLATE_RELATIONS) && base)
278 {
279 for (const auto &ccd : cd->templateTypeConstraints())
280 {
281 //printf("addClass: %s\n",qPrint(ccd.classDef->name()));
282 addClass(ccd.classDef,n,EdgeInfo::Orange2,joinLabels(ccd.accessors),QCString(),
283 QCString(),TRUE,distance);
284 }
285 }
286
287 // ---- Add template instantiation relations
288
289 if (Config_getBool(TEMPLATE_RELATIONS))
290 {
291 if (base) // template relations for base classes
292 {
293 const ClassDef *templMaster=cd->templateMaster();
294 if (templMaster)
295 {
296 for (const auto &ti : templMaster->getTemplateInstances())
297 if (ti.classDef==cd)
298 {
299 addClass(templMaster,n,EdgeInfo::Orange,ti.templSpec,QCString(),QCString(),TRUE,distance);
300 }
301 }
302 }
303 else // template relations for super classes
304 {
305 for (const auto &ti : cd->getTemplateInstances())
306 {
307 addClass(ti.classDef,n,EdgeInfo::Orange,ti.templSpec,QCString(),QCString(),FALSE,distance);
308 }
309 }
310 }
311}
312
314{
315 //printf("--------------- DotClassGraph::DotClassGraph '%s'\n",qPrint(cd->displayName()));
316 m_graphType = t;
317 QCString tmp_url="";
318 if (cd->isLinkable() && !cd->isHidden())
319 {
320 tmp_url=cd->getReference()+"$"+cd->getOutputFileBase();
321 if (!cd->anchor().isEmpty())
322 {
323 tmp_url+="#"+cd->anchor();
324 }
325 }
326 QCString className = cd->displayName();
327 QCString tooltip = cd->briefDescriptionAsTooltip();
328 m_startNode = new DotNode(this,
329 className,
330 tooltip,
331 tmp_url,
332 TRUE, // is a root node
333 cd
334 );
335 m_startNode->setDistance(0);
336 m_usedNodes.emplace(className.str(),m_startNode);
337
340
342 DotNodeDeque openNodeQueue;
343 openNodeQueue.push_back(m_startNode);
345
348}
349
351{
353 return m_startNode->children().empty() && m_startNode->parents().empty();
354 else
355 return !Config_getBool(UML_LOOK) && m_startNode->children().empty();
356}
357
359{
360 return numNodes()>=Config_getInt(DOT_GRAPH_MAX_NODES);
361}
362
364{
365 size_t numNodes = 0;
366 numNodes+= m_startNode->children().size();
368 {
369 numNodes+= m_startNode->parents().size();
370 }
371 return static_cast<int>(numNodes);
372}
373
378
380{
381 switch (m_graphType)
382 {
384 return m_collabFileName;
385 break;
387 return m_inheritFileName;
388 break;
389 default:
390 ASSERT(0);
391 break;
392 }
393 return "";
394}
395
397{
402 m_lrRank ? "LR" : "",
404 TRUE,
405 m_startNode->label(),
407 );
408}
409
411{
412 QCString mapName;
413 switch (m_graphType)
414 {
416 mapName="coll_map";
417 break;
419 mapName="inherit_map";
420 break;
421 default:
422 ASSERT(0);
423 break;
424 }
425
426 return escapeCharsInString(m_startNode->label(),FALSE)+"_"+escapeCharsInString(mapName,FALSE);
427}
428
430{
431 switch (m_graphType)
432 {
434 return "Collaboration graph";
435 break;
437 return "Inheritance graph";
438 break;
439 default:
440 ASSERT(0);
441 break;
442 }
443 return "";
444}
445
447 GraphOutputFormat graphFormat,
448 EmbeddedOutputFormat textFormat,
449 const QCString &path,
450 const QCString &fileName,
451 const QCString &relPath,
452 bool /*isTBRank*/,
453 bool generateImageMap,
454 int graphId)
455{
456 return DotGraph::writeGraph(out, graphFormat, textFormat, path, fileName, relPath, generateImageMap, graphId);
457}
458
459//--------------------------------------------------------------------
460
462{
463 for (const auto &[name,node] : m_usedNodes)
464 {
465 node->writeXML(t,TRUE);
466 }
467}
468
470{
471 for (const auto &[name,node] : m_usedNodes)
472 {
473 node->writeDocbook(t,TRUE);
474 }
475}
476
478{
479 for (const auto &[name,node] : m_usedNodes)
480 {
481 node->writeDEF(t);
482 }
483}
A abstract class representing of a compound symbol.
Definition classdef.h:104
virtual const BaseClassList & baseClasses() const =0
Returns the list of base classes from which this class directly inherits.
virtual const TemplateInstanceList & getTemplateInstances() const =0
Returns a sorted dictionary with all template instances found for this template class.
virtual const UsesClassList & usedImplementationClasses() const =0
virtual QCString inheritanceGraphFileName() const =0
returns the file name to use for the inheritance graph
virtual QCString collaborationGraphFileName() const =0
returns the file name to use for the collaboration graph
virtual const ConstraintClassList & templateTypeConstraints() const =0
virtual const UsesClassList & usedByImplementationClasses() const =0
virtual const ClassDef * templateMaster() const =0
Returns the template master of which this class is an instance.
virtual const BaseClassList & subClasses() const =0
Returns the list of sub classes that directly derive from this class.
virtual bool isLinkable() const =0
virtual QCString anchor() const =0
virtual QCString briefDescriptionAsTooltip() const =0
virtual bool isAnonymous() const =0
virtual bool isHidden() const =0
virtual QCString getReference() const =0
virtual QCString displayName(bool includeScope=TRUE) const =0
virtual QCString getOutputFileBase() const =0
virtual const QCString & name() const =0
QCString writeGraph(TextStream &t, GraphOutputFormat gf, EmbeddedOutputFormat ef, const QCString &path, const QCString &fileName, const QCString &relPath, bool TBRank=TRUE, bool imageMap=TRUE, int graphId=-1)
DotNodeMap m_usedNodes
void writeDocbook(TextStream &t)
void writeXML(TextStream &t)
QCString getBaseName() const override
bool isTooBig() const
DotClassGraph(const ClassDef *cd, GraphType t)
DotNode * m_startNode
GraphType m_graphType
bool determineVisibleNodes(DotNode *rootNode, int maxNodes, bool includeParents)
QCString m_inheritFileName
QCString getMapLabel() const override
~DotClassGraph() override
bool isTrivial() const
void computeTheGraph() override
void determineTruncatedNodes(DotNodeDeque &queue, bool includeParents)
int numNodes() const
void addClass(const ClassDef *cd, DotNode *n, EdgeInfo::Colors color, const QCString &label, const QCString &usedName, const QCString &templSpec, bool base, int distance)
void writeDEF(TextStream &t)
void buildGraph(const ClassDef *cd, DotNode *n, bool base, int distance)
QCString getImgAltText() const override
QCString m_collabFileName
static void computeGraph(DotNode *root, GraphType gt, GraphOutputFormat format, const QCString &rank, bool renderParents, bool backArrows, const QCString &title, QCString &graphStr)
Definition dotgraph.cpp:306
GraphOutputFormat m_graphFormat
Definition dotgraph.h:85
QCString m_theGraph
Definition dotgraph.h:95
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:115
friend class DotNode
Definition dotgraph.h:36
int distance() const
Definition dotnode.h:106
void setDistance(int distance)
Definition dotnode.cpp:366
void markAsVisible(bool b=TRUE)
Definition dotnode.h:120
DotNode & markAsTruncated(bool b=TRUE)
Definition dotnode.h:121
static void deleteNodes(DotNode *node)
Definition dotnode.cpp:380
void addParent(DotNode *n)
Definition dotnode.cpp:331
bool isVisible() const
Definition dotnode.h:104
@ Unknown
Definition dotnode.h:76
void addChild(DotNode *n, EdgeInfo::Colors edgeColor=EdgeInfo::Purple, EdgeInfo::Styles edgeStyle=EdgeInfo::Solid, const QCString &edgeLab=QCString(), const QCString &edgeURL=QCString(), int edgeLabCol=-1)
Definition dotnode.cpp:314
const DotNodeRefVector & parents() const
Definition dotnode.h:123
const DotNodeRefVector & children() const
Definition dotnode.h:122
TruncState isTruncated() const
Definition dotnode.h:105
QCString label() const
Definition dotnode.h:102
@ Solid
Definition dotnode.h:36
@ Dashed
Definition dotnode.h:36
static constexpr Colors protectionToColor(Protection prot)
Definition dotnode.h:44
@ Purple
Definition dotnode.h:35
@ Orange2
Definition dotnode.h:35
@ Orange
Definition dotnode.h:35
This is an alternative implementation of QCString.
Definition qcstring.h:101
size_t length() const
Returns the length of the string, not counting the 0-terminator.
Definition qcstring.h:153
bool isEmpty() const
Returns TRUE iff the string is empty.
Definition qcstring.h:150
const std::string & str() const
Definition qcstring.h:526
Text streaming class that buffers data.
Definition textstream.h:36
#define Config_getInt(name)
Definition config.h:34
#define Config_getBool(name)
Definition config.h:33
std::set< std::string > StringSet
Definition containers.h:31
static QCString joinLabels(const StringSet &ss)
GraphType
Definition dotgraph.h:31
@ Collaboration
Definition dotgraph.h:31
@ Inheritance
Definition dotgraph.h:31
EmbeddedOutputFormat
Definition dotgraph.h:30
GraphOutputFormat
Definition dotgraph.h:29
#define TRUE
Definition qcstring.h:37
#define FALSE
Definition qcstring.h:34
#define ASSERT(x)
Definition qcstring.h:39
QCString insertTemplateSpecifierInScope(const QCString &scope, const QCString &templ)
Definition util.cpp:4100
QCString escapeCharsInString(const QCString &name, bool allowDots, bool allowUnderscore)
Definition util.cpp:3684
QCString stripScope(const QCString &name)
Definition util.cpp:4133
A bunch of utility functions.