diff options
author | Dimitri van Heesch <dimitri@stack.nl> | 2014-12-14 15:39:29 (GMT) |
---|---|---|
committer | Dimitri van Heesch <dimitri@stack.nl> | 2014-12-25 12:43:31 (GMT) |
commit | fe818bf8e3a154788a4a180068cfdfbbadd66ff6 (patch) | |
tree | c08545cd15e627b36eef1e0d0a7eb4fa0bb76437 | |
parent | 3ebc431569aa6566389f3f3fc00aae7b8a90e58b (diff) | |
download | Doxygen-fe818bf8e3a154788a4a180068cfdfbbadd66ff6.zip Doxygen-fe818bf8e3a154788a4a180068cfdfbbadd66ff6.tar.gz Doxygen-fe818bf8e3a154788a4a180068cfdfbbadd66ff6.tar.bz2 |
Added graphical hierarchy support to template engine
-rw-r--r-- | src/context.cpp | 573 | ||||
-rw-r--r-- | src/context.h | 30 | ||||
-rw-r--r-- | src/dot.cpp | 211 | ||||
-rw-r--r-- | src/dot.h | 16 | ||||
-rw-r--r-- | src/template.cpp | 29 | ||||
-rw-r--r-- | templates/html/doxygen.css | 11 | ||||
-rw-r--r-- | templates/html/htmlclasses.tpl | 40 | ||||
-rw-r--r-- | templates/html/htmlgraphhierarchy.tpl | 13 | ||||
-rw-r--r-- | templates/html/htmlhierarchy.tpl | 17 | ||||
-rw-r--r-- | templates/html/htmllayout.tpl | 7 | ||||
-rw-r--r-- | templates/html/htmlpage.tpl | 2 | ||||
-rw-r--r-- | templates/html/htmltabs.tpl | 2 |
12 files changed, 557 insertions, 394 deletions
diff --git a/src/context.cpp b/src/context.cpp index 06bc14c..ae5d5bc 100644 --- a/src/context.cpp +++ b/src/context.cpp @@ -666,6 +666,18 @@ class TranslateContext::Private : public PropertyMapper static bool extractAll = Config_getBool("EXTRACT_ALL"); return theTranslator->trNamespaceMemberDescription(extractAll); } + TemplateVariant classHierarchyDescription() const + { + return theTranslator->trClassHierarchyDescription(); + } + TemplateVariant gotoGraphicalHierarchy() const + { + return theTranslator->trGotoGraphicalHierarchy(); + } + TemplateVariant gotoTextualHierarchy() const + { + return theTranslator->trGotoTextualHierarchy(); + } TemplateVariant classMembersDescription() const { static bool extractAll = Config_getBool("EXTRACT_ALL"); @@ -1012,6 +1024,12 @@ class TranslateContext::Private : public PropertyMapper addProperty("macros", this,&Private::macros); //%% string namespaceMembersDescription addProperty("namespaceMembersDescription",this,&Private::namespaceMembersDescription); + //%% string classHierarchyDescription + addProperty("classHierarchyDescription",this,&Private::classHierarchyDescription); + //%% string gotoGraphicalHierarchy + addProperty("gotoGraphicalHierarchy",this,&Private::gotoGraphicalHierarchy); + //%% string gotoTextualHierarchy + addProperty("gotoTextualHierarchy",this,&Private::gotoTextualHierarchy); m_javaOpt = Config_getBool("OPTIMIZE_OUTPUT_JAVA"); m_fortranOpt = Config_getBool("OPTIMIZE_FOR_FORTRAN"); @@ -4822,194 +4840,74 @@ TemplateVariant ClassIndexContext::get(const char *n) const //------------------------------------------------------------------------ -//%% struct ClassInheritanceNode: node in inheritance tree -//%% { -class ClassInheritanceNodeContext::Private : public PropertyMapper +static int computeMaxDepth(const TemplateListIntf *list) { - public: - Private(ClassDef *cd) : m_classDef(cd) + int maxDepth=0; + if (list) + { + TemplateListIntf::ConstIterator *it = list->createIterator(); + TemplateVariant v; + for (it->toFirst();it->current(v);it->toNext()) { - //%% bool is_leaf_node: true if this node does not have any children - addProperty("is_leaf_node",this,&Private::isLeafNode); - //%% ClassInheritance children: list of nested classes/namespaces - addProperty("children",this,&Private::children); - //%% Class class: class info - addProperty("class",this,&Private::getClass); + const TemplateStructIntf *s = v.toStruct(); + TemplateVariant child = s->get("children"); + int d = computeMaxDepth(child.toList())+1; + if (d>maxDepth) maxDepth=d; } - void addChildren(const BaseClassList *bcl,bool hideSuper) - { - if (bcl==0) return; - BaseClassListIterator bcli(*bcl); - BaseClassDef *bcd; - for (bcli.toFirst() ; (bcd=bcli.current()) ; ++bcli) - { - ClassDef *cd=bcd->classDef; - if (cd->getLanguage()==SrcLangExt_VHDL && (VhdlDocGen::VhdlClasses)cd->protection()!=VhdlDocGen::ENTITYCLASS) - { - continue; - } - - bool b; - if (cd->getLanguage()==SrcLangExt_VHDL) - { - b=hasVisibleRoot(cd->subClasses()); - } - else - { - b=hasVisibleRoot(cd->baseClasses()); - } + delete it; + } + return maxDepth; +} - if (cd->isVisibleInHierarchy() && b) // hasVisibleRoot(cd->baseClasses())) - { - bool hasChildren = !cd->visited && !hideSuper && classHasVisibleChildren(cd); - ClassInheritanceNodeContext *tnc = new ClassInheritanceNodeContext(cd); - m_children.append(tnc); - if (hasChildren) - { - //printf("Class %s at %p visited=%d\n",cd->name().data(),cd,cd->visited); - bool wasVisited=cd->visited; - cd->visited=TRUE; - if (cd->getLanguage()==SrcLangExt_VHDL) - { - tnc->addChildren(cd->baseClasses(),wasVisited); - } - else - { - tnc->addChildren(cd->subClasses(),wasVisited); - } - } - } - } - } - TemplateVariant isLeafNode() const - { - return m_children.isEmpty(); - } - TemplateVariant children() const - { - return TemplateVariant(&m_children); - } - TemplateVariant getClass() const +static int computeNumNodesAtLevel(const TemplateStructIntf *s,int level,int maxLevel) +{ + int num=0; + if (level<maxLevel) + { + num++; + TemplateVariant child = s->get("children"); + if (child.toList()) { - if (!m_cache.classContext) + TemplateListIntf::ConstIterator *it = child.toList()->createIterator(); + TemplateVariant v; + for (it->toFirst();it->current(v);it->toNext()) { - m_cache.classContext.reset(ClassContext::alloc(m_classDef)); + num+=computeNumNodesAtLevel(v.toStruct(),level+1,maxLevel); } - return m_cache.classContext.get(); + delete it; } - private: - ClassDef *m_classDef; - GenericNodeListContext m_children; - struct Cachable - { - SharedPtr<ClassContext> classContext; - }; - mutable Cachable m_cache; -}; -//%% } - -ClassInheritanceNodeContext::ClassInheritanceNodeContext(ClassDef *cd) : RefCountedContext("ClassInheritanceNodeContext") -{ - p = new Private(cd); -} - -ClassInheritanceNodeContext::~ClassInheritanceNodeContext() -{ - delete p; -} - -TemplateVariant ClassInheritanceNodeContext::get(const char *n) const -{ - return p->get(n); -} - -void ClassInheritanceNodeContext::addChildren(const BaseClassList *bcl,bool hideSuper) -{ - p->addChildren(bcl,hideSuper); + } + return num; } -//------------------------------------------------------------------------ - -//%% list ClassInheritance[ClassInheritanceNode]: list of classes -class ClassInheritanceContext::Private : public GenericNodeListContext +static int computePreferredDepth(const TemplateListIntf *list,int maxDepth) { - public: - void addClasses(const ClassSDict &classSDict) + int preferredNumEntries = Config_getInt("HTML_INDEX_NUM_ENTRIES"); + int preferredDepth=1; + if (preferredNumEntries>0) + { + int depth = maxDepth; + for (int i=1;i<=depth;i++) { - ClassSDict::Iterator cli(classSDict); - ClassDef *cd; - for (cli.toFirst();(cd=cli.current());++cli) + int num=0; + TemplateListIntf::ConstIterator *it = list->createIterator(); + TemplateVariant v; + for (it->toFirst();it->current(v);it->toNext()) { - bool b; - if (cd->getLanguage()==SrcLangExt_VHDL) - { - if ((VhdlDocGen::VhdlClasses)cd->protection()!=VhdlDocGen::ENTITYCLASS) - { - continue; - } - b=!hasVisibleRoot(cd->subClasses()); - } - else - { - b=!hasVisibleRoot(cd->baseClasses()); - } - if (b) - { - if (cd->isVisibleInHierarchy()) // should it be visible - { - // new root level class - ClassInheritanceNodeContext *tnc = ClassInheritanceNodeContext::alloc(cd); - append(tnc); - bool hasChildren = !cd->visited && classHasVisibleChildren(cd); - if (cd->getLanguage()==SrcLangExt_VHDL && hasChildren) - { - tnc->addChildren(cd->baseClasses(),cd->visited); - cd->visited=TRUE; - } - else if (hasChildren) - { - tnc->addChildren(cd->subClasses(),cd->visited); - cd->visited=TRUE; - } - } - } + num+=computeNumNodesAtLevel(v.toStruct(),0,i); + } + delete it; + if (num<=preferredNumEntries) + { + preferredDepth=i; + } + else + { + break; } } -}; - -ClassInheritanceContext::ClassInheritanceContext() : RefCountedContext("ClassInheritanceContext") -{ - p = new Private; - initClassHierarchy(Doxygen::classSDict); - initClassHierarchy(Doxygen::hiddenClasses); - p->addClasses(*Doxygen::classSDict); - p->addClasses(*Doxygen::hiddenClasses); -} - -ClassInheritanceContext::~ClassInheritanceContext() -{ - delete p; -} - -// TemplateListIntf -int ClassInheritanceContext::count() const -{ - return (int)p->count(); -} - -TemplateVariant ClassInheritanceContext::at(int index) const -{ - TemplateVariant result; - if (index>=0 && index<count()) - { - result = p->at(index); } - return result; -} - -TemplateListIntf::ConstIterator *ClassInheritanceContext::createIterator() const -{ - return p->createIterator(); + return preferredDepth; } //------------------------------------------------------------------------ @@ -5019,13 +4917,27 @@ TemplateListIntf::ConstIterator *ClassInheritanceContext::createIterator() const class ClassHierarchyContext::Private : public PropertyMapper { public: + Private() + { + m_classTree.reset(NestingContext::alloc(0,0)); + initClassHierarchy(Doxygen::classSDict); + initClassHierarchy(Doxygen::hiddenClasses); + m_classTree->addClassHierarchy(*Doxygen::classSDict,TRUE); + m_classTree->addClassHierarchy(*Doxygen::hiddenClasses,TRUE); + //%% ClassInheritance tree + addProperty("tree", this,&Private::tree); + addProperty("fileName", this,&Private::fileName); + addProperty("relPath", this,&Private::relPath); + addProperty("highlight", this,&Private::highlight); + addProperty("subhighlight", this,&Private::subhighlight); + addProperty("title", this,&Private::title); + addProperty("preferredDepth", this,&Private::preferredDepth); + addProperty("maxDepth", this,&Private::maxDepth); + addProperty("diagrams", this,&Private::diagrams); + } TemplateVariant tree() const { - if (!m_cache.classTree) - { - m_cache.classTree.reset(ClassInheritanceContext::alloc()); - } - return m_cache.classTree.get(); + return m_classTree.get(); } TemplateVariant fileName() const { @@ -5043,6 +4955,34 @@ class ClassHierarchyContext::Private : public PropertyMapper { return "classhierarchy"; } + DotGfxHierarchyTable *getHierarchy() const + { + if (!m_cache.hierarchy) + { + m_cache.hierarchy.reset(new DotGfxHierarchyTable()); + } + return m_cache.hierarchy.get(); + } + TemplateVariant diagrams() const + { + if (!m_cache.diagrams) + { + TemplateList *diagrams = TemplateList::alloc(); + DotGfxHierarchyTable *hierarchy = getHierarchy(); + if (hierarchy->subGraphs()) + { + int id=0; + QListIterator<DotNode> li(*hierarchy->subGraphs()); + DotNode *n; + for (li.toFirst();(n=li.current());++li) + { + diagrams->append(InheritanceGraphContext::alloc(hierarchy,n,id++)); + } + } + m_cache.diagrams.reset(diagrams); + } + return m_cache.diagrams.get(); + } TemplateVariant title() const { static bool vhdlOpt = Config_getBool("OPTIMIZE_OUTPUT_VHDL"); @@ -5055,20 +4995,36 @@ class ClassHierarchyContext::Private : public PropertyMapper return theTranslator->trClassHierarchy(); } } - Private() + TemplateVariant maxDepth() const { - //%% ClassInheritance tree - addProperty("tree",this,&Private::tree); - addProperty("fileName",this,&Private::fileName); - addProperty("relPath",this,&Private::relPath); - addProperty("highlight",this,&Private::highlight); - addProperty("subhighlight",this,&Private::subhighlight); - addProperty("title",this,&Private::title); + if (!m_cache.maxDepthComputed) + { + m_cache.maxDepth = computeMaxDepth(m_classTree.get()); + m_cache.maxDepthComputed=TRUE; + } + return m_cache.maxDepth; + } + TemplateVariant preferredDepth() const + { + if (!m_cache.preferredDepthComputed) + { + m_cache.preferredDepth = computePreferredDepth(m_classTree.get(),maxDepth().toInt()); + m_cache.preferredDepthComputed=TRUE; + } + return m_cache.preferredDepth; } private: + SharedPtr<NestingContext> m_classTree; struct Cachable { - SharedPtr<ClassInheritanceContext> classTree; + Cachable() : maxDepth(0), maxDepthComputed(FALSE), + preferredDepth(0), preferredDepthComputed(FALSE), hierarchy(0) {} + int maxDepth; + bool maxDepthComputed; + int preferredDepth; + bool preferredDepthComputed; + SharedPtr<TemplateList> diagrams; + ScopedPtr<DotGfxHierarchyTable> hierarchy; }; mutable Cachable m_cache; }; @@ -5097,7 +5053,7 @@ class NestingNodeContext::Private : public PropertyMapper { public: Private(const NestingNodeContext *parent,const NestingNodeContext *thisNode, - Definition *d,int index,int level,bool addCls) + Definition *d,int index,int level,bool addCls,bool inherit, bool hideSuper) : m_parent(parent), m_def(d), m_level(level), m_index(index) { m_children.reset(NestingContext::alloc(thisNode,level+1)); @@ -5131,7 +5087,7 @@ class NestingNodeContext::Private : public PropertyMapper addProperty("fileName",this,&Private::fileName); addNamespaces(addCls); - addClasses(); + addClasses(inherit,hideSuper); addDirFiles(); addPages(); addModules(); @@ -5283,12 +5239,34 @@ class NestingNodeContext::Private : public PropertyMapper return m_def->getOutputFileBase(); } - void addClasses() + //------------------------------------------------------------------ + + void addClasses(bool inherit, bool hideSuper) { ClassDef *cd = m_def->definitionType()==Definition::TypeClass ? (ClassDef*)m_def : 0; - if (cd && cd->getClassSDict()) + if (inherit) { - m_children->addClasses(*cd->getClassSDict(),FALSE); + bool hasChildren = !cd->visited && !hideSuper && classHasVisibleChildren(cd); + if (hasChildren) + { + bool wasVisited=cd->visited; + cd->visited=TRUE; + if (cd->getLanguage()==SrcLangExt_VHDL) + { + m_children->addDerivedClasses(cd->baseClasses(),wasVisited); + } + else + { + m_children->addDerivedClasses(cd->subClasses(),wasVisited); + } + } + } + else + { + if (cd && cd->getClassSDict()) + { + m_children->addClasses(*cd->getClassSDict(),FALSE); + } } } void addNamespaces(bool addClasses) @@ -5352,9 +5330,10 @@ class NestingNodeContext::Private : public PropertyMapper //%% } NestingNodeContext::NestingNodeContext(const NestingNodeContext *parent, - Definition *d,int index,int level,bool addClass) : RefCountedContext("NestingNodeContext") + Definition *d,int index,int level,bool addClass,bool inherit,bool hideSuper) + : RefCountedContext("NestingNodeContext") { - p = new Private(parent,this,d,index,level,addClass); + p = new Private(parent,this,d,index,level,addClass,inherit,hideSuper); } NestingNodeContext::~NestingNodeContext() @@ -5394,7 +5373,7 @@ class NestingContext::Private : public GenericNodeListContext bool isLinkable = nd->isLinkableInProject(); if (isLinkable || hasChildren) { - NestingNodeContext *nnc = NestingNodeContext::alloc(m_parent,nd,m_index,m_level,addClasses); + NestingNodeContext *nnc = NestingNodeContext::alloc(m_parent,nd,m_index,m_level,addClasses,FALSE,FALSE); append(nnc); m_index++; } @@ -5423,7 +5402,7 @@ class NestingContext::Private : public GenericNodeListContext { if (classVisibleInIndex(cd) && cd->templateMaster()==0) { - NestingNodeContext *nnc = NestingNodeContext::alloc(m_parent,cd,m_index,m_level,TRUE); + NestingNodeContext *nnc = NestingNodeContext::alloc(m_parent,cd,m_index,m_level,TRUE,FALSE,FALSE); append(nnc); m_index++; } @@ -5438,7 +5417,7 @@ class NestingContext::Private : public GenericNodeListContext { if (dd->getOuterScope()==Doxygen::globalScope) { - append(NestingNodeContext::alloc(m_parent,dd,m_index,m_level,FALSE)); + append(NestingNodeContext::alloc(m_parent,dd,m_index,m_level,FALSE,FALSE,FALSE)); m_index++; } } @@ -5449,7 +5428,7 @@ class NestingContext::Private : public GenericNodeListContext DirDef *dd; for (li.toFirst();(dd=li.current());++li) { - append(NestingNodeContext::alloc(m_parent,dd,m_index,m_level,FALSE)); + append(NestingNodeContext::alloc(m_parent,dd,m_index,m_level,FALSE,FALSE,FALSE)); m_index++; } } @@ -5465,7 +5444,7 @@ class NestingContext::Private : public GenericNodeListContext { if (fd->getDirDef()==0) // top level file { - append(NestingNodeContext::alloc(m_parent,fd,m_index,m_level,FALSE)); + append(NestingNodeContext::alloc(m_parent,fd,m_index,m_level,FALSE,FALSE,FALSE)); m_index++; } } @@ -5477,7 +5456,7 @@ class NestingContext::Private : public GenericNodeListContext FileDef *fd; for (li.toFirst();(fd=li.current());++li) { - append(NestingNodeContext::alloc(m_parent,fd,m_index,m_level,FALSE)); + append(NestingNodeContext::alloc(m_parent,fd,m_index,m_level,FALSE,FALSE,FALSE)); m_index++; } } @@ -5491,7 +5470,7 @@ class NestingContext::Private : public GenericNodeListContext pd->getOuterScope()==0 || pd->getOuterScope()->definitionType()!=Definition::TypePage) { - append(NestingNodeContext::alloc(m_parent,pd,m_index,m_level,FALSE)); + append(NestingNodeContext::alloc(m_parent,pd,m_index,m_level,FALSE,FALSE,FALSE)); m_index++; } } @@ -5507,7 +5486,7 @@ class NestingContext::Private : public GenericNodeListContext (!gd->isReference() || externalGroups) ) { - append(NestingNodeContext::alloc(m_parent,gd,m_index,m_level,FALSE)); + append(NestingNodeContext::alloc(m_parent,gd,m_index,m_level,FALSE,FALSE,FALSE)); m_index++; } } @@ -5520,11 +5499,74 @@ class NestingContext::Private : public GenericNodeListContext { if (gd->isVisible()) { - append(NestingNodeContext::alloc(m_parent,gd,m_index,m_level,FALSE)); + append(NestingNodeContext::alloc(m_parent,gd,m_index,m_level,FALSE,FALSE,FALSE)); m_index++; } } } + void addDerivedClasses(const BaseClassList *bcl,bool hideSuper) + { + if (bcl==0) return; + BaseClassListIterator bcli(*bcl); + BaseClassDef *bcd; + for (bcli.toFirst() ; (bcd=bcli.current()) ; ++bcli) + { + ClassDef *cd=bcd->classDef; + if (cd->getLanguage()==SrcLangExt_VHDL && (VhdlDocGen::VhdlClasses)cd->protection()!=VhdlDocGen::ENTITYCLASS) + { + continue; + } + + bool b; + if (cd->getLanguage()==SrcLangExt_VHDL) + { + b=hasVisibleRoot(cd->subClasses()); + } + else + { + b=hasVisibleRoot(cd->baseClasses()); + } + + if (cd->isVisibleInHierarchy() && b) + { + NestingNodeContext *tnc = NestingNodeContext::alloc(m_parent,cd,m_index,m_level,TRUE,TRUE,hideSuper); + append(tnc); + m_index++; + } + } + } + void addClassHierarchy(const ClassSDict &classSDict,bool) + { + ClassSDict::Iterator cli(classSDict); + ClassDef *cd; + for (cli.toFirst();(cd=cli.current());++cli) + { + bool b; + if (cd->getLanguage()==SrcLangExt_VHDL) + { + if ((VhdlDocGen::VhdlClasses)cd->protection()!=VhdlDocGen::ENTITYCLASS) + { + continue; + } + b=!hasVisibleRoot(cd->subClasses()); + } + else + { + b=!hasVisibleRoot(cd->baseClasses()); + } + if (b) + { + if (cd->isVisibleInHierarchy()) // should it be visible + { + // new root level class + NestingNodeContext *nnc = NestingNodeContext::alloc(m_parent,cd,m_index,m_level,TRUE,TRUE,cd->visited); + append(nnc); + m_index++; + } + } + } + } + private: const NestingNodeContext *m_parent; int m_level; @@ -5602,78 +5644,17 @@ void NestingContext::addModules(const GroupList &modules) p->addModules(modules); } -//------------------------------------------------------------------------ - -static int computeMaxDepth(const TemplateListIntf *list) +void NestingContext::addClassHierarchy(const ClassSDict &classSDict,bool rootOnly) { - int maxDepth=0; - if (list) - { - TemplateListIntf::ConstIterator *it = list->createIterator(); - TemplateVariant v; - for (it->toFirst();it->current(v);it->toNext()) - { - const TemplateStructIntf *s = v.toStruct(); - TemplateVariant child = s->get("children"); - int d = computeMaxDepth(child.toList())+1; - if (d>maxDepth) maxDepth=d; - } - delete it; - } - return maxDepth; + p->addClassHierarchy(classSDict,rootOnly); } -static int computeNumNodesAtLevel(const TemplateStructIntf *s,int level,int maxLevel) +void NestingContext::addDerivedClasses(const BaseClassList *bcl,bool hideSuper) { - int num=0; - if (level<maxLevel) - { - num++; - TemplateVariant child = s->get("children"); - if (child.toList()) - { - TemplateListIntf::ConstIterator *it = child.toList()->createIterator(); - TemplateVariant v; - for (it->toFirst();it->current(v);it->toNext()) - { - num+=computeNumNodesAtLevel(v.toStruct(),level+1,maxLevel); - } - delete it; - } - } - return num; -} - -static int computePreferredDepth(const TemplateListIntf *list,int maxDepth) -{ - int preferredNumEntries = Config_getInt("HTML_INDEX_NUM_ENTRIES"); - int preferredDepth=1; - if (preferredNumEntries>0) - { - int depth = maxDepth; - for (int i=1;i<=depth;i++) - { - int num=0; - TemplateListIntf::ConstIterator *it = list->createIterator(); - TemplateVariant v; - for (it->toFirst();it->current(v);it->toNext()) - { - num+=computeNumNodesAtLevel(v.toStruct(),0,i); - } - delete it; - if (num<=preferredNumEntries) - { - preferredDepth=i; - } - else - { - break; - } - } - } - return preferredDepth; + p->addDerivedClasses(bcl,hideSuper); } +//------------------------------------------------------------------------ //%% struct ClassTree: Class nesting relations //%% { @@ -7049,6 +7030,56 @@ TemplateVariant NamespaceMembersIndexContext::get(const char *name) const return p->get(name); } +//------------------------------------------------------------------------ + +//%% struct InheritanceGraph: a connected graph reprenting part of the overall interitance tree +//%% { +class InheritanceGraphContext::Private : public PropertyMapper +{ + public: + Private(DotGfxHierarchyTable *hierarchy,DotNode *n,int id) : m_hierarchy(hierarchy), m_node(n), m_id(id) + { + addProperty("graph",this,&Private::graph); + } + TemplateVariant graph() const + { + QGString result; + static bool haveDot = Config_getBool("HAVE_DOT"); + static bool graphicalHierarchy = Config_getBool("GRAPHICAL_HIERARCHY"); + if (haveDot && graphicalHierarchy) + { + FTextStream t(&result); + m_hierarchy->createGraph(m_node,t, + /*GOF_BITMAP, + EOF_Html,*/ + g_globals.outputDir, + g_globals.outputDir+portable_pathSeparator()+"inherits"+Doxygen::htmlFileExtension, + m_id); + } + return TemplateVariant(result.data(),TRUE); + } + private: + DotGfxHierarchyTable *m_hierarchy; + DotNode *m_node; + int m_id; +}; + +InheritanceGraphContext::InheritanceGraphContext(DotGfxHierarchyTable *hierarchy,DotNode *n,int id) + : RefCountedContext("InheritanceGraphContext") +{ + p = new Private(hierarchy,n,id); +} + +InheritanceGraphContext::~InheritanceGraphContext() +{ + delete p; +} + +TemplateVariant InheritanceGraphContext::get(const char *name) const +{ + return p->get(name); +} + //------------------------------------------------------------------------ @@ -8086,7 +8117,7 @@ class HtmlSpaceless : public TemplateSpacelessIntf { m_insideString='\0'; } - else // start of string + else if (m_insideString=='\0') // start of string { m_insideString=c; } @@ -8111,8 +8142,8 @@ class HtmlSpaceless : public TemplateSpacelessIntf } } result+='\0'; - //printf("HtmlSpaceless::remove({%s})={%s} m_insideTag=%d m_insideString=%d removeSpaces=%d\n",s.data(),result.data(), - // m_insideTag,m_insideString,m_removeSpaces); + //printf("HtmlSpaceless::remove({%s})={%s} m_insideTag=%d m_insideString=%c (%d) removeSpaces=%d\n",s.data(),result.data(), + // m_insideTag,m_insideString,m_insideString,m_removeSpaces); return result.data(); } private: diff --git a/src/context.h b/src/context.h index b39ab40..6b5b810 100644 --- a/src/context.h +++ b/src/context.h @@ -51,6 +51,8 @@ struct MemberInfo; class MemberGroup; class MemberGroupSDict; class MemberGroupList; +class DotNode; +class DotGfxHierarchyTable; //---------------------------------------------------- @@ -419,6 +421,26 @@ class ClassIndexContext : public RefCountedContext, public TemplateStructIntf //---------------------------------------------------- +class InheritanceGraphContext : public RefCountedContext, public TemplateStructIntf +{ + public: + static InheritanceGraphContext *alloc(DotGfxHierarchyTable *hierarchy,DotNode *n,int id) + { return new InheritanceGraphContext(hierarchy,n,id); } + + // TemplateStructIntf methods + virtual TemplateVariant get(const char *name) const; + virtual int addRef() { return RefCountedContext::addRef(); } + virtual int release() { return RefCountedContext::release(); } + + private: + InheritanceGraphContext(DotGfxHierarchyTable *hierarchy,DotNode *n,int id); + ~InheritanceGraphContext(); + class Private; + Private *p; +}; + +//---------------------------------------------------- + class ClassInheritanceNodeContext : public RefCountedContext, public TemplateStructIntf { public: @@ -485,8 +507,8 @@ class NestingNodeContext : public RefCountedContext, public TemplateStructIntf { public: static NestingNodeContext *alloc(const NestingNodeContext *parent,Definition *def, - int index,int level,bool addClasses) - { return new NestingNodeContext(parent,def,index,level,addClasses); } + int index,int level,bool addClasses,bool inherit,bool hideSuper) + { return new NestingNodeContext(parent,def,index,level,addClasses,inherit,hideSuper); } QCString id() const; @@ -497,7 +519,7 @@ class NestingNodeContext : public RefCountedContext, public TemplateStructIntf private: NestingNodeContext(const NestingNodeContext *parent, - Definition *,int index,int level,bool addClasses); + Definition *,int index,int level,bool addClasses,bool inherit,bool hideSuper); ~NestingNodeContext(); class Private; Private *p; @@ -527,6 +549,8 @@ class NestingContext : public RefCountedContext, public TemplateListIntf void addPages(const PageSDict &pages,bool rootOnly); void addModules(const GroupSDict &modules); void addModules(const GroupList &modules); + void addClassHierarchy(const ClassSDict &clDict,bool rootOnly); + void addDerivedClasses(const BaseClassList *bcl,bool hideSuper); private: NestingContext(const NestingNodeContext *parent,int level); diff --git a/src/dot.cpp b/src/dot.cpp index 4638309..f9b4302 100644 --- a/src/dot.cpp +++ b/src/dot.cpp @@ -772,18 +772,18 @@ static bool checkDeliverables(const QCString &file1, //-------------------------------------------------------------------- -/** Class representing a list of DotNode objects. */ -class DotNodeList : public QList<DotNode> +inline int DotNode::findParent( DotNode *n ) { - public: - DotNodeList() : QList<DotNode>() {} - ~DotNodeList() {} - private: - int compareValues(const DotNode *n1,const DotNode *n2) const - { - return qstricmp(n1->m_label,n2->m_label); - } -}; + if ( !m_parents ) return -1; + return m_parents->find(n); +} + +//-------------------------------------------------------------------- + +int DotNodeList::compareValues(const DotNode *n1,const DotNode *n2) const +{ + return qstricmp(n1->m_label,n2->m_label); +} //-------------------------------------------------------------------- @@ -1908,7 +1908,7 @@ void DotNode::write(FTextStream &t, bool reNumber ) { - //printf("DotNode::write(%d) name=%s this=%p written=%d\n",distance,m_label.data(),this,m_written); + //printf("DotNode::write(%d) name=%s this=%p written=%d visible=%d\n",m_distance,m_label.data(),this,m_written,m_visible); if (m_written) return; // node already written to the output if (!m_visible) return; // node is not visible writeBox(t,gt,format,m_truncated==Truncated,reNumber); @@ -2261,12 +2261,106 @@ const DotNode *DotNode::findDocNode() const int DotGfxHierarchyTable::m_curNodeNumber; +void DotGfxHierarchyTable::createGraph(DotNode *n,FTextStream &out, + const char *path,const char *fileName,int id) const +{ + QDir d(path); + QCString baseName; + QCString imgExt = Config_getEnum("DOT_IMAGE_FORMAT"); + baseName.sprintf("inherit_graph_%d",id); + QCString imgName = baseName+"."+ imgExt; + QCString mapName = baseName+".map"; + QCString absImgName = QCString(d.absPath().data())+"/"+imgName; + QCString absMapName = QCString(d.absPath().data())+"/"+mapName; + QCString absBaseName = QCString(d.absPath().data())+"/"+baseName; + QListIterator<DotNode> dnli2(*m_rootNodes); + DotNode *node; + + // compute md5 checksum of the graph were are about to generate + QGString theGraph; + FTextStream md5stream(&theGraph); + writeGraphHeader(md5stream,theTranslator->trGraphicalHierarchy()); + md5stream << " rankdir=\"LR\";" << endl; + for (dnli2.toFirst();(node=dnli2.current());++dnli2) + { + if (node->m_subgraphId==n->m_subgraphId) + { + node->clearWriteFlag(); + } + } + for (dnli2.toFirst();(node=dnli2.current());++dnli2) + { + if (node->m_subgraphId==n->m_subgraphId) + { + node->write(md5stream,DotNode::Hierarchy,GOF_BITMAP,FALSE,TRUE,TRUE,TRUE); + } + } + writeGraphFooter(md5stream); + resetReNumbering(); + uchar md5_sig[16]; + QCString sigStr(33); + MD5Buffer((const unsigned char *)theGraph.data(),theGraph.length(),md5_sig); + MD5SigToString(md5_sig,sigStr.data(),33); + bool regenerate=FALSE; + if (checkAndUpdateMd5Signature(absBaseName,sigStr) || + !checkDeliverables(absImgName,absMapName)) + { + regenerate=TRUE; + // image was new or has changed + QCString dotName=absBaseName+".dot"; + QFile f(dotName); + if (!f.open(IO_WriteOnly)) return; + FTextStream t(&f); + t << theGraph; + f.close(); + resetReNumbering(); + + DotRunner *dotRun = new DotRunner(dotName,d.absPath().data(),TRUE,absImgName); + dotRun->addJob(imgExt,absImgName); + dotRun->addJob(MAP_CMD,absMapName); + DotManager::instance()->addRun(dotRun); + } + else + { + removeDotGraph(absBaseName+".dot"); + } + Doxygen::indexList->addImageFile(imgName); + // write image and map in a table row + QCString mapLabel = escapeCharsInString(n->m_label,FALSE); + if (imgExt=="svg") // vector graphics + { + if (regenerate || !writeSVGFigureLink(out,QCString(),baseName,absImgName)) + { + if (regenerate) + { + DotManager::instance()->addSVGConversion(absImgName,QCString(), + FALSE,QCString(),FALSE,0); + } + int mapId = DotManager::instance()->addSVGObject(fileName,baseName, + absImgName,QCString()); + out << "<!-- SVG " << mapId << " -->" << endl; + } + } + else // normal bitmap + { + out << "<img src=\"" << imgName << "\" border=\"0\" alt=\"\" usemap=\"#" + << mapLabel << "\"/>" << endl; + + if (regenerate || !insertMapFile(out,absMapName,QCString(),mapLabel)) + { + int mapId = DotManager::instance()->addMap(fileName,absMapName,QCString(), + FALSE,QCString(),mapLabel); + out << "<!-- MAP " << mapId << " -->" << endl; + } + } +} + void DotGfxHierarchyTable::writeGraph(FTextStream &out, const char *path,const char *fileName) const { //printf("DotGfxHierarchyTable::writeGraph(%s)\n",name); //printf("m_rootNodes=%p count=%d\n",m_rootNodes,m_rootNodes->count()); - + if (m_rootSubgraphs->count()==0) return; QDir d(path); @@ -2284,97 +2378,8 @@ void DotGfxHierarchyTable::writeGraph(FTextStream &out, int count=0; for (dnli.toFirst();(n=dnli.current());++dnli) { - QCString baseName; - QCString imgExt = Config_getEnum("DOT_IMAGE_FORMAT"); - baseName.sprintf("inherit_graph_%d",count++); - //baseName = convertNameToFile(baseName); - QCString imgName = baseName+"."+ imgExt; - QCString mapName = baseName+".map"; - QCString absImgName = QCString(d.absPath().data())+"/"+imgName; - QCString absMapName = QCString(d.absPath().data())+"/"+mapName; - QCString absBaseName = QCString(d.absPath().data())+"/"+baseName; - QListIterator<DotNode> dnli2(*m_rootNodes); - DotNode *node; - - // compute md5 checksum of the graph were are about to generate - QGString theGraph; - FTextStream md5stream(&theGraph); - writeGraphHeader(md5stream,theTranslator->trGraphicalHierarchy()); - md5stream << " rankdir=\"LR\";" << endl; - for (dnli2.toFirst();(node=dnli2.current());++dnli2) - { - if (node->m_subgraphId==n->m_subgraphId) - { - node->clearWriteFlag(); - } - } - for (dnli2.toFirst();(node=dnli2.current());++dnli2) - { - if (node->m_subgraphId==n->m_subgraphId) - { - node->write(md5stream,DotNode::Hierarchy,GOF_BITMAP,FALSE,TRUE,TRUE,TRUE); - } - } - writeGraphFooter(md5stream); - resetReNumbering(); - uchar md5_sig[16]; - QCString sigStr(33); - MD5Buffer((const unsigned char *)theGraph.data(),theGraph.length(),md5_sig); - MD5SigToString(md5_sig,sigStr.data(),33); - bool regenerate=FALSE; - if (checkAndUpdateMd5Signature(absBaseName,sigStr) || - !checkDeliverables(absImgName,absMapName)) - { - regenerate=TRUE; - // image was new or has changed - QCString dotName=absBaseName+".dot"; - QFile f(dotName); - if (!f.open(IO_WriteOnly)) return; - FTextStream t(&f); - t << theGraph; - f.close(); - resetReNumbering(); - - DotRunner *dotRun = new DotRunner(dotName,d.absPath().data(),TRUE,absImgName); - dotRun->addJob(imgExt,absImgName); - dotRun->addJob(MAP_CMD,absMapName); - DotManager::instance()->addRun(dotRun); - } - else - { - removeDotGraph(absBaseName+".dot"); - } - Doxygen::indexList->addImageFile(imgName); - // write image and map in a table row - QCString mapLabel = escapeCharsInString(n->m_label,FALSE); out << "<tr><td>"; - if (imgExt=="svg") // vector graphics - { - if (regenerate || !writeSVGFigureLink(out,QCString(),baseName,absImgName)) - { - if (regenerate) - { - DotManager::instance()->addSVGConversion(absImgName,QCString(), - FALSE,QCString(),FALSE,0); - } - int mapId = DotManager::instance()->addSVGObject(fileName,baseName, - absImgName,QCString()); - out << "<!-- SVG " << mapId << " -->" << endl; - } - } - else // normal bitmap - { - out << "<img src=\"" << imgName << "\" border=\"0\" alt=\"\" usemap=\"#" - << mapLabel << "\"/>" << endl; - - if (regenerate || !insertMapFile(out,absMapName,QCString(),mapLabel)) - { - int mapId = DotManager::instance()->addMap(fileName,absMapName,QCString(), - FALSE,QCString(),mapLabel); - out << "<!-- MAP " << mapId << " -->" << endl; - } - } - + createGraph(n,out,path,fileName,count++); out << "</td></tr>" << endl; } out << "</table>" << endl; @@ -122,6 +122,7 @@ class DotNode friend class DotNodeList; friend class DotCallGraph; friend class DotGroupCollaboration; + friend class DotInheritanceGraph; friend QCString computeMd5Signature( DotNode *root, GraphType gt, @@ -133,12 +134,15 @@ class DotNode ); }; -inline int DotNode::findParent( DotNode *n ) +/** Class representing a list of DotNode objects. */ +class DotNodeList : public QList<DotNode> { - if( !m_parents ) - return -1; - return m_parents->find(n); -} + public: + DotNodeList() : QList<DotNode>() {} + ~DotNodeList() {} + private: + int compareValues(const DotNode *n1,const DotNode *n2) const; +}; /** Represents a graphical class hierarchy */ class DotGfxHierarchyTable @@ -147,6 +151,8 @@ class DotGfxHierarchyTable DotGfxHierarchyTable(); ~DotGfxHierarchyTable(); void writeGraph(FTextStream &t,const char *path, const char *fileName) const; + void createGraph(DotNode *rootNode,FTextStream &t,const char *path,const char *fileName,int id) const; + const DotNodeList *subGraphs() const { return m_rootSubgraphs; } private: void addHierarchy(DotNode *n,ClassDef *cd,bool hide); diff --git a/src/template.cpp b/src/template.cpp index 100de16..9fa03aa 100644 --- a/src/template.cpp +++ b/src/template.cpp @@ -1976,10 +1976,21 @@ class ExpressionParser ExprAst *parseLiteral() { TRACE(("{parseLiteral(%s)\n",m_curToken.id.data())); - ExprAst *lit = new ExprAstLiteral(m_curToken.id); + ExprAst *expr = new ExprAstLiteral(m_curToken.id); getNextToken(); + if (expr) + { + while (m_curToken.type==ExprToken::Operator && + m_curToken.op==Operator::Filter) + { + getNextToken(); + ExprAstFilter *filter = parseFilter(); + if (!filter) break; + expr = new ExprAstFilterAppl(expr,filter); + } + } TRACE(("}parseLiteral()\n")); - return lit; + return expr; } ExprAst *parseIdentifierOptionalArgs() @@ -3550,6 +3561,7 @@ class TemplateNodeCreate : public TemplateNodeCreator<TemplateNodeCreate> { outputFile.prepend(ci->outputDirectory()+"/"); } + //printf("NoteCreate(%s)\n",outputFile.data()); QFile f(outputFile); if (f.open(IO_WriteOnly)) { @@ -3622,9 +3634,11 @@ class TemplateNodeTree : public TemplateNodeCreator<TemplateNodeTree> { //printf("TemplateNodeTree::renderChildren(%d)\n",ctx->list->count()); // render all children of node to a string and return it + TemplateContext *c = ctx->templateCtx; + TemplateContextImpl* ci = dynamic_cast<TemplateContextImpl*>(c); + if (ci==0) return QCString(); // should not happen QGString result; FTextStream ss(&result); - TemplateContext *c = ctx->templateCtx; c->push(); TemplateVariant node; TemplateListIntf::ConstIterator *it = ctx->list->createIterator(); @@ -3642,14 +3656,21 @@ class TemplateNodeTree : public TemplateNodeCreator<TemplateNodeTree> if (list && list->count()>0) // non-empty list { TreeContext childCtx(this,list,ctx->templateCtx); -// TemplateVariant children(&childCtx,renderChildrenStub); TemplateVariant children(TemplateVariant::Delegate::fromFunction(&childCtx,renderChildrenStub)); children.setRaw(TRUE); c->set("children",children); m_treeNodes.render(ss,c); hasChildren=TRUE; } + else if (list==0) + { + ci->warn(m_templateName,m_line,"recursetree: children attribute has type '%s' instead of list\n",v.typeAsString().data()); + } } + //else + //{ + // ci->warn(m_templateName,m_line,"recursetree: children attribute is not valid"); + //} } if (!hasChildren) { diff --git a/templates/html/doxygen.css b/templates/html/doxygen.css index a7a1e4f..1d9002f 100644 --- a/templates/html/doxygen.css +++ b/templates/html/doxygen.css @@ -227,7 +227,7 @@ span.lineno a:hover { background-color: #C8C8C8; } -div.ah { +div.ah, span.ah { background-color: black; font-weight: bold; color: #ffffff; @@ -245,6 +245,15 @@ div.ah { background-image: -moz-linear-gradient(center top, #eee 0%, #444 40%, #000); } +div.classindex ul { + list-style: none; + padding-left: 0; +} + +div.classindex span.ai { + display: inline-block; +} + div.groupHeader { margin-left: 16px; margin-top: 12px; diff --git a/templates/html/htmlclasses.tpl b/templates/html/htmlclasses.tpl index e932c26..803b1a9 100644 --- a/templates/html/htmlclasses.tpl +++ b/templates/html/htmlclasses.tpl @@ -4,18 +4,46 @@ <div class="textblock"> {% indexentry nav name=tr.classIndex file=page.fileName anchor='' %} </div> -<div class="classindex" style="column-count:{{ config.COLS_IN_ALPHA_INDEX }};-moz-column-count:{{ config.COLS_IN_ALPHA_INDEX }};-webkit-column-count:{{ config.COLS_IN_ALPHA_INDEX}}"> -<ul> {% with index=classIndex.list|alphaIndex:'name' %} + {# quick index at top #} + <div class="qindex"> {% for section in index %} - <div class="ah">  {{ section.letter }}  </div> + <a class="qindex" href="#letter_{{ section.label }}">{{ section.letter }}</a> + {% if not forloop.last %} +  |  + {% endif %} + {% endfor %} + </div> + {# multi column index #} + <div class="classindex" style="column-count:{{ config.COLS_IN_ALPHA_INDEX }};-moz-column-count:{{ config.COLS_IN_ALPHA_INDEX }};-webkit-column-count:{{ config.COLS_IN_ALPHA_INDEX}}"> + {% for section in index %} + <ul> {% for cls in section.items %} - <li>{{ cls.name }}</li> + <li> + <span class="ai"> + {% if forloop.first %} + <a name="#letter_{{ section.label }}"></a> + <span class="ah">  {{ section.letter }}  </span><br/> + {% endif %} + {% with obj=cls text=cls.name %} + {% include 'htmlobjlink.tpl' %} + {% endwith %} + </span> + </li> {% endfor %} + </ul> + {% endfor %} + </div><!-- classindex --> + {# quick index at bottom #} + <div class="qindex"> + {% for section in index %} + <a class="qindex" href="#letter_{{ section.label }}">{{ section.letter }}</a> + {% if not forloop.last %} +  |  + {% endif %} {% endfor %} + </div> {% endwith %} -</ul> -</div><!-- classindex --> </div><!-- contents --> {% endblock %} diff --git a/templates/html/htmlgraphhierarchy.tpl b/templates/html/htmlgraphhierarchy.tpl new file mode 100644 index 0000000..2c2dde5 --- /dev/null +++ b/templates/html/htmlgraphhierarchy.tpl @@ -0,0 +1,13 @@ +{% extend 'htmlbase.tpl' %} +{% block content %} +<div class="contents"> +<div class="textblock"> +<p><a href="hierarchy{{ config.HTML_FILE_EXTENSION }}">{{ tr.gotoTextualHierarchy }}</a></p> +</div> +<table border="0" cellspacing="10" cellpadding="0"> +{% for d in classHierarchy.diagrams %} +<tr><td>{{ d.graph }}</td></tr> +{% endfor %} +</table> +</div> +{% endblock %} diff --git a/templates/html/htmlhierarchy.tpl b/templates/html/htmlhierarchy.tpl new file mode 100644 index 0000000..5d03755 --- /dev/null +++ b/templates/html/htmlhierarchy.tpl @@ -0,0 +1,17 @@ +{% extend 'htmlbase.tpl' %} +{% block content %} +<div class="contents"> +<div class="textblock"> +<p>{{ tr.classHierarchyDescription }}</p> +{% if config.HAVE_DOT and config.GRAPHICAL_HIERARCHY %} +<p><a href="inherits{{ config.HTML_FILE_EXTENSION }}">{{ tr.gotoGraphicalHierarchy }}</a></p> +{% endif %} +</div> +{% indexentry nav name=tr.classHierarchy file=page.fileName anchor='' %} +{% opensubindex nav %} +{% with tree=classHierarchy %} + {% include 'htmldirtree.tpl' %} +{% endwith %} +{% closesubindex nav %} +</div> +{% endblock %} diff --git a/templates/html/htmllayout.tpl b/templates/html/htmllayout.tpl index ffcd318..9b82238 100644 --- a/templates/html/htmllayout.tpl +++ b/templates/html/htmllayout.tpl @@ -179,7 +179,12 @@ {# TODO: write the class inheritance hierarchy #} {% if classHierarchy.tree %} {% with page=classHierarchy %} - {# {% create classHierarchy.fileName|append:config.HTML_FILE_EXTENSION from 'hierarchy.tpl' %} #} + {% create classHierarchy.fileName|append:config.HTML_FILE_EXTENSION from 'htmlhierarchy.tpl' %} + {% endwith %} + {% with page=classHierarchy %} + {% if config.HAVE_DOT and config.GRAPHICAL_HIERARCHY %} + {% create 'inherits'|append:config.HTML_FILE_EXTENSION from 'htmlgraphhierarchy.tpl' %} + {% endif %} {% endwith %} {% endif %} diff --git a/templates/html/htmlpage.tpl b/templates/html/htmlpage.tpl index e703513..3882989 100644 --- a/templates/html/htmlpage.tpl +++ b/templates/html/htmlpage.tpl @@ -34,7 +34,9 @@ {% if classHierarchy.tree %} <li><a href="{{ page.relPath }}hierarchy{{ config.HTML_FILE_EXTENSION }}"><span>{{ tr.classHierarchy }} </span></a></li> {% endif %} + {% if classMembersIndex.all %} <li><a href="{{ page.relPath }}functions{{ config.HTML_FILE_EXTENSION }}"><span>{{ tr.classMembers }} </span></a></li> + {% endif %} </ul> </li> {% endif %} diff --git a/templates/html/htmltabs.tpl b/templates/html/htmltabs.tpl index 3119eb6..9ce8c44 100644 --- a/templates/html/htmltabs.tpl +++ b/templates/html/htmltabs.tpl @@ -83,7 +83,9 @@ {% if classHierarchy.tree %} <li{% if page.subhighlight=='classhierarchy' %} class="current"{% endif %}><a href="{{ page.relPath }}hierarchy{{ config.HTML_FILE_EXTENSION }}"><span>{{ tr.classHierarchy|nowrap }}</span></a></li> {% endif %} + {% if classMembersIndex.all %} <li{% if page.subhighlight=='classmembers' %} class="current"{% endif %}><a href="{{ page.relPath }}functions{{ config.HTML_FILE_EXTENSION }}"><span>{{ tr.classMembers|nowrap }}</span></a></li> + {% endif %} {% endif %} {# file subtabs #} {% if page.highlight=='files' %} |