Commit fe818bf8 authored by Dimitri van Heesch's avatar Dimitri van Heesch

Added graphical hierarchy support to template engine

parent 3ebc4315
......@@ -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:
......
......@@ -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);
......
......@@ -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);
......
......@@ -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)
{
......
......@@ -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;
......
......@@ -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 %}
{% 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 %}
{% 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 %}
......@@ -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 %}
......
......@@ -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 %}
......
......@@ -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' %}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment