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