summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDimitri van Heesch <dimitri@stack.nl>2014-12-14 15:39:29 (GMT)
committerDimitri van Heesch <dimitri@stack.nl>2014-12-25 12:43:31 (GMT)
commitfe818bf8e3a154788a4a180068cfdfbbadd66ff6 (patch)
treec08545cd15e627b36eef1e0d0a7eb4fa0bb76437
parent3ebc431569aa6566389f3f3fc00aae7b8a90e58b (diff)
downloadDoxygen-fe818bf8e3a154788a4a180068cfdfbbadd66ff6.zip
Doxygen-fe818bf8e3a154788a4a180068cfdfbbadd66ff6.tar.gz
Doxygen-fe818bf8e3a154788a4a180068cfdfbbadd66ff6.tar.bz2
Added graphical hierarchy support to template engine
-rw-r--r--src/context.cpp573
-rw-r--r--src/context.h30
-rw-r--r--src/dot.cpp211
-rw-r--r--src/dot.h16
-rw-r--r--src/template.cpp29
-rw-r--r--templates/html/doxygen.css11
-rw-r--r--templates/html/htmlclasses.tpl40
-rw-r--r--templates/html/htmlgraphhierarchy.tpl13
-rw-r--r--templates/html/htmlhierarchy.tpl17
-rw-r--r--templates/html/htmllayout.tpl7
-rw-r--r--templates/html/htmlpage.tpl2
-rw-r--r--templates/html/htmltabs.tpl2
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;
diff --git a/src/dot.h b/src/dot.h
index 8906199..41a416e 100644
--- a/src/dot.h
+++ b/src/dot.h
@@ -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">&#160;&#160;{{ section.letter }}&#160;&#160;</div>
+ <a class="qindex" href="#letter_{{ section.label }}">{{ section.letter }}</a>
+ {% if not forloop.last %}
+ &#160;|&#160;
+ {% 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">&#160;&#160;{{ section.letter }}&#160;&#160;</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 %}
+ &#160;|&#160;
+ {% 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' %}