/****************************************************************************** * * $Id: dot.h,v 1.14 2001/03/19 19:27:40 root Exp $ * * * Copyright (C) 1997-2011 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. * */ #ifndef _DOT_H #define _DOT_H #include "qtbc.h" #include #include #include #include #include #include #include "sortdict.h" class ClassDef; class FileDef; class FTextStream; class DotNodeList; class ClassSDict; class MemberDef; class Definition; class DirDef; class GroupDef; class DotGroupCollaboration; class DotRunnerQueue; enum GraphOutputFormat { BITMAP , EPS }; /** @brief Attributes of an edge of a dot graph */ struct EdgeInfo { enum Colors { Blue=0, Green=1, Red=2, Purple=3, Grey=4, Orange=5 }; enum Styles { Solid=0, Dashed=1 }; EdgeInfo() : m_color(0), m_style(0), m_labColor(0) {} ~EdgeInfo() {} int m_color; int m_style; QCString m_label; QCString m_url; int m_labColor; }; /** @brief A node in a dot graph */ class DotNode { public: enum GraphType { Dependency, Inheritance, Collaboration, Hierarchy, CallGraph }; enum TruncState { Unknown, Truncated, Untruncated }; DotNode(int n,const char *lab,const char *tip,const char *url, bool rootNode=FALSE,ClassDef *cd=0); ~DotNode(); void addChild(DotNode *n, int edgeColor=EdgeInfo::Purple, int edgeStyle=EdgeInfo::Solid, const char *edgeLab=0, const char *edgeURL=0, int edgeLabCol=-1 ); void addParent(DotNode *n); void deleteNode(DotNodeList &deletedList,SDict *skipNodes=0); void removeChild(DotNode *n); void removeParent(DotNode *n); int findParent( DotNode *n ); void write(FTextStream &t,GraphType gt,GraphOutputFormat f, bool topDown,bool toChildren,bool backArrows,bool reNumber); int m_subgraphId; void clearWriteFlag(); void writeXML(FTextStream &t,bool isClassGraph); void writeDEF(FTextStream &t); QCString label() const { return m_label; } int number() const { return m_number; } bool isVisible() const { return m_visible; } TruncState isTruncated() const { return m_truncated; } int distance() const { return m_distance; } private: void colorConnectedNodes(int curColor); void writeBox(FTextStream &t,GraphType gt,GraphOutputFormat f, bool hasNonReachableChildren, bool reNumber=FALSE); void writeArrow(FTextStream &t,GraphType gt,GraphOutputFormat f,DotNode *cn, EdgeInfo *ei,bool topDown, bool pointBack=TRUE, bool reNumber=FALSE); void setDistance(int distance); const DotNode *findDocNode() const; // only works for acyclic graphs! void markAsVisible(bool b=TRUE) { m_visible=b; } void markAsTruncated(bool b=TRUE) { m_truncated=b ? Truncated : Untruncated; } int m_number; QCString m_label; //!< label text QCString m_tooltip; //!< node's tooltip QCString m_url; //!< url of the node (format: remote$local) QList *m_parents; //!< list of parent nodes (incoming arrows) QList *m_children; //!< list of child nodes (outgoing arrows) QList *m_edgeInfo; //!< edge info for each child bool m_deleted; //!< used to mark a node as deleted bool m_written; //!< used to mark a node as written bool m_hasDoc; //!< used to mark a node as documented bool m_isRoot; //!< indicates if this is a root node ClassDef * m_classDef; //!< class representing this node (can be 0) bool m_visible; //!< is the node visible in the output TruncState m_truncated; //!< does the node have non-visible children/parents int m_distance; //!< shortest path to the root node friend class DotGfxHierarchyTable; friend class DotClassGraph; friend class DotInclDepGraph; friend class DotNodeList; friend class DotCallGraph; friend class DotGroupCollaboration; friend QCString computeMd5Signature( DotNode *root, GraphType gt, GraphOutputFormat f, bool lrRank, bool renderParents, bool backArrows, QCString &graphStr ); }; inline int DotNode::findParent( DotNode *n ) { if( !m_parents ) return -1; return m_parents->find(n); } /** @brief Represents a graphical class hierarchy */ class DotGfxHierarchyTable { public: DotGfxHierarchyTable(); ~DotGfxHierarchyTable(); void writeGraph(FTextStream &t,const char *path, const char *fileName) const; private: void addHierarchy(DotNode *n,ClassDef *cd,bool hide); void addClassList(ClassSDict *cl); QList *m_rootNodes; QDict *m_usedNodes; static int m_curNodeNumber; DotNodeList *m_rootSubgraphs; }; /** @brief Representation of a class inheritance or dependency graph */ class DotClassGraph { public: DotClassGraph(ClassDef *cd,DotNode::GraphType t); ~DotClassGraph(); bool isTrivial() const; bool isTooBig() const; QCString writeGraph(FTextStream &t,GraphOutputFormat f,const char *path, const char *fileName, const char *relPath, bool TBRank=TRUE,bool imageMap=TRUE) const; void writeXML(FTextStream &t); void writeDEF(FTextStream &t); QCString diskName() const; private: void buildGraph(ClassDef *cd,DotNode *n,bool base,int distance); bool determineVisibleNodes(DotNode *rootNode,int maxNodes,bool includeParents); void determineTruncatedNodes(QList &queue,bool includeParents); void addClass(ClassDef *cd,DotNode *n,int prot,const char *label, const char *usedName,const char *templSpec, bool base,int distance); DotNode * m_startNode; QDict * m_usedNodes; static int m_curNodeNumber; DotNode::GraphType m_graphType; QCString m_diskName; bool m_lrRank; }; /** @brief Representation of an include dependency graph */ class DotInclDepGraph { public: DotInclDepGraph(FileDef *fd,bool inverse); ~DotInclDepGraph(); QCString writeGraph(FTextStream &t, GraphOutputFormat f, const char *path,const char *fileName,const char *relPath, bool writeImageMap=TRUE) const; bool isTrivial() const; bool isTooBig() const; QCString diskName() const; void writeXML(FTextStream &t); private: void buildGraph(DotNode *n,FileDef *fd,int distance); void determineVisibleNodes(QList &queue,int &maxNodes); void determineTruncatedNodes(QList &queue); DotNode *m_startNode; QDict *m_usedNodes; static int m_curNodeNumber; QCString m_diskName; int m_maxDistance; bool m_inverse; }; /** @brief Representation of an call graph */ class DotCallGraph { public: DotCallGraph(MemberDef *md,bool inverse); ~DotCallGraph(); QCString writeGraph(FTextStream &t, GraphOutputFormat f, const char *path,const char *fileName, const char *relPath,bool writeImageMap=TRUE) const; void buildGraph(DotNode *n,MemberDef *md,int distance); bool isTrivial() const; bool isTooBig() const; void determineVisibleNodes(QList &queue, int &maxNodes); void determineTruncatedNodes(QList &queue); private: DotNode *m_startNode; static int m_curNodeNumber; QDict *m_usedNodes; int m_maxDistance; int m_recDepth; bool m_inverse; QCString m_diskName; Definition * m_scope; }; /** @brief Representation of an directory dependency graph */ class DotDirDeps { public: DotDirDeps(DirDef *dir); ~DotDirDeps(); bool isTrivial() const; QCString writeGraph(FTextStream &out, GraphOutputFormat format, const char *path, const char *fileName, const char *relPath, bool writeImageMap=TRUE) const; private: DirDef *m_dir; }; /** @brief Representation of a group collaboration graph */ class DotGroupCollaboration { public : enum EdgeType { tmember = 0, tclass, tnamespace, tfile, tpages, tdir, thierarchy }; class Link { public: Link(const QCString lab,const QCString &u) : label(lab), url(u) {} QCString label; QCString url; }; class Edge { public : Edge(DotNode *start,DotNode *end,EdgeType type) : pNStart(start), pNEnd(end), eType(type) { links.setAutoDelete(TRUE); } DotNode* pNStart; DotNode* pNEnd; EdgeType eType; QList links; void write( FTextStream &t ) const; }; DotGroupCollaboration(GroupDef* gd); ~DotGroupCollaboration(); QCString writeGraph(FTextStream &t, GraphOutputFormat format, const char *path,const char *fileName,const char *relPath, bool writeImageMap=TRUE) const; void buildGraph(GroupDef* gd); bool isTrivial() const; private : void addCollaborationMember( Definition* def, QCString& url, EdgeType eType ); void addMemberList( class MemberList* ml ); void writeGraphHeader(FTextStream &t) const; Edge* addEdge( DotNode* _pNStart, DotNode* _pNEnd, EdgeType _eType, const QCString& _label, const QCString& _url ); DotNode *m_rootNode; int m_curNodeId; QDict *m_usedNodes; QCString m_diskName; QList m_edges; }; /** @brief Helper class to run dot from doxygen. */ class DotRunner { public: struct CleanupItem { QCString path; QCString file; }; /** Creates a runner for a dot \a file. */ DotRunner(const QCString &file,const QCString &fontPath,bool checkResult, const QCString &imageName = QCString()); /** Adds an additional job to the run. * Performing multiple jobs one file can be faster. */ void addJob(const char *format,const char *output); void addPostProcessing(const char *cmd,const char *args); void preventCleanUp() { m_cleanUp = FALSE; } /** Runs dot for all jobs added. */ bool run(); CleanupItem cleanup() const { return m_cleanupItem; } private: QList m_jobs; QCString m_postArgs; QCString m_postCmd; QCString m_file; QCString m_path; bool m_checkResult; QCString m_imageName; bool m_cleanUp; CleanupItem m_cleanupItem; }; /** @brief Helper class to insert a set of map file into an output file */ class DotFilePatcher { public: struct Map { QCString mapFile; QCString relPath; bool urlOnly; QCString context; QCString label; }; DotFilePatcher(const char *patchFile); int addMap(const QCString &mapFile,const QCString &relPath, bool urlOnly,const QCString &context,const QCString &label); int addFigure(const QCString &baseName, const QCString &figureName,bool heightCheck); int addSVGConversion(const QCString &relPath,bool urlOnly,const QCString &context); int addSVGObject(const QCString &baseName, const QCString &figureName, const QCString &relPath); bool run(); private: QList m_maps; QCString m_patchFile; }; class DotRunnerQueue { public: void enqueue(DotRunner *runner); DotRunner *dequeue(); uint count() const; private: QWaitCondition m_bufferNotEmpty; QQueue m_queue; mutable QMutex m_mutex; }; class DotWorkerThread : public QThread { public: DotWorkerThread(int id,DotRunnerQueue *queue); void run(); void cleanup(); private: int m_id; DotRunnerQueue *m_queue; QList m_cleanupItems; }; /** @brief singleton that manages dot relation actions */ class DotManager { public: static DotManager *instance(); void addRun(DotRunner *run); int addMap(const QCString &file,const QCString &mapFile, const QCString &relPath,bool urlOnly, const QCString &context,const QCString &label); int addFigure(const QCString &file,const QCString &baseName, const QCString &figureName,bool heightCheck); int addSVGConversion(const QCString &file,const QCString &relPath, bool urlOnly,const QCString &context); int addSVGObject(const QCString &file,const QCString &baseName, const QCString &figureNAme,const QCString &relPath); bool run(); private: DotManager(); virtual ~DotManager(); QList m_dotRuns; SDict m_dotMaps; static DotManager *m_theInstance; DotRunnerQueue *m_queue; QList m_workers; }; /** Generated a graphs legend page */ void generateGraphLegend(const char *path); void writeDotGraphFromFile(const char *inFile,const char *outDir, const char *outFile,GraphOutputFormat format); void writeDotImageMapFromFile(FTextStream &t, const QCString& inFile, const QCString& outDir, const QCString& relPath,const QCString& baseName, const QCString& context); void writeDotDirDepGraph(FTextStream &t,DirDef *dd); #endif