📄 dot.cpp
字号:
/***************************************************************************** * * $Id: dot.cpp,v 1.20 2001/03/19 19:27:40 root Exp $ * * * Copyright (C) 1997-2001 by Dimitri van Heesch. * * Permission to use, copy, modify, and distribute this software and its * documentation under the terms of the GNU General Public License is hereby * granted. No representations are made about the suitability of this software * for any purpose. It is provided "as is" without express or implied warranty. * See the GNU General Public License for more details. * * Documents produced by Doxygen are derivative works derived from the * input used in their production; they are not affected by this license. * */#include <stdlib.h>#include "dot.h"#include "doxygen.h"#include "message.h"#include "util.h"#include "config.h"#include "language.h"#include "scanner.h"#include "defargs.h"#include <qdir.h>#include <qfile.h>#include <qtextstream.h>//--------------------------------------------------------------------/*! mapping from protection levels to color names */static const char *edgeColorMap[] ={ "midnightblue", // Public "darkgreen", // Protected "firebrick4", // Private "darkorchid3", // "use" relation "grey75", // Undocumented "orange" // template relation};static const char *edgeStyleMap[] ={ "solid", // inheritance "dashed" // usage};/*! converts the rectangles in a server site image map into a client * site image map. * \param t the stream to which the result is written. * \param mapName the name of the map file. * \returns TRUE if succesful. */static bool convertMapFile(QTextStream &t,const char *mapName){ QFile f(mapName); if (!f.open(IO_ReadOnly)) { err("Error opening map file %s for inclusion in the docs!\n",mapName); return FALSE; } const int maxLineLen=1024; char buf[maxLineLen]; char url[maxLineLen]; int x1,y1,x2,y2; while (!f.atEnd()) { int numBytes = f.readLine(buf,maxLineLen); buf[numBytes-1]='\0'; //printf("ReadLine `%s'\n",buf); if (strncmp(buf,"rect",4)==0) { sscanf(buf,"rect %s %d,%d %d,%d",url,&x1,&y2,&x2,&y1); char *refPtr = url; char *urlPtr = strchr(url,'$'); //printf("url=`%s'\n",url); if (urlPtr) { QCString *dest; *urlPtr++='\0'; //printf("refPtr=`%s' urlPtr=`%s'\n",refPtr,urlPtr); //printf("Found url=%s coords=%d,%d,%d,%d\n",url,x1,y1,x2,y2); t << "<area "; if (*refPtr!='\0') { t << "doxygen=\"" << refPtr << ":"; if ((dest=Doxygen::tagDestinationDict[refPtr])) t << *dest << "/"; t << "\" "; } t << "href=\""; if (*refPtr!='\0') { if ((dest=Doxygen::tagDestinationDict[refPtr])) t << *dest << "/"; } t << urlPtr << "\" shape=\"rect\" coords=\"" << x1 << "," << y1 << "," << x2 << "," << y2 << "\"" << " alt=\"\">" << endl; } } } return TRUE;}static bool readBoundingBoxDot(const char *fileName,int *width,int *height){ QFile f(fileName); if (!f.open(IO_ReadOnly)) return FALSE; const int maxLineLen=1024; char buf[maxLineLen]; while (!f.atEnd()) { int numBytes = f.readLine(buf,maxLineLen); buf[numBytes-1]='\0'; if (strncmp(buf,"\tgraph [bb",10)==0) { int x,y; if (sscanf(buf,"\tgraph [bb= \"%d,%d,%d,%d\"];",&x,&y,width,height)!=4) { return FALSE; } return TRUE; } } return FALSE;}static bool readBoundingBoxEPS(const char *fileName,int *width,int *height){ QFile f(fileName); if (!f.open(IO_ReadOnly)) return FALSE; const int maxLineLen=1024; char buf[maxLineLen]; while (!f.atEnd()) { int numBytes = f.readLine(buf,maxLineLen); buf[numBytes-1]='\0'; if (strncmp(buf,"%%BoundingBox: ",15)==0) { int x,y; if (sscanf(buf,"%%%%BoundingBox: %d %d %d %d",&x,&y,width,height)!=4) { return FALSE; } return TRUE; } } return FALSE;}/*! returns TRUE if class cd is a leaf (i.e. has no visible children) */static bool isLeaf(ClassDef *cd){ BaseClassList *bcl = cd->subClasses(); if (bcl->count()>0) // class has children, check their visibility { BaseClassListIterator bcli(*bcl); BaseClassDef *bcd; for ( ; (bcd=bcli.current()); ++bcli ) { ClassDef *bClass = bcd->classDef; //if (bClass->isLinkable() || !isLeaf(bClass)) return FALSE; // if class is not a leaf if (!isLeaf(bClass)) return FALSE; // or class is not documented in this project if (!Config_getBool("ALLEXTERNALS") && !bClass->isLinkableInProject()) return FALSE; // or class is not documented and all ALLEXTERNALS = YES if (Config_getBool("ALLEXTERNALS") && !bClass->isLinkable()) return FALSE; } } return TRUE;}//--------------------------------------------------------------------class DotNodeList : public QList<DotNode>{ public: DotNodeList() : QList<DotNode>() {} ~DotNodeList() {} int compareItems(GCI item1,GCI item2) { return stricmp(((DotNode *)item1)->m_label,((DotNode *)item2)->m_label); }};//--------------------------------------------------------------------/*! helper function that deletes all nodes in a connected graph, given * one of the graph's nodes */static void deleteNodes(DotNode *node){ static DotNodeList deletedNodes; deletedNodes.setAutoDelete(TRUE); node->deleteNode(deletedNodes); // collect nodes to be deleted. deletedNodes.clear(); // actually remove the nodes.}DotNode::DotNode(int n,const char *lab,const char *url,int distance,bool isRoot) : m_number(n), m_label(lab), m_url(url), m_isRoot(isRoot){ m_children = 0; m_edgeInfo = 0; m_parents = 0; m_subgraphId=-1; m_deleted=FALSE; m_written=FALSE; m_hasDoc=FALSE; m_distance = distance;}DotNode::~DotNode(){ delete m_children; delete m_parents; delete m_edgeInfo;}void DotNode::setDistance(int distance){ if (distance<m_distance) m_distance=distance;}void DotNode::addChild(DotNode *n, int edgeColor, int edgeStyle, const char *edgeLab, const char *edgeURL, int edgeLabCol ){ if (m_children==0) { m_children = new QList<DotNode>; m_edgeInfo = new QList<EdgeInfo>; m_edgeInfo->setAutoDelete(TRUE); } m_children->append(n); EdgeInfo *ei = new EdgeInfo; ei->m_color = edgeColor; ei->m_style = edgeStyle; ei->m_label = edgeLab; ei->m_url = edgeURL; if (edgeLabCol==-1) ei->m_labColor=edgeColor; else ei->m_labColor=edgeLabCol; m_edgeInfo->append(ei);}void DotNode::addParent(DotNode *n){ if (m_parents==0) { m_parents = new QList<DotNode>; } m_parents->append(n);}void DotNode::removeChild(DotNode *n){ if (m_children) m_children->remove(n);}void DotNode::removeParent(DotNode *n){ if (m_parents) m_parents->remove(n);}void DotNode::deleteNode(DotNodeList &deletedList){ if (m_deleted) return; // avoid recursive loops in case the graph has cycles m_deleted=TRUE; if (m_parents!=0) // delete all parent nodes of this node { QListIterator<DotNode> dnlip(*m_parents); DotNode *pn; for (dnlip.toFirst();(pn=dnlip.current());++dnlip) { //pn->removeChild(this); pn->deleteNode(deletedList); } } if (m_children!=0) // delete all child nodes of this node { QListIterator<DotNode> dnlic(*m_children); DotNode *cn; for (dnlic.toFirst();(cn=dnlic.current());++dnlic) { //cn->removeParent(this); cn->deleteNode(deletedList); } } // add this node to the list of deleted nodes. deletedList.append(this);}static QCString convertLabel(const QCString &l){ QCString result; const char *p=l.data(); char c; while ((c=*p++)) { if (c=='\\') result+="\\\\"; else result+=c; } return result;}void DotNode::writeBox(QTextStream &t, GraphOutputFormat format, bool hasNonReachableChildren){ const char *labCol = m_url.isEmpty() ? "grey75" : // non link ( (hasNonReachableChildren) ? "red" : "black" ); t << " Node" << m_number << " [shape=\"box\",label=\"" << convertLabel(m_label) << "\",fontsize=10,height=0.2,width=0.4"; if (format==GIF) t << ",fontname=\"doxfont\""; t << ",color=\"" << labCol << "\""; if (m_isRoot) { t << ",style=\"filled\" fontcolor=\"white\""; } else if (!m_url.isEmpty()) { t << ",URL=\"" << m_url << ".html\""; } t << "];" << endl; }void DotNode::writeArrow(QTextStream &t, GraphOutputFormat format, DotNode *cn, EdgeInfo *ei, bool topDown, bool pointBack ){ t << " Node"; if (topDown) t << cn->number(); else t << m_number; t << " -> Node"; if (topDown) t << m_number; else t << cn->number(); t << " ["; if (pointBack) t << "dir=back,"; t << "color=\"" << edgeColorMap[ei->m_color] << "\",fontsize=10,style=\"" << edgeStyleMap[ei->m_style] << "\""; if (!ei->m_label.isEmpty()) { t << ",label=\"" << ei->m_label << "\""; } if (format==GIF) t << ",fontname=\"doxfont\""; t << "];" << endl; }void DotNode::write(QTextStream &t, GraphOutputFormat format, bool topDown, bool toChildren, int distance, bool backArrows ){ //printf("DotNode::write(%d) name=%s\n",distance,m_label.data()); if (m_written) return; // node already written to the output if (m_distance>distance) return; QList<DotNode> *nl = toChildren ? m_children : m_parents; bool hasNonReachableChildren=FALSE; if (m_distance==distance && nl) { QListIterator<DotNode> dnli(*nl); DotNode *cn; for (dnli.toFirst();(cn=dnli.current());++dnli) { if (cn->m_distance>distance) hasNonReachableChildren=TRUE; } } writeBox(t,format,hasNonReachableChildren); m_written=TRUE; if (nl) { if (toChildren) { QListIterator<DotNode> dnli1(*nl); QListIterator<EdgeInfo> dnli2(*m_edgeInfo); DotNode *cn; for (dnli1.toFirst();(cn=dnli1.current());++dnli1,++dnli2) { if (cn->m_distance<=distance) { writeArrow(t,format,cn,dnli2.current(),topDown,backArrows); }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -