📄 dot.cpp
字号:
//{ // printf("Node %s color=%d (c=%d,p=%d)\n", // n->m_label.data(),n->m_subgraphId, // n->m_children?n->m_children->count():0, // n->m_parents?n->m_parents->count():0); //}}DotGfxHierarchyTable::~DotGfxHierarchyTable(){ DotNode *n = m_rootNodes->first(); while (n) { DotNode *oldNode=n; n=m_rootNodes->next(); deleteNodes(oldNode); } delete m_rootNodes; delete m_usedNodes; delete m_rootSubgraphs;}//--------------------------------------------------------------------int DotClassGraph::m_curNodeNumber;void DotClassGraph::addClass(ClassDef *cd,DotNode *n,int prot, const char *label,int distance,const char *usedName,const char *templSpec,bool base){ if (Config_getBool("HIDE_UNDOC_CLASSES") && !cd->isLinkable()) return; int edgeStyle = (label || prot==EdgeInfo::Orange) ? EdgeInfo::Dashed : EdgeInfo::Solid; QCString className; if (usedName) // name is a typedef { className=usedName; } else if (templSpec) // name has a template part { className=insertTemplateSpecifierInScope(cd->name(),templSpec); } else // just a normal name { className=cd->displayName(); } //printf("DotClassGraph::addClass(class=`%s',parent=%s,prot=%d,label=%s,dist=%d,usedName=%s,templSpec=%s,base=%d)\n", // className.data(),n->m_label.data(),prot,label,distance,usedName,templSpec,base); DotNode *bn = m_usedNodes->find(className); if (bn) // class already inserted { if (base) { n->addChild(bn,prot,edgeStyle,label); bn->addParent(n); } else { bn->addChild(n,prot,edgeStyle,label); n->addParent(bn); } bn->setDistance(distance); //printf(" add exiting node %s of %s\n",bn->m_label.data(),n->m_label.data()); } else // new class { QCString displayName=className; if (Config_getBool("HIDE_SCOPE_NAMES")) displayName=stripScope(displayName); QCString tmp_url; if (cd->isLinkable()) { tmp_url=cd->getReference()+"$"+cd->getOutputFileBase(); } bn = new DotNode(m_curNodeNumber++, displayName, tmp_url.data(), distance ); if (distance>m_maxDistance) m_maxDistance=distance; if (base) { n->addChild(bn,prot,edgeStyle,label); bn->addParent(n); } else { bn->addChild(n,prot,edgeStyle,label); n->addParent(bn); } m_usedNodes->insert(className,bn); //printf(" add new child node `%s' to %s\n",className.data(),n->m_label.data()); if (distance<m_recDepth) buildGraph(cd,bn,distance+1,base); }}void DotClassGraph::buildGraph(ClassDef *cd,DotNode *n,int distance,bool base){ // ---- Add inheritance relations BaseClassListIterator bcli(base ? *cd->baseClasses() : *cd->subClasses()); BaseClassDef *bcd; for ( ; (bcd=bcli.current()) ; ++bcli ) { //printf("-------- inheritance relation %s->%s templ=`%s'\n", // cd->name().data(),bcd->classDef->name().data(),bcd->templSpecifiers.data()); addClass(bcd->classDef,n,bcd->prot,0,distance,bcd->usedName, bcd->templSpecifiers,base); } if (m_graphType != Inheritance) { // ---- Add usage relations UsesClassDict *dict = m_graphType==Implementation ? cd->usedImplementationClasses() : cd->usedInterfaceClasses(); if (dict) { UsesClassDictIterator ucdi(*dict); UsesClassDef *ucd; for (;(ucd=ucdi.current());++ucdi) { QCString label; QDictIterator<void> dvi(*ucd->accessors); const char *s; bool first=TRUE; for (;(s=dvi.currentKey());++dvi) { if (first) { label=s; first=FALSE; } else { label+=QCString("\\n")+s; } } addClass(ucd->classDef,n,EdgeInfo::Purple,label,distance,0, ucd->templSpecifiers,base); } } } // ---- Add template instantiation relations if (Config_getBool("TEMPLATE_RELATIONS")) { if (base) // template relations for base classes { ClassDef *templMaster=cd->templateMaster(); if (templMaster) { QDictIterator<ClassDef> cli(*templMaster->getTemplateInstances()); ClassDef *templInstance; for (;(templInstance=cli.current());++cli) { if (templInstance==cd) { addClass(templMaster,n,EdgeInfo::Orange,cli.currentKey(),distance,0, 0,TRUE); } } } } else // template relations for super classes { QDict<ClassDef> *templInstances = cd->getTemplateInstances(); if (templInstances) { QDictIterator<ClassDef> cli(*templInstances); ClassDef *templInstance; for (;(templInstance=cli.current());++cli) { addClass(templInstance,n,EdgeInfo::Orange,cli.currentKey(),distance,0, 0,FALSE); } } } }}DotClassGraph::DotClassGraph(ClassDef *cd,GraphType t,int maxRecursionDepth){ //printf("--------------- DotClassGraph::DotClassGraph `%s'\n",cd->displayName().data()); m_graphType = t; m_maxDistance = 0; m_recDepth = maxRecursionDepth; QCString tmp_url=""; if (cd->isLinkable()) tmp_url=cd->getReference()+"$"+cd->getOutputFileBase(); QCString className = cd->displayName(); //if (cd->templateArguments()) //{ // className+=tempArgListToString(cd->templateArguments()); //} m_startNode = new DotNode(m_curNodeNumber++, className, tmp_url.data(), 0, // distance TRUE // is a root node ); m_usedNodes = new QDict<DotNode>(1009); m_usedNodes->insert(className,m_startNode); //ClassSDict::Iterator cli(Doxygen::classSDict); //ClassDef *icd; //for (cli.toFirst();(icd=cli.current());++cli) icd->initTemplateMapping(); //printf("Root node %s\n",cd->name().data()); if (m_recDepth>0) { buildGraph(cd,m_startNode,1,TRUE); if (t==Inheritance) buildGraph(cd,m_startNode,1,FALSE); } m_diskName = cd->getFileBase().copy();}bool DotClassGraph::isTrivial() const{ if (m_graphType==Inheritance) return m_startNode->m_children==0 && m_startNode->m_parents==0; else return m_startNode->m_children==0;}DotClassGraph::~DotClassGraph(){ deleteNodes(m_startNode); delete m_usedNodes;}void writeDotGraph(DotNode *root, GraphOutputFormat format, const QCString &baseName, bool lrRank, bool renderParents, int distance, bool backArrows ){ // generate the graph description for dot //printf("writeDotGraph(%s,%d)\n",baseName.data(),backArrows); QFile f; f.setName(baseName+".dot"); if (f.open(IO_WriteOnly)) { QTextStream t(&f); t << "digraph inheritance" << endl; t << "{" << endl; if (lrRank) { t << " rankdir=LR;" << endl; } root->clearWriteFlag(); root->write(t,format,TRUE,TRUE,distance,backArrows); if (renderParents && root->m_parents) { //printf("rendering parents!\n"); QListIterator<DotNode> dnli(*root->m_parents); DotNode *pn; for (dnli.toFirst();(pn=dnli.current());++dnli) { if (pn->m_distance<=distance) { root->writeArrow(t, format, pn, pn->m_edgeInfo->at(pn->m_children->findRef(root)), FALSE, backArrows ); } pn->write(t,format,TRUE,FALSE,distance,backArrows); } } t << "}" << endl; f.close(); }}static void findMaximalDotGraph(DotNode *root, int maxDist, const QCString &baseName, QDir &thisDir, GraphOutputFormat format, bool lrRank=FALSE, bool renderParents=FALSE, bool backArrows=TRUE ){ bool lastFit; int minDistance=1; int maxDistance=maxDist; int curDistance=maxDistance; int width=0; int height=0; // binary search for the maximal inheritance depth that fits in a reasonable // sized image (dimensions: Config_getInt("MAX_DOT_GRAPH_WIDTH"), Config_getInt("MAX_DOT_GRAPH_HEIGHT")) do { writeDotGraph(root,format,baseName,lrRank,renderParents, curDistance,backArrows); QCString dotArgs(4096); // create annotated dot file dotArgs.sprintf("-Tdot \"%s.dot\" -o \"%s_tmp.dot\"",baseName.data(),baseName.data()); if (iSystem(Config_getString("DOT_PATH")+"dot",dotArgs)!=0) { err("Problems running dot. Check your installation!\n"); return; } // extract bounding box from the result readBoundingBoxDot(baseName+"_tmp.dot",&width,&height); width = width *96/72; // 96 pixels/inch, 72 points/inch height = height*96/72; // 96 pixels/inch, 72 points/inch //printf("Found bounding box (%d,%d) max (%d,%d)\n",width,height, // Config_getInt("MAX_DOT_GRAPH_WIDTH"),Config_getInt("MAX_DOT_GRAPH_HEIGHT")); lastFit=(width<Config_getInt("MAX_DOT_GRAPH_WIDTH") && height<Config_getInt("MAX_DOT_GRAPH_HEIGHT")); if (lastFit) // image is small enough { minDistance=curDistance; //printf("Image fits [%d-%d]\n",minDistance,maxDistance); } else { maxDistance=curDistance; //printf("Image does not fit [%d-%d]\n",minDistance,maxDistance); } curDistance=minDistance+(maxDistance-minDistance)/2; //printf("curDistance=%d\n",curDistance); // remove temporary dot file thisDir.remove(baseName+"_tmp.dot"); } while ((maxDistance-minDistance)>1); if (!lastFit) { writeDotGraph(root, format, baseName, lrRank || (curDistance==1 && width>Config_getInt("MAX_DOT_GRAPH_WIDTH")), renderParents, minDistance, backArrows ); }}QCString DotClassGraph::diskName() const{ QCString result=m_diskName.copy(); switch (m_graphType) { case Implementation: result+="_coll_graph"; break; case Interface: result+="_intf_graph"; break; case Inheritance: result+="_inherit_graph"; break; } return result;}QCString DotClassGraph::writeGraph(QTextStream &out, GraphOutputFormat format, const char *path, bool isTBRank, bool generateImageMap){ QDir d(path); // store the original directory if (!d.exists()) { err("Error: Output dir %s does not exist!\n",path); exit(1); } QCString oldDir = convertToQCString(QDir::currentDirPath()); // go to the html output directory (i.e. path) QDir::setCurrent(d.absPath()); QDir thisDir; QCString baseName; QCString mapName; switch (m_graphType) { case Implementation: mapName="coll_map"; break; case Interface: mapName="intf_map"; break; case Inheritance: mapName="inherit_map"; break; } baseName = convertNameToFile(diskName()); findMaximalDotGraph(m_startNode,m_maxDistance,baseName, thisDir,format,!isTBRank,m_graphType==Inheritance);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -