summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDimitri van Heesch <dimitri@stack.nl>2013-08-26 08:18:59 (GMT)
committerDimitri van Heesch <dimitri@stack.nl>2013-10-21 18:21:33 (GMT)
commit784a67d23ff81275c95af4199179da094953be2e (patch)
tree90a165d2f3327f3ad94775f616c3440d37813702
parent74815268dd88f2cfb4473462cef3c33eebd5516a (diff)
downloadDoxygen-784a67d23ff81275c95af4199179da094953be2e.zip
Doxygen-784a67d23ff81275c95af4199179da094953be2e.tar.gz
Doxygen-784a67d23ff81275c95af4199179da094953be2e.tar.bz2
Added rudimentary support for django like template system for output creation.
-rw-r--r--src/classdef.cpp49
-rw-r--r--src/classdef.h8
-rw-r--r--src/context.cpp2442
-rw-r--r--src/context.h535
-rw-r--r--src/definition.cpp2
-rw-r--r--src/definition.h2
-rw-r--r--src/dirdef.cpp8
-rw-r--r--src/dirdef.h1
-rw-r--r--src/doxygen.cpp21
-rw-r--r--src/filedef.cpp6
-rw-r--r--src/filedef.h2
-rw-r--r--[-rwxr-xr-x]src/fortranscanner.l0
-rw-r--r--src/ftextstream.h4
-rw-r--r--src/index.cpp77
-rw-r--r--src/libdoxygen.pro.in8
-rw-r--r--src/namespacedef.cpp46
-rw-r--r--src/namespacedef.h2
-rw-r--r--src/template.cpp2968
-rw-r--r--src/template.h395
-rw-r--r--src/util.cpp69
-rw-r--r--src/util.h5
21 files changed, 6532 insertions, 118 deletions
diff --git a/src/classdef.cpp b/src/classdef.cpp
index eab6b8e..c097aee 100644
--- a/src/classdef.cpp
+++ b/src/classdef.cpp
@@ -916,9 +916,15 @@ static void writeTemplateSpec(OutputList &ol,Definition *d,
}
}
+bool ClassDef::hasBriefDescription() const
+{
+ static bool briefMemberDesc = Config_getBool("BRIEF_MEMBER_DESC");
+ return !briefDescription().isEmpty() && briefMemberDesc;
+}
+
void ClassDef::writeBriefDescription(OutputList &ol,bool exampleFlag)
{
- if (!briefDescription().isEmpty() && Config_getBool("BRIEF_MEMBER_DESC"))
+ if (hasBriefDescription())
{
ol.startParagraph();
ol.generateDoc(briefFile(),briefLine(),this,0,
@@ -929,10 +935,7 @@ void ClassDef::writeBriefDescription(OutputList &ol,bool exampleFlag)
ol.enable(OutputGenerator::RTF);
ol.popGeneratorState();
- if (Config_getBool("REPEAT_BRIEF") ||
- !documentation().isEmpty() ||
- exampleFlag
- )
+ if (hasDetailedDescription() || exampleFlag)
{
writeMoreLink(ol,anchor());
}
@@ -990,14 +993,20 @@ void ClassDef::writeDetailedDocumentationBody(OutputList &ol)
ol.endTextBlock();
}
+bool ClassDef::hasDetailedDescription() const
+{
+ static bool repeatBrief = Config_getBool("REPEAT_BRIEF");
+ static bool sourceBrowser = Config_getBool("SOURCE_BROWSER");
+ return ((!briefDescription().isEmpty() && repeatBrief) ||
+ !documentation().isEmpty() ||
+ (sourceBrowser && getStartBodyLine()!=-1 && getBodyDef()));
+}
+
// write the detailed description for this class
void ClassDef::writeDetailedDescription(OutputList &ol, const QCString &/*pageType*/, bool exampleFlag,
const QCString &title,const QCString &anchor)
{
- if ((!briefDescription().isEmpty() && Config_getBool("REPEAT_BRIEF")) ||
- !documentation().isEmpty() ||
- (Config_getBool("SOURCE_BROWSER") && getStartBodyLine()!=-1 && getBodyDef()) ||
- exampleFlag)
+ if (hasDetailedDescription() || exampleFlag)
{
ol.pushGeneratorState();
ol.disable(OutputGenerator::Html);
@@ -1990,12 +1999,8 @@ void ClassDef::writeDocumentationContents(OutputList &ol,const QCString & /*page
ol.endContents();
}
-// write all documentation for this class
-void ClassDef::writeDocumentation(OutputList &ol)
+QCString ClassDef::title() const
{
- static bool generateTreeView = Config_getBool("GENERATE_TREEVIEW");
- //static bool fortranOpt = Config_getBool("OPTIMIZE_FOR_FORTRAN");
- //static bool vhdlOpt = Config_getBool("OPTIMIZE_OUTPUT_VHDL");
QCString pageTitle;
SrcLangExt lang = getLanguage();
@@ -2027,7 +2032,17 @@ void ClassDef::writeDocumentation(OutputList &ol)
m_impl->compType == Interface && getLanguage()==SrcLangExt_ObjC ? Class : m_impl->compType,
m_impl->tempArgs != 0);
}
-
+ return pageTitle;
+}
+
+// write all documentation for this class
+void ClassDef::writeDocumentation(OutputList &ol)
+{
+ static bool generateTreeView = Config_getBool("GENERATE_TREEVIEW");
+ //static bool fortranOpt = Config_getBool("OPTIMIZE_FOR_FORTRAN");
+ //static bool vhdlOpt = Config_getBool("OPTIMIZE_OUTPUT_VHDL");
+ QCString pageTitle = title();
+
startFile(ol,getOutputFileBase(),name(),pageTitle,HLI_ClassVisible,!generateTreeView);
if (!generateTreeView)
{
@@ -4723,4 +4738,8 @@ bool ClassDef::isExtension() const
return b;
}
+const ClassSDict *ClassDef::innerClasses() const
+{
+ return m_impl->innerClasses;
+}
diff --git a/src/classdef.h b/src/classdef.h
index 494b8f2..537ff1f 100644
--- a/src/classdef.h
+++ b/src/classdef.h
@@ -125,6 +125,12 @@ class ClassDef : public Definition
/** returns TRUE if this class has documentation */
bool hasDocumentation() const;
+ /** returns TRUE if this class has a brief description */
+ bool hasBriefDescription() const;
+
+ /** returns TRUE if this class has a non-empty detailed description */
+ bool hasDetailedDescription() const;
+
/** Returns the name as it is appears in the documentation */
QCString displayName(bool includeScope=TRUE) const;
@@ -301,6 +307,8 @@ class ClassDef : public Definition
bool isJavaEnum() const;
bool isGeneric() const;
+ const ClassSDict *innerClasses() const;
+ QCString title() const;
//-----------------------------------------------------------------------------------
// --- setters ----
diff --git a/src/context.cpp b/src/context.cpp
new file mode 100644
index 0000000..c5b6903
--- /dev/null
+++ b/src/context.cpp
@@ -0,0 +1,2442 @@
+#include "context.h"
+#include "config.h"
+#include "index.h"
+#include "classlist.h"
+#include "doxygen.h"
+#include "namespacedef.h"
+#include "filedef.h"
+#include "pagedef.h"
+#include "groupdef.h"
+#include "util.h"
+#include "version.h"
+#include "language.h"
+#include "message.h"
+#include "vhdldocgen.h"
+#include "filename.h"
+#include "dirdef.h"
+#include "docparser.h"
+#include "htmlgen.h"
+#include "htmldocvisitor.h"
+
+// iterator support
+template<class T>
+class GenericConstIterator : public TemplateListIntf::ConstIterator
+{
+ public:
+ GenericConstIterator(const QList<T> &list)
+ : m_it(list) { }
+ virtual ~GenericConstIterator() {}
+ void toFirst()
+ {
+ m_it.toFirst();
+ }
+ void toLast()
+ {
+ m_it.toLast();
+ }
+ void toNext()
+ {
+ if (m_it.current()) ++m_it;
+ }
+ void toPrev()
+ {
+ if (m_it.current()) --m_it;
+ }
+ bool current(TemplateVariant &v) const
+ {
+ if (m_it.current())
+ {
+ v = m_it.current();
+ return TRUE;
+ }
+ else
+ {
+ v = TemplateVariant();
+ return FALSE;
+ }
+ }
+ private:
+ QListIterator<T> m_it;
+};
+
+//------------------------------------------------------------------------
+
+// standard list implementation
+template<class T>
+class GenericNodeListContext : public TemplateListIntf
+{
+ public:
+ GenericNodeListContext()
+ {
+ m_children.setAutoDelete(TRUE);
+ }
+
+ // TemplateListIntf methods
+ int count() const
+ {
+ return (int)m_children.count();
+ }
+ TemplateVariant at(int index) const
+ {
+ TemplateVariant result;
+ if (index>=0 && index<count())
+ {
+ result = m_children.at(index);
+ }
+ return result;
+ }
+ TemplateListIntf::ConstIterator *createIterator() const
+ {
+ return new GenericConstIterator<T>(m_children);
+ }
+
+ void append(T *ctn)
+ {
+ m_children.append(ctn);
+ }
+ bool isEmpty() const
+ {
+ return m_children.isEmpty();
+ }
+ private:
+ mutable QList<T> m_children;
+};
+
+//------------------------------------------------------------------------
+
+/** @brief Helper class to map a property name to a handler member function */
+template<typename T>
+class PropertyMapper
+{
+ public:
+ struct PropertyFunc
+ {
+ typedef TemplateVariant (T::*Handler)() const;
+ PropertyFunc(const T *o,Handler h) : obj(o), handler(h) {}
+ TemplateVariant operator()() const
+ {
+ return (obj->*handler)();
+ }
+ const T *obj;
+ Handler handler;
+ };
+ PropertyMapper() { m_map.setAutoDelete(TRUE); }
+ TemplateVariant get(const char *n)
+ {
+ //printf("PropertyMapper::get(%s)\n",n);
+ TemplateVariant result;
+ PropertyFunc *func = m_map.find(n);
+ if (func)
+ {
+ result = (*func)();
+ }
+ return result;
+ }
+ void insert(const char *name,const PropertyFunc *func)
+ {
+ m_map.insert(name,func);
+ }
+ private:
+ QDict<PropertyFunc> m_map;
+};
+
+
+//------------------------------------------------------------------------
+
+//%% struct Config : configuration options
+//%% {
+class ConfigContext::Private
+{
+ public:
+ Private() { cachedLists.setAutoDelete(TRUE); }
+ TemplateVariant fetchList(const QCString &name,const QStrList *list)
+ {
+ TemplateList *tlist = cachedLists.find(name);
+ if (tlist==0)
+ {
+ tlist = new TemplateList;
+ cachedLists.insert(name,tlist);
+ QStrListIterator li(*list);
+ char *s;
+ for (li.toFirst();(s=li.current());++li)
+ {
+ tlist->append(s);
+ }
+ }
+ return tlist;
+ }
+ private:
+ QDict<TemplateList> cachedLists;
+};
+//%% }
+
+ConfigContext::ConfigContext()
+{
+ p = new Private;
+}
+
+ConfigContext::~ConfigContext()
+{
+ delete p;
+}
+
+TemplateVariant ConfigContext::get(const char *name) const
+{
+ TemplateVariant result;
+ if (name)
+ {
+ ConfigOption *option = Config::instance()->get(name);
+ if (option)
+ {
+ switch (option->kind())
+ {
+ case ConfigOption::O_Bool:
+ return TemplateVariant(*((ConfigBool*)option)->valueRef());
+ case ConfigOption::O_Int:
+ return TemplateVariant(*((ConfigInt*)option)->valueRef());
+ case ConfigOption::O_Enum:
+ return TemplateVariant(*((ConfigEnum*)option)->valueRef());
+ case ConfigOption::O_String:
+ return TemplateVariant(*((ConfigString*)option)->valueRef());
+ case ConfigOption::O_List:
+ return p->fetchList(name,((ConfigList*)option)->valueRef());
+ break;
+ default:
+ break;
+ }
+ }
+ }
+ return result;
+}
+
+//------------------------------------------------------------------------
+
+//%% struct Doxygen: global information
+//%% {
+class DoxygenContext::Private : public PropertyMapper<DoxygenContext::Private>
+{
+ public:
+ TemplateVariant version() const
+ {
+ return versionString;
+ }
+ TemplateVariant date() const
+ {
+ return TemplateVariant(dateToString(TRUE));
+ }
+ Private()
+ {
+ //%% string version
+ insert("version",new PropertyFunc(this,&Private::version));
+ //%% string date
+ insert("date", new PropertyFunc(this,&Private::date));
+ }
+};
+//%% }
+
+DoxygenContext::DoxygenContext()
+{
+ p = new Private;
+}
+
+DoxygenContext::~DoxygenContext()
+{
+ delete p;
+}
+
+TemplateVariant DoxygenContext::get(const char *n) const
+{
+ return p->get(n);
+}
+
+//------------------------------------------------------------------------
+
+//%% struct Translator: translation methods
+//%% {
+class TranslateContext::Private : public PropertyMapper<TranslateContext::Private>
+{
+ public:
+ static QCString generatedAtFunc(const void *obj,const QValueList<TemplateVariant> &args)
+ {
+ return ((TranslateContext::Private*)obj)->generatedAt(args);
+ }
+ QCString generatedAt(const QValueList<TemplateVariant> &args) const
+ {
+ if (args.count()==2)
+ {
+ return theTranslator->trGeneratedAt(args[0].toString(),args[1].toString());
+ }
+ else
+ {
+ err("tr.generateAt should take two parameters!\n");
+ }
+ return QCString();
+ }
+
+ TemplateVariant generatedBy() const
+ {
+ return theTranslator->trGeneratedBy();
+ }
+ TemplateVariant generatedAt() const
+ {
+ return TemplateVariant(this,&Private::generatedAtFunc);
+ }
+ TemplateVariant search() const
+ {
+ return theTranslator->trSearch();
+ }
+ TemplateVariant mainPage() const
+ {
+ return theTranslator->trMainPage();
+ }
+ TemplateVariant classes() const
+ {
+ return theTranslator->trClasses();
+ }
+ TemplateVariant classList() const
+ {
+ return theTranslator->trCompoundList();
+ }
+ TemplateVariant classIndex() const
+ {
+ return theTranslator->trCompoundIndex();
+ }
+ TemplateVariant classHierarchy() const
+ {
+ return theTranslator->trClassHierarchy();
+ }
+ TemplateVariant classMembers() const
+ {
+ return theTranslator->trCompoundMembers();
+ }
+ TemplateVariant modules() const
+ {
+ return theTranslator->trModules();
+ }
+ TemplateVariant namespaces() const
+ {
+ if (m_javaOpt || m_vhdlOpt)
+ {
+ return theTranslator->trPackages();
+ }
+ else if (m_fortranOpt)
+ {
+ return theTranslator->trModules();
+ }
+ else
+ {
+ return theTranslator->trNamespaces();
+ }
+ }
+ TemplateVariant files() const
+ {
+ return theTranslator->trFile(TRUE,FALSE);
+ }
+ TemplateVariant pages() const
+ {
+ return theTranslator->trRelatedPages();
+ }
+ TemplateVariant examples() const
+ {
+ return theTranslator->trExamples();
+ }
+ TemplateVariant namespaceList() const
+ {
+ if (m_javaOpt || m_vhdlOpt)
+ {
+ return theTranslator->trPackages();
+ }
+ else if (m_fortranOpt)
+ {
+ return theTranslator->trModulesList();
+ }
+ else
+ {
+ return theTranslator->trNamespaceList();
+ }
+ }
+ TemplateVariant namespaceMembers() const
+ {
+ if (m_javaOpt || m_vhdlOpt)
+ {
+ return theTranslator->trPackageMembers();
+ }
+ else if (m_fortranOpt)
+ {
+ return theTranslator->trModulesMembers();
+ }
+ else
+ {
+ return theTranslator->trNamespaceMembers();
+ }
+ }
+ TemplateVariant fileList() const
+ {
+ return theTranslator->trFileList();
+ }
+ TemplateVariant fileMembers() const
+ {
+ return theTranslator->trFileMembers();
+ }
+ TemplateVariant relatedPagesDesc() const
+ {
+ return theTranslator->trRelatedPagesDescription();
+ }
+ TemplateVariant more() const
+ {
+ return theTranslator->trMore();
+ }
+ TemplateVariant detailedDesc() const
+ {
+ return theTranslator->trDetailedDescription();
+ }
+ Private()
+ {
+ //%% string generatedBy
+ insert("generatedby", new PropertyFunc(this,&Private::generatedBy));
+ //%% string generatedAt
+ insert("generatedAt", new PropertyFunc(this,&Private::generatedAt));
+ //%% string search
+ insert("search", new PropertyFunc(this,&Private::search));
+ //%% string mainPage
+ insert("mainPage", new PropertyFunc(this,&Private::mainPage));
+ //%% string classes
+ insert("classes", new PropertyFunc(this,&Private::classes));
+ //%% string classList
+ insert("classList", new PropertyFunc(this,&Private::classList));
+ //%% string classIndex
+ insert("classIndex", new PropertyFunc(this,&Private::classIndex));
+ //%% string classHierarchy
+ insert("classHierarchy", new PropertyFunc(this,&Private::classHierarchy));
+ //%% string classMembers
+ insert("classMembers", new PropertyFunc(this,&Private::classMembers));
+ //%% string modules
+ insert("modules", new PropertyFunc(this,&Private::modules));
+ //%% string namespaces
+ insert("namespaces", new PropertyFunc(this,&Private::namespaces));
+ //%% string files
+ insert("files", new PropertyFunc(this,&Private::files));
+ //%% string pages
+ insert("pages", new PropertyFunc(this,&Private::pages));
+ //%% string examples
+ insert("examples", new PropertyFunc(this,&Private::examples));
+ //%% string namespaceList
+ insert("namespaceList", new PropertyFunc(this,&Private::namespaceList));
+ //%% string namespaceMembers
+ insert("namespaceMembers",new PropertyFunc(this,&Private::namespaceMembers));
+ //%% srting fileList
+ insert("fileList", new PropertyFunc(this,&Private::fileList));
+ //%% string fileMembers
+ insert("fileMembers", new PropertyFunc(this,&Private::fileMembers));
+ //%% string relatedPagesDescripiton
+ insert("relatedPagesDesc",new PropertyFunc(this,&Private::relatedPagesDesc));
+ //%% string more
+ insert("more", new PropertyFunc(this,&Private::more));
+ //%% string detailedDescription
+ insert("detailedDesc", new PropertyFunc(this,&Private::detailedDesc));
+
+ m_javaOpt = Config_getBool("OPTIMIZE_OUTPUT_JAVA");
+ m_fortranOpt = Config_getBool("OPTIMIZE_FOR_FORTRAN");
+ m_vhdlOpt = Config_getBool("OPTIMIZE_OUTPUT_VHDL");
+ }
+ private:
+ bool m_javaOpt;
+ bool m_fortranOpt;
+ bool m_vhdlOpt;
+};
+//%% }
+
+TranslateContext::TranslateContext()
+{
+ p = new Private;
+}
+
+TranslateContext::~TranslateContext()
+{
+ delete p;
+}
+
+TemplateVariant TranslateContext::get(const char *n) const
+{
+ return p->get(n);
+}
+
+static TemplateVariant parseDoc(Definition *def,const QCString &file,int line,
+ const QCString &relPath,const QCString &docStr,bool isBrief)
+{
+ TemplateVariant result;
+ DocRoot *root = validatingParseDoc(file,line,def,0,docStr,TRUE,FALSE,0,isBrief,FALSE);
+ QGString docs;
+ {
+ FTextStream ts(&docs);
+ // TODO: support other generators
+ HtmlCodeGenerator codeGen(ts,relPath);
+ HtmlDocVisitor visitor(ts,codeGen,def);
+ root->accept(&visitor);
+ }
+ bool isEmpty = root->isEmpty();
+ if (isEmpty)
+ result = "";
+ else
+ result = TemplateVariant(docs);
+ result.setRaw(TRUE);
+ delete root;
+ return result;
+}
+
+//------------------------------------------------------------------------
+
+//%% struct Symbol: shared info for all symbols
+//%% {
+template<typename T>
+class DefinitionContext : public PropertyMapper<T>
+{
+ public:
+ DefinitionContext(const T *super,Definition *d) : m_def(d), m_detailsCached(FALSE)
+ {
+ //%% string name: the name of the symbol
+ PropertyMapper<T>::insert("name", new typename PropertyMapper<T>::PropertyFunc(super,&DefinitionContext::name));
+ //%% string relPath: the relative path to the root of the output (CREATE_SUBDIRS)
+ PropertyMapper<T>::insert("relPath", new typename PropertyMapper<T>::PropertyFunc(super,&DefinitionContext::relPath));
+ //%% string fileName: the file name of the output file associated with the symbol (without extension)
+ PropertyMapper<T>::insert("fileName", new typename PropertyMapper<T>::PropertyFunc(super,&DefinitionContext::fileName));
+ //%% string details: the detailed documentation for this symbol
+ PropertyMapper<T>::insert("details", new typename PropertyMapper<T>::PropertyFunc(super,&DefinitionContext::details));
+ //%% string brief: the brief description for this symbol
+ PropertyMapper<T>::insert("brief", new typename PropertyMapper<T>::PropertyFunc(super,&DefinitionContext::brief));
+ }
+ TemplateVariant fileName() const
+ {
+ return TemplateVariant(m_def->getOutputFileBase());
+ }
+ TemplateVariant name() const
+ {
+ return m_def->displayName();
+ }
+ TemplateVariant relPath() const
+ {
+ static bool createSubdirs = Config_getBool("CREATE_SUBDIRS");
+ return createSubdirs ? TemplateVariant("../../") : TemplateVariant("");
+ }
+ TemplateVariant details() const
+ {
+ if (!m_detailsCached)
+ {
+ m_details = parseDoc(m_def,m_def->docFile(),m_def->docLine(),
+ relPath().toString(),m_def->documentation(),FALSE);
+ m_detailsCached = TRUE;
+ }
+ return m_details;
+ }
+ TemplateVariant brief() const
+ {
+ if (!m_briefCached)
+ {
+ m_brief = parseDoc(m_def,m_def->briefFile(),m_def->briefLine(),
+ relPath().toString(),m_def->briefDescription(),TRUE);
+ m_briefCached = TRUE;
+ }
+ return m_brief;
+ }
+
+ private:
+ Definition *m_def;
+ mutable bool m_detailsCached;
+ mutable TemplateVariant m_details;
+ mutable bool m_briefCached;
+ mutable TemplateVariant m_brief;
+};
+//%% }
+
+//------------------------------------------------------------------------
+
+//%% struct Class(Symbol): class information
+//%% {
+class ClassContext::Private : public DefinitionContext<ClassContext::Private>
+{
+ public:
+ Private(ClassDef *cd) : DefinitionContext(this,cd) , m_classDef(cd)
+ {
+ insert("title", new PropertyFunc(this,&Private::title));
+ insert("highlight", new PropertyFunc(this,&Private::highlight));
+ insert("subhighlight", new PropertyFunc(this,&Private::subHighlight));
+ insert("hasBrief", new PropertyFunc(this,&Private::hasBrief));
+ insert("hasDetails", new PropertyFunc(this,&Private::hasDetails));
+ }
+ TemplateVariant title() const
+ {
+ return TemplateVariant(m_classDef->title());
+ }
+ TemplateVariant highlight() const
+ {
+ return TemplateVariant("classes");
+ }
+ TemplateVariant subHighlight() const
+ {
+ return TemplateVariant("");
+ }
+ TemplateVariant hasBrief() const
+ {
+ return m_classDef->hasBriefDescription();
+ }
+ TemplateVariant hasDetails() const
+ {
+ return m_classDef->hasDetailedDescription();
+ }
+ private:
+ ClassDef *m_classDef;
+};
+//%% }
+
+ClassContext::ClassContext(ClassDef *cd)
+{
+ p = new Private(cd);
+}
+
+ClassContext::~ClassContext()
+{
+ delete p;
+}
+
+TemplateVariant ClassContext::get(const char *n) const
+{
+ return p->get(n);
+}
+
+//------------------------------------------------------------------------
+
+//%% struct Namespace(Symbol): namespace information
+//%% {
+class NamespaceContext::Private : public DefinitionContext<NamespaceContext::Private>
+{
+ public:
+ Private(NamespaceDef *nd) : DefinitionContext(this,nd) , m_namespaceDef(nd)
+ {
+ insert("title", new PropertyFunc(this,&Private::title));
+ insert("highlight", new PropertyFunc(this,&Private::highlight));
+ insert("subhighlight", new PropertyFunc(this,&Private::subHighlight));
+ }
+ TemplateVariant title() const
+ {
+ return TemplateVariant(m_namespaceDef->title());
+ }
+ TemplateVariant highlight() const
+ {
+ return TemplateVariant("namespaces");
+ }
+ TemplateVariant subHighlight() const
+ {
+ return TemplateVariant("");
+ }
+ private:
+ NamespaceDef *m_namespaceDef;
+};
+//%% }
+
+NamespaceContext::NamespaceContext(NamespaceDef *nd)
+{
+ p = new Private(nd);
+}
+
+NamespaceContext::~NamespaceContext()
+{
+ delete p;
+}
+
+TemplateVariant NamespaceContext::get(const char *n) const
+{
+ return p->get(n);
+}
+
+//------------------------------------------------------------------------
+
+//%% struct File(Symbol): file information
+//%% {
+class FileContext::Private : public DefinitionContext<FileContext::Private>
+{
+ public:
+ Private(FileDef *fd) : DefinitionContext(this,fd) , m_fileDef(fd)
+ {
+ insert("title", new PropertyFunc(this,&Private::title));
+ insert("highlight", new PropertyFunc(this,&Private::highlight));
+ insert("subhighlight", new PropertyFunc(this,&Private::subHighlight));
+ }
+ TemplateVariant title() const
+ {
+ return TemplateVariant(m_fileDef->title());
+ }
+ TemplateVariant highlight() const
+ {
+ return TemplateVariant("files");
+ }
+ TemplateVariant subHighlight() const
+ {
+ return TemplateVariant("");
+ }
+ private:
+ FileDef *m_fileDef;
+};
+//%% }
+
+FileContext::FileContext(FileDef *fd)
+{
+ p = new Private(fd);
+}
+
+FileContext::~FileContext()
+{
+ delete p;
+}
+
+TemplateVariant FileContext::get(const char *n) const
+{
+ return p->get(n);
+}
+
+//------------------------------------------------------------------------
+
+//%% struct Dir(Symbol): directory information
+//%% {
+class DirContext::Private : public DefinitionContext<DirContext::Private>
+{
+ public:
+ Private(DirDef *dd) : DefinitionContext(this,dd) , m_dirDef(dd)
+ {
+ insert("title", new PropertyFunc(this,&Private::title));
+ insert("highlight", new PropertyFunc(this,&Private::highlight));
+ insert("subhighlight", new PropertyFunc(this,&Private::subHighlight));
+ insert("dirName", new PropertyFunc(this,&Private::dirName));
+ }
+ TemplateVariant title() const
+ {
+ return TemplateVariant(m_dirDef->shortTitle());
+ }
+ TemplateVariant highlight() const
+ {
+ return TemplateVariant("files");
+ }
+ TemplateVariant subHighlight() const
+ {
+ return TemplateVariant("");
+ }
+ TemplateVariant dirName() const
+ {
+ return TemplateVariant(m_dirDef->shortName());
+ }
+ private:
+ DirDef *m_dirDef;
+};
+//%% }
+
+DirContext::DirContext(DirDef *fd)
+{
+ p = new Private(fd);
+}
+
+DirContext::~DirContext()
+{
+ delete p;
+}
+
+TemplateVariant DirContext::get(const char *n) const
+{
+ return p->get(n);
+}
+
+
+//------------------------------------------------------------------------
+
+//%% struct Page(Symbol): page information
+//%% {
+class PageContext::Private : public DefinitionContext<PageContext::Private>
+{
+ public:
+ Private(PageDef *pd) : DefinitionContext(this,pd) , m_pageDef(pd)
+ {
+ insert("title", new PropertyFunc(this,&Private::title));
+ insert("highlight", new PropertyFunc(this,&Private::highlight));
+ insert("subhighlight", new PropertyFunc(this,&Private::subHighlight));
+ }
+ TemplateVariant title() const
+ {
+ return TemplateVariant(m_pageDef->title());
+ }
+ TemplateVariant highlight() const
+ {
+ return TemplateVariant("pages");
+ }
+ TemplateVariant subHighlight() const
+ {
+ return TemplateVariant("");
+ }
+ private:
+ PageDef *m_pageDef;
+};
+//%% }
+
+PageContext::PageContext(PageDef *pd)
+{
+ p = new Private(pd);
+}
+
+PageContext::~PageContext()
+{
+ delete p;
+}
+
+TemplateVariant PageContext::get(const char *n) const
+{
+ return p->get(n);
+}
+
+//------------------------------------------------------------------------
+
+//%% struct Module(Symbol): group information
+//%% {
+class ModuleContext::Private : public DefinitionContext<ModuleContext::Private>
+{
+ public:
+ Private(GroupDef *gd) : DefinitionContext(this,gd) , m_groupDef(gd)
+ {
+ insert("title", new PropertyFunc(this,&Private::title));
+ insert("highlight", new PropertyFunc(this,&Private::highlight));
+ insert("subhighlight", new PropertyFunc(this,&Private::subHighlight));
+ }
+ TemplateVariant title() const
+ {
+ return TemplateVariant(m_groupDef->groupTitle());
+ }
+ TemplateVariant highlight() const
+ {
+ return TemplateVariant("modules");
+ }
+ TemplateVariant subHighlight() const
+ {
+ return TemplateVariant("");
+ }
+ private:
+ GroupDef *m_groupDef;
+};
+//%% }
+
+ModuleContext::ModuleContext(GroupDef *gd)
+{
+ p = new Private(gd);
+}
+
+ModuleContext::~ModuleContext()
+{
+ delete p;
+}
+
+TemplateVariant ModuleContext::get(const char *n) const
+{
+ return p->get(n);
+}
+
+//------------------------------------------------------------------------
+
+//%% list ClassList[Class] : list of classes
+class ClassListContext::Private : public GenericNodeListContext<ClassContext>
+{
+ public:
+ void addClasses(const ClassSDict &classSDict)
+ {
+ ClassSDict::Iterator cli(classSDict);
+ ClassDef *cd;
+ for (cli.toFirst() ; (cd=cli.current()) ; ++cli )
+ {
+ if (cd->getLanguage()==SrcLangExt_VHDL &&
+ ((VhdlDocGen::VhdlClasses)cd->protection()==VhdlDocGen::PACKAGECLASS ||
+ (VhdlDocGen::VhdlClasses)cd->protection()==VhdlDocGen::PACKBODYCLASS)
+ ) // no architecture
+ {
+ continue;
+ }
+ if (cd->isLinkableInProject() && cd->templateMaster()==0)
+ {
+ append(new ClassContext(cd));
+ }
+ }
+ }
+};
+
+ClassListContext::ClassListContext()
+{
+ p = new Private;
+ p->addClasses(*Doxygen::classSDict);
+ p->addClasses(*Doxygen::hiddenClasses);
+}
+
+ClassListContext::~ClassListContext()
+{
+ delete p;
+}
+
+// TemplateListIntf
+int ClassListContext::count() const
+{
+ return p->count();
+}
+
+TemplateVariant ClassListContext::at(int index) const
+{
+ return p->at(index);
+}
+
+TemplateListIntf::ConstIterator *ClassListContext::createIterator() const
+{
+ return p->createIterator();
+}
+
+//------------------------------------------------------------------------
+
+//%% struct ClassInheritanceNode: node in inheritance tree
+//%% {
+class ClassInheritanceNodeContext::Private : public PropertyMapper<ClassInheritanceNodeContext::Private>
+{
+ public:
+ Private(ClassDef *cd) : m_classContext(cd)
+ {
+ //%% bool is_leaf_node: true if this node does not have any children
+ insert("is_leaf_node", new PropertyFunc(this,&Private::isLeafNode));
+ //%% ClassInheritance children: list of nested classes/namespaces
+ insert("children", new PropertyFunc(this,&Private::children));
+ //%% Class class: class info
+ insert("class", new PropertyFunc(this,&Private::getClass));
+ }
+ 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());
+ }
+
+ 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
+ {
+ return TemplateVariant(&m_classContext);
+ }
+ private:
+ GenericNodeListContext<ClassInheritanceNodeContext> m_children;
+ ClassContext m_classContext;
+};
+//%% }
+
+ClassInheritanceNodeContext::ClassInheritanceNodeContext(ClassDef *cd)
+{
+ 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);
+}
+
+//------------------------------------------------------------------------
+
+//%% list ClassInheritance[ClassInheritanceNode]: list of classes
+class ClassInheritanceContext::Private : public
+ GenericNodeListContext<ClassInheritanceNodeContext>
+{
+ public:
+ void addClasses(const ClassSDict &classSDict)
+ {
+ 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
+ ClassInheritanceNodeContext *tnc = new ClassInheritanceNodeContext(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;
+ }
+ }
+ }
+ }
+ }
+};
+
+ClassInheritanceContext::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();
+}
+
+//------------------------------------------------------------------------
+
+//%% struct ClassHierarchy: inheritance tree
+//%% {
+class ClassHierarchyContext::Private : public PropertyMapper<ClassHierarchyContext::Private>
+{
+ public:
+ TemplateVariant tree() const
+ {
+ return TemplateVariant(&m_classTree);
+ }
+ TemplateVariant fileName() const
+ {
+ return "hierarchy";
+ }
+ TemplateVariant relPath() const
+ {
+ return "";
+ }
+ TemplateVariant highlight() const
+ {
+ return "classes";
+ }
+ TemplateVariant subhighlight() const
+ {
+ return "classhierarchy";
+ }
+ TemplateVariant title() const
+ {
+ static bool vhdlOpt = Config_getBool("OPTIMIZE_OUTPUT_VHDL");
+ if (vhdlOpt)
+ {
+ return VhdlDocGen::trDesignUnitHierarchy();
+ }
+ else
+ {
+ return theTranslator->trClassHierarchy();
+ }
+ }
+ Private()
+ {
+ //%% ClassInheritance tree
+ insert("tree",new PropertyFunc(this,&Private::tree));
+ insert("fileName",new PropertyFunc(this,&Private::fileName));
+ insert("relPath",new PropertyFunc(this,&Private::relPath));
+ insert("highlight",new PropertyFunc(this,&Private::highlight));
+ insert("subhighlight",new PropertyFunc(this,&Private::subhighlight));
+ insert("title",new PropertyFunc(this,&Private::title));
+ }
+ private:
+ ClassInheritanceContext m_classTree;
+};
+//%% }
+
+ClassHierarchyContext::ClassHierarchyContext()
+{
+ p = new Private;
+}
+
+ClassHierarchyContext::~ClassHierarchyContext()
+{
+ delete p;
+}
+
+TemplateVariant ClassHierarchyContext::get(const char *name) const
+{
+ return p->get(name);
+}
+
+//------------------------------------------------------------------------
+
+//%% struct NestingNode: node is a nesting relation tree
+//%% {
+class NestingNodeContext::Private : public PropertyMapper<NestingNodeContext::Private>
+{
+ public:
+ Private(Definition *d,bool addCls) : m_def(d),
+ m_classContext(m_def->definitionType()==Definition::TypeClass?(ClassDef*)d:0),
+ m_namespaceContext(m_def->definitionType()==Definition::TypeNamespace?(NamespaceDef*)d:0)
+ {
+ //%% bool is_leaf_node: true if this node does not have any children
+ insert("is_leaf_node", new PropertyFunc(this,&Private::isLeafNode));
+ //%% Nesting children: list of nested classes/namespaces
+ insert("children", new PropertyFunc(this,&Private::children));
+ //%% [optional] Class class: class info (if this node represents a class)
+ insert("class", new PropertyFunc(this,&Private::getClass));
+ //%% [optional] Namespace namespace: namespace info (if this node represents a namespace)
+ insert("namespace", new PropertyFunc(this,&Private::getNamespace));
+ addNamespaces(addCls);
+ addClasses();
+ }
+ TemplateVariant isLeafNode() const
+ {
+ return m_children.count()==0;
+ }
+ TemplateVariant children() const
+ {
+ return TemplateVariant(&m_children);
+ }
+ TemplateVariant getClass() const
+ {
+ if (m_def->definitionType()==Definition::TypeClass)
+ {
+ return TemplateVariant(&m_classContext);
+ }
+ else
+ {
+ return TemplateVariant(FALSE);
+ }
+ }
+ TemplateVariant getNamespace() const
+ {
+ if (m_def->definitionType()==Definition::TypeNamespace)
+ {
+ return TemplateVariant(&m_namespaceContext);
+ }
+ else
+ {
+ return TemplateVariant(FALSE);
+ }
+ }
+ void addClasses()
+ {
+ ClassDef *cd = m_def->definitionType()==Definition::TypeClass ? (ClassDef*)m_def : 0;
+ if (cd && cd->getClassSDict())
+ {
+ m_children.addClasses(*cd->getClassSDict(),FALSE);
+ }
+ }
+ void addNamespaces(bool addClasses)
+ {
+ NamespaceDef *nd = m_def->definitionType()==Definition::TypeNamespace ? (NamespaceDef*)m_def : 0;
+ if (nd && nd->getNamespaceSDict())
+ {
+ m_children.addNamespaces(*nd->getNamespaceSDict(),FALSE,addClasses);
+ }
+ if (addClasses && nd && nd->getClassSDict())
+ {
+ m_children.addClasses(*nd->getClassSDict(),FALSE);
+ }
+ }
+ Definition *m_def;
+ private:
+ NestingContext m_children;
+ ClassContext m_classContext;
+ NamespaceContext m_namespaceContext;
+};
+//%% }
+
+NestingNodeContext::NestingNodeContext(Definition *d,bool addClass)
+{
+ p = new Private(d,addClass);
+}
+
+NestingNodeContext::~NestingNodeContext()
+{
+ delete p;
+}
+
+TemplateVariant NestingNodeContext::get(const char *n) const
+{
+ return p->get(n);
+}
+
+//------------------------------------------------------------------------
+
+//%% list Nesting[NestingNode]: namespace and class nesting relations
+class NestingContext::Private : public GenericNodeListContext<NestingNodeContext>
+{
+ public:
+ void addNamespaces(const NamespaceSDict &nsDict,bool rootOnly,bool addClasses)
+ {
+ NamespaceSDict::Iterator nli(nsDict);
+ NamespaceDef *nd;
+ for (nli.toFirst();(nd=nli.current());++nli)
+ {
+ if (nd->localName().find('@')==-1 &&
+ (!rootOnly || nd->getOuterScope()==Doxygen::globalScope))
+ {
+ bool hasChildren = namespaceHasVisibleChild(nd,addClasses);
+ bool isLinkable = nd->isLinkableInProject();
+ if (isLinkable || hasChildren)
+ {
+ NestingNodeContext *nnc = new NestingNodeContext(nd,addClasses);
+ append(nnc);
+ }
+ }
+ }
+ }
+ void addClasses(const ClassSDict &clDict,bool rootOnly)
+ {
+ ClassSDict::Iterator cli(clDict);
+ ClassDef *cd;
+ for (;(cd=cli.current());++cli)
+ {
+ if (cd->getLanguage()==SrcLangExt_VHDL)
+ {
+ if ((VhdlDocGen::VhdlClasses)cd->protection()==VhdlDocGen::PACKAGECLASS ||
+ (VhdlDocGen::VhdlClasses)cd->protection()==VhdlDocGen::PACKBODYCLASS
+ )// no architecture
+ {
+ continue;
+ }
+ }
+ if (!rootOnly ||
+ cd->getOuterScope()==0 ||
+ cd->getOuterScope()==Doxygen::globalScope
+ )
+ {
+ if (classVisibleInIndex(cd) && cd->templateMaster()==0)
+ {
+ NestingNodeContext *nnc = new NestingNodeContext(cd,TRUE);
+ append(nnc);
+ }
+ }
+ }
+ }
+};
+
+NestingContext::NestingContext()
+{
+ p = new Private;
+}
+
+NestingContext::~NestingContext()
+{
+ delete p;
+}
+
+// TemplateListIntf
+int NestingContext::count() const
+{
+ return p->count();
+}
+
+TemplateVariant NestingContext::at(int index) const
+{
+ return p->at(index);
+}
+
+TemplateListIntf::ConstIterator *NestingContext::createIterator() const
+{
+ return p->createIterator();
+}
+
+void NestingContext::addClasses(const ClassSDict &clDict,bool rootOnly)
+{
+ p->addClasses(clDict,rootOnly);
+}
+
+void NestingContext::addNamespaces(const NamespaceSDict &nsDict,bool rootOnly,bool addClasses)
+{
+ p->addNamespaces(nsDict,rootOnly,addClasses);
+}
+
+//------------------------------------------------------------------------
+
+//%% struct ClassTree: Class nesting relations
+//%% {
+class ClassTreeContext::Private : public PropertyMapper<ClassTreeContext::Private>
+{
+ public:
+ TemplateVariant tree() const
+ {
+ return TemplateVariant(&m_classTree);
+ }
+ TemplateVariant fileName() const
+ {
+ return "annotated";
+ }
+ TemplateVariant relPath() const
+ {
+ return "";
+ }
+ TemplateVariant highlight() const
+ {
+ return "classes";
+ }
+ TemplateVariant subhighlight() const
+ {
+ return "classlist";
+ }
+ TemplateVariant title() const
+ {
+ static bool fortranOpt = Config_getBool("OPTIMIZE_FOR_FORTRAN");
+ static bool vhdlOpt = Config_getBool("OPTIMIZE_OUTPUT_VHDL");
+ if (fortranOpt)
+ {
+ return theTranslator->trCompoundListFortran();
+ }
+ else if (vhdlOpt)
+ {
+ return VhdlDocGen::trDesignUnitList();
+ }
+ else
+ {
+ return theTranslator->trClasses();
+ }
+ }
+ Private()
+ {
+ if (Doxygen::namespaceSDict)
+ {
+ m_classTree.addNamespaces(*Doxygen::namespaceSDict,TRUE,TRUE);
+ }
+ if (Doxygen::classSDict)
+ {
+ m_classTree.addClasses(*Doxygen::classSDict,TRUE);
+ }
+ //%% Nesting tree
+ insert("tree", new PropertyFunc(this,&Private::tree));
+ insert("fileName", new PropertyFunc(this,&Private::fileName));
+ insert("relPath", new PropertyFunc(this,&Private::relPath));
+ insert("highlight", new PropertyFunc(this,&Private::highlight));
+ insert("subhighlight",new PropertyFunc(this,&Private::subhighlight));
+ insert("title", new PropertyFunc(this,&Private::title));
+ }
+ private:
+ NestingContext m_classTree;
+};
+//%% }
+
+ClassTreeContext::ClassTreeContext()
+{
+ p = new Private;
+}
+
+ClassTreeContext::~ClassTreeContext()
+{
+ delete p;
+}
+
+TemplateVariant ClassTreeContext::get(const char *name) const
+{
+ return p->get(name);
+}
+
+//------------------------------------------------------------------------
+
+//%% list NamespaceList[Namespace] : list of namespaces
+class NamespaceListContext::Private : public GenericNodeListContext<NamespaceContext>
+{
+ public:
+ void addNamespaces(const NamespaceSDict &nsDict)
+ {
+ NamespaceSDict::Iterator nli(nsDict);
+ NamespaceDef *nd;
+ for (nli.toFirst();(nd=nli.current());++nli)
+ {
+ if (nd->isLinkableInProject())
+ {
+ append(new NamespaceContext(nd));
+ }
+ }
+ }
+};
+
+NamespaceListContext::NamespaceListContext()
+{
+ p = new Private;
+ p->addNamespaces(*Doxygen::namespaceSDict);
+}
+
+NamespaceListContext::~NamespaceListContext()
+{
+ delete p;
+}
+
+// TemplateListIntf
+int NamespaceListContext::count() const
+{
+ return p->count();
+}
+
+TemplateVariant NamespaceListContext::at(int index) const
+{
+ return p->at(index);
+}
+
+TemplateListIntf::ConstIterator *NamespaceListContext::createIterator() const
+{
+ return p->createIterator();
+}
+
+//------------------------------------------------------------------------
+
+//%% struct NamespaceTree: tree of nested namespace
+//%% {
+class NamespaceTreeContext::Private : public PropertyMapper<NamespaceTreeContext::Private>
+{
+ public:
+ TemplateVariant tree() const
+ {
+ return TemplateVariant(&m_namespaceTree);
+ }
+ TemplateVariant fileName() const
+ {
+ return "namespaces";
+ }
+ TemplateVariant relPath() const
+ {
+ return "";
+ }
+ TemplateVariant highlight() const
+ {
+ return "namespaces";
+ }
+ TemplateVariant subhighlight() const
+ {
+ return "namespacelist";
+ }
+ TemplateVariant title() const
+ {
+ static bool javaOpt = Config_getBool("OPTIMIZE_OUTPUT_JAVA");
+ static bool fortranOpt = Config_getBool("OPTIMIZE_FOR_FORTRAN");
+ static bool vhdlOpt = Config_getBool("OPTIMIZE_OUTPUT_VHDL");
+ if (javaOpt || vhdlOpt)
+ {
+ return theTranslator->trPackages();
+ }
+ else if (fortranOpt)
+ {
+ return theTranslator->trModulesList();
+ }
+ else
+ {
+ return theTranslator->trNamespaceList();
+ }
+ }
+ Private()
+ {
+ if (Doxygen::namespaceSDict)
+ {
+ m_namespaceTree.addNamespaces(*Doxygen::namespaceSDict,TRUE,FALSE);
+ }
+ //%% Nesting tree
+ insert("tree", new PropertyFunc(this,&Private::tree));
+ insert("fileName", new PropertyFunc(this,&Private::fileName));
+ insert("relPath", new PropertyFunc(this,&Private::relPath));
+ insert("highlight", new PropertyFunc(this,&Private::highlight));
+ insert("subhighlight",new PropertyFunc(this,&Private::subhighlight));
+ insert("title", new PropertyFunc(this,&Private::title));
+ }
+ private:
+ NestingContext m_namespaceTree;
+};
+//%% }
+
+NamespaceTreeContext::NamespaceTreeContext()
+{
+ p = new Private;
+}
+
+NamespaceTreeContext::~NamespaceTreeContext()
+{
+ delete p;
+}
+
+TemplateVariant NamespaceTreeContext::get(const char *name) const
+{
+ return p->get(name);
+}
+
+//------------------------------------------------------------------------
+
+//%% list FileList[File] : list of files
+class FileListContext::Private : public GenericNodeListContext<FileContext>
+{
+ public:
+ void addFiles(const FileNameList &fnList)
+ {
+ // TODO: if FULL_PATH_NAMES is enabled, the ordering should be dir+file
+ FileNameListIterator fnli(fnList);
+ FileName *fn;
+ for (fnli.toFirst();(fn=fnli.current());++fnli)
+ {
+ FileNameIterator fni(*fn);
+ FileDef *fd;
+ for (fni.toFirst();(fd=fni.current());++fni)
+ {
+ bool doc = fd->isLinkableInProject();
+ bool src = fd->generateSourceFile();
+ bool nameOk = !fd->isDocumentationFile();
+ if (nameOk && (doc || src) && !fd->isReference())
+ {
+ append(new FileContext(fd));
+ }
+ }
+ }
+ }
+};
+
+FileListContext::FileListContext()
+{
+ p = new Private;
+ if (Doxygen::inputNameList) p->addFiles(*Doxygen::inputNameList);
+}
+
+FileListContext::~FileListContext()
+{
+ delete p;
+}
+
+// TemplateListIntf
+int FileListContext::count() const
+{
+ return p->count();
+}
+
+TemplateVariant FileListContext::at(int index) const
+{
+ return p->at(index);
+}
+
+TemplateListIntf::ConstIterator *FileListContext::createIterator() const
+{
+ return p->createIterator();
+}
+
+//------------------------------------------------------------------------
+
+//%% struct DirFileNode: node is a directory hierarchy
+//%% {
+class DirFileNodeContext::Private : public PropertyMapper<DirFileNodeContext::Private>
+{
+ public:
+ Private(Definition *d) : m_def(d),
+ m_dirContext (m_def->definitionType()==Definition::TypeDir ? (DirDef*)d : 0),
+ m_fileContext(m_def->definitionType()==Definition::TypeFile ? (FileDef*)d : 0)
+ {
+ //%% bool is_leaf_node: true if this node does not have any children
+ insert("is_leaf_node", new PropertyFunc(this,&Private::isLeafNode));
+ //%% DirFile children: list of nested classes/namespaces
+ insert("children", new PropertyFunc(this,&Private::children));
+ //%% [optional] Dir dir: directory info (if this node represents a directory)
+ insert("dir", new PropertyFunc(this,&Private::getDir));
+ //%% [optional] File file: file info (if this node represents a file)
+ insert("file", new PropertyFunc(this,&Private::getFile));
+ addDirFiles();
+ }
+ TemplateVariant isLeafNode() const
+ {
+ return m_children.count()==0;
+ }
+ TemplateVariant children() const
+ {
+ return TemplateVariant(&m_children);
+ }
+ TemplateVariant getDir() const
+ {
+ if (m_def->definitionType()==Definition::TypeDir)
+ {
+ return TemplateVariant(&m_dirContext);
+ }
+ else
+ {
+ return TemplateVariant(FALSE);
+ }
+ }
+ TemplateVariant getFile() const
+ {
+ if (m_def->definitionType()==Definition::TypeFile)
+ {
+ return TemplateVariant(&m_fileContext);
+ }
+ else
+ {
+ return TemplateVariant(FALSE);
+ }
+ }
+ void addDirFiles()
+ {
+ DirDef *dd = m_def->definitionType()==Definition::TypeDir ? (DirDef*)m_def : 0;
+ if (dd)
+ {
+ m_children.addDirs(dd->subDirs());
+ if (dd && dd->getFiles())
+ {
+ m_children.addFiles(*dd->getFiles());
+ }
+ }
+ }
+ private:
+ Definition *m_def;
+ DirFileContext m_children;
+ DirContext m_dirContext;
+ FileContext m_fileContext;
+};
+//%% }
+
+DirFileNodeContext::DirFileNodeContext(Definition *d)
+{
+ p = new Private(d);
+}
+
+DirFileNodeContext::~DirFileNodeContext()
+{
+ delete p;
+}
+
+TemplateVariant DirFileNodeContext::get(const char *n) const
+{
+ return p->get(n);
+}
+
+
+//------------------------------------------------------------------------
+
+//%% list DirFile[DirFileNode]: list of directories and/or files
+class DirFileContext::Private : public GenericNodeListContext<DirFileNodeContext>
+{
+ public:
+ void addDirs(const DirSDict &dirDict)
+ {
+ SDict<DirDef>::Iterator dli(dirDict);
+ DirDef *dd;
+ for (dli.toFirst();(dd=dli.current());++dli)
+ {
+ if (dd->getOuterScope()==Doxygen::globalScope)
+ {
+ append(new DirFileNodeContext(dd));
+ }
+ }
+ }
+ void addDirs(const DirList &dirList)
+ {
+ QListIterator<DirDef> li(dirList);
+ DirDef *dd;
+ for (li.toFirst();(dd=li.current());++li)
+ {
+ append(new DirFileNodeContext(dd));
+ }
+ }
+ void addFiles(const FileNameList &fnList)
+ {
+ FileNameListIterator fnli(fnList);
+ FileName *fn;
+ for (fnli.toFirst();(fn=fnli.current());++fnli)
+ {
+ FileNameIterator fni(*fn);
+ FileDef *fd;
+ for (;(fd=fni.current());++fni)
+ {
+ if (fd->getDirDef()==0) // top level file
+ {
+ append(new DirFileNodeContext(fd));
+ }
+ }
+ }
+ }
+ void addFiles(const FileList &fList)
+ {
+ QListIterator<FileDef> li(fList);
+ FileDef *fd;
+ for (li.toFirst();(fd=li.current());++li)
+ {
+ append(new DirFileNodeContext(fd));
+ }
+ }
+};
+
+DirFileContext::DirFileContext()
+{
+ p = new Private;
+}
+
+DirFileContext::~DirFileContext()
+{
+ delete p;
+}
+
+// TemplateListIntf
+int DirFileContext::count() const
+{
+ return p->count();
+}
+
+TemplateVariant DirFileContext::at(int index) const
+{
+ return p->at(index);
+}
+
+TemplateListIntf::ConstIterator *DirFileContext::createIterator() const
+{
+ return p->createIterator();
+}
+
+void DirFileContext::addDirs(const DirSDict &dirs)
+{
+ p->addDirs(dirs);
+}
+
+void DirFileContext::addDirs(const DirList &dirs)
+{
+ p->addDirs(dirs);
+}
+
+void DirFileContext::addFiles(const FileNameList &files)
+{
+ p->addFiles(files);
+}
+
+void DirFileContext::addFiles(const FileList &files)
+{
+ p->addFiles(files);
+}
+
+
+//------------------------------------------------------------------------
+
+//%% struct FileTree: tree of directories and files
+//%% {
+class FileTreeContext::Private : public PropertyMapper<FileTreeContext::Private>
+{
+ public:
+ TemplateVariant tree() const
+ {
+ return TemplateVariant(&m_dirFileTree);
+ }
+ TemplateVariant fileName() const
+ {
+ return "files";
+ }
+ TemplateVariant relPath() const
+ {
+ return "";
+ }
+ TemplateVariant highlight() const
+ {
+ return "files";
+ }
+ TemplateVariant subhighlight() const
+ {
+ return "filelist";
+ }
+ TemplateVariant title() const
+ {
+ return theTranslator->trFileList();
+ }
+ Private()
+ {
+ // Add dirs tree
+ if (Doxygen::directories)
+ {
+ m_dirFileTree.addDirs(*Doxygen::directories);
+ }
+ if (Doxygen::inputNameList)
+ {
+ m_dirFileTree.addFiles(*Doxygen::inputNameList);
+ }
+ //%% DirFile tree:
+ insert("tree", new PropertyFunc(this,&Private::tree));
+ insert("fileName", new PropertyFunc(this,&Private::fileName));
+ insert("relPath", new PropertyFunc(this,&Private::relPath));
+ insert("highlight", new PropertyFunc(this,&Private::highlight));
+ insert("subhighlight",new PropertyFunc(this,&Private::subhighlight));
+ insert("title", new PropertyFunc(this,&Private::title));
+ }
+ private:
+ DirFileContext m_dirFileTree;
+};
+//%% }
+
+FileTreeContext::FileTreeContext()
+{
+ p = new Private;
+}
+
+FileTreeContext::~FileTreeContext()
+{
+ delete p;
+}
+
+TemplateVariant FileTreeContext::get(const char *name) const
+{
+ return p->get(name);
+}
+
+//------------------------------------------------------------------------
+
+//%% struct PageNode: node is a directory hierarchy
+//%% {
+class PageNodeContext::Private : public PropertyMapper<PageNodeContext::Private>
+{
+ public:
+ Private(PageDef *pd) : m_pageDef(pd), m_pageContext(pd)
+ {
+ //%% bool is_leaf_node: true if this node does not have any children
+ insert("is_leaf_node", new PropertyFunc(this,&Private::isLeafNode));
+ //%% PageList children: list of nested classes/namespaces
+ insert("children", new PropertyFunc(this,&Private::children));
+ //%% Page page: page info
+ insert("page", new PropertyFunc(this,&Private::getPage));
+ addPages();
+ }
+ TemplateVariant isLeafNode() const
+ {
+ return m_children.count()==0;
+ }
+ TemplateVariant children() const
+ {
+ return TemplateVariant(&m_children);
+ }
+ TemplateVariant getPage() const
+ {
+ return TemplateVariant(&m_pageContext);
+ }
+ void addPages()
+ {
+ if (m_pageDef->getSubPages())
+ {
+ m_children.addPages(*m_pageDef->getSubPages(),FALSE);
+ }
+ }
+ private:
+ PageDef *m_pageDef;
+ PageNodeListContext m_children;
+ PageContext m_pageContext;
+};
+//%% }
+
+PageNodeContext::PageNodeContext(PageDef *pd)
+{
+ p = new Private(pd);
+}
+
+PageNodeContext::~PageNodeContext()
+{
+ delete p;
+}
+
+TemplateVariant PageNodeContext::get(const char *n) const
+{
+ return p->get(n);
+}
+
+//------------------------------------------------------------------------
+
+//%% list PageList[PageNode]: list of directories and/or files
+class PageNodeListContext::Private : public GenericNodeListContext<PageNodeContext>
+{
+ public:
+ void addPages(const PageSDict &pages,bool rootOnly)
+ {
+ SDict<PageDef>::Iterator pli(pages);
+ PageDef *pd;
+ for (pli.toFirst();(pd=pli.current());++pli)
+ {
+ if (!rootOnly ||
+ pd->getOuterScope()==0 ||
+ pd->getOuterScope()->definitionType()!=Definition::TypePage)
+ {
+ append(new PageNodeContext(pd));
+ }
+ }
+ }
+};
+
+PageNodeListContext::PageNodeListContext()
+{
+ p = new Private;
+}
+
+PageNodeListContext::~PageNodeListContext()
+{
+ delete p;
+}
+
+// TemplateListIntf
+int PageNodeListContext::count() const
+{
+ return p->count();
+}
+
+TemplateVariant PageNodeListContext::at(int index) const
+{
+ return p->at(index);
+}
+
+TemplateListIntf::ConstIterator *PageNodeListContext::createIterator() const
+{
+ return p->createIterator();
+}
+
+void PageNodeListContext::addPages(const PageSDict &pages,bool rootOnly)
+{
+ p->addPages(pages,rootOnly);
+}
+
+//------------------------------------------------------------------------
+
+//%% struct PageTree: tree of related pages
+//%% {
+class PageTreeContext::Private : public PropertyMapper<PageTreeContext::Private>
+{
+ public:
+ TemplateVariant tree() const
+ {
+ return TemplateVariant(&m_pageList);
+ }
+ TemplateVariant fileName() const
+ {
+ return "pages";
+ }
+ TemplateVariant relPath() const
+ {
+ return "";
+ }
+ TemplateVariant highlight() const
+ {
+ return "pages";
+ }
+ TemplateVariant subhighlight() const
+ {
+ return "";
+ }
+ TemplateVariant title() const
+ {
+ return theTranslator->trRelatedPages();
+ }
+ Private()
+ {
+ // Add pages
+ if (Doxygen::pageSDict)
+ {
+ m_pageList.addPages(*Doxygen::pageSDict,TRUE);
+ }
+
+ //%% PageNodeList tree:
+ insert("tree", new PropertyFunc(this,&Private::tree));
+ insert("fileName", new PropertyFunc(this,&Private::fileName));
+ insert("relPath", new PropertyFunc(this,&Private::relPath));
+ insert("highlight", new PropertyFunc(this,&Private::highlight));
+ insert("subhighlight",new PropertyFunc(this,&Private::subhighlight));
+ insert("title", new PropertyFunc(this,&Private::title));
+ }
+ private:
+ PageNodeListContext m_pageList;
+};
+//%% }
+
+PageTreeContext::PageTreeContext()
+{
+ p = new Private;
+}
+
+PageTreeContext::~PageTreeContext()
+{
+ delete p;
+}
+
+TemplateVariant PageTreeContext::get(const char *name) const
+{
+ return p->get(name);
+}
+
+//------------------------------------------------------------------------
+
+//%% struct PageList: list of related pages
+//%% {
+class PageListContext::Private : public PropertyMapper<PageListContext::Private>
+{
+ public:
+ TemplateVariant items() const
+ {
+ return TemplateVariant(&m_pageList);
+ }
+ TemplateVariant fileName() const
+ {
+ return "pages";
+ }
+ TemplateVariant relPath() const
+ {
+ return "";
+ }
+ TemplateVariant highlight() const
+ {
+ return "pages";
+ }
+ TemplateVariant subhighlight() const
+ {
+ return "";
+ }
+ TemplateVariant title() const
+ {
+ return theTranslator->trRelatedPages();
+ }
+ Private()
+ {
+ // Add pages
+ PageSDict::Iterator pdi(*Doxygen::pageSDict);
+ PageDef *pd=0;
+ for (pdi.toFirst();(pd=pdi.current());++pdi)
+ {
+ if (!pd->getGroupDef() && !pd->isReference())
+ {
+ m_pageList.append(new PageContext(pd));
+ }
+ }
+
+ //%% list[Page] items:
+ insert("items", new PropertyFunc(this,&Private::items));
+ insert("fileName", new PropertyFunc(this,&Private::fileName));
+ insert("relPath", new PropertyFunc(this,&Private::relPath));
+ insert("highlight", new PropertyFunc(this,&Private::highlight));
+ insert("subhighlight",new PropertyFunc(this,&Private::subhighlight));
+ insert("title", new PropertyFunc(this,&Private::title));
+ }
+ private:
+ GenericNodeListContext<PageContext> m_pageList;
+};
+//%% }
+
+PageListContext::PageListContext()
+{
+ p = new Private;
+}
+
+PageListContext::~PageListContext()
+{
+ delete p;
+}
+
+TemplateVariant PageListContext::get(const char *name) const
+{
+ return p->get(name);
+}
+
+
+//------------------------------------------------------------------------
+
+//%% struct ModuleNode: node is a directory hierarchy
+//%% {
+class ModuleNodeContext::Private : public PropertyMapper<ModuleNodeContext::Private>
+{
+ public:
+ Private(GroupDef *gd) : m_groupDef(gd), m_moduleContext(gd)
+ {
+ //%% bool is_leaf_node: true if this node does not have any children
+ insert("is_leaf_node", new PropertyFunc(this,&Private::isLeafNode));
+ //%% ModuleList children: list of submodules
+ insert("children", new PropertyFunc(this,&Private::children));
+ //%% Module module: module info
+ insert("module", new PropertyFunc(this,&Private::getModule));
+ addModules();
+ }
+ TemplateVariant isLeafNode() const
+ {
+ return m_children.count()==0;
+ }
+ TemplateVariant children() const
+ {
+ return TemplateVariant(&m_children);
+ }
+ TemplateVariant getModule() const
+ {
+ return TemplateVariant(&m_moduleContext);
+ }
+ void addModules()
+ {
+ if (m_groupDef->getSubGroups())
+ {
+ m_children.addModules(*m_groupDef->getSubGroups());
+ }
+ }
+ private:
+ GroupDef *m_groupDef;
+ ModuleListContext m_children;
+ ModuleContext m_moduleContext;
+};
+//%% }
+
+ModuleNodeContext::ModuleNodeContext(GroupDef *gd)
+{
+ p = new Private(gd);
+}
+
+ModuleNodeContext::~ModuleNodeContext()
+{
+ delete p;
+}
+
+TemplateVariant ModuleNodeContext::get(const char *n) const
+{
+ return p->get(n);
+}
+
+//------------------------------------------------------------------------
+
+//%% list ModuleList[ModuleNode]: list of directories and/or files
+class ModuleListContext::Private : public GenericNodeListContext<ModuleNodeContext>
+{
+ public:
+ void addModules(const GroupSDict &modules)
+ {
+ static bool externalGroups = Config_getBool("EXTERNAL_GROUPS");
+ GroupSDict::Iterator gli(modules);
+ GroupDef *gd;
+ for (gli.toFirst();(gd=gli.current());++gli)
+ {
+ if (!gd->isASubGroup() && gd->isVisible() && (!gd->isReference() || externalGroups))
+ {
+ append(new ModuleNodeContext(gd));
+ }
+ }
+ }
+ void addModules(const GroupList &list)
+ {
+ QListIterator<GroupDef> gli(list);
+ GroupDef *gd;
+ for (gli.toFirst();(gd=gli.current());++gli)
+ {
+ append(new ModuleNodeContext(gd));
+ }
+ }
+};
+
+ModuleListContext::ModuleListContext()
+{
+ p = new Private;
+}
+
+ModuleListContext::~ModuleListContext()
+{
+ delete p;
+}
+
+// TemplateListIntf
+int ModuleListContext::count() const
+{
+ return p->count();
+}
+
+TemplateVariant ModuleListContext::at(int index) const
+{
+ return p->at(index);
+}
+
+TemplateListIntf::ConstIterator *ModuleListContext::createIterator() const
+{
+ return p->createIterator();
+}
+
+void ModuleListContext::addModules(const GroupSDict &modules)
+{
+ p->addModules(modules);
+}
+
+void ModuleListContext::addModules(const GroupList &modules)
+{
+ p->addModules(modules);
+}
+
+
+//------------------------------------------------------------------------
+
+//%% struct ModuleTree: tree of modules
+//%% {
+class ModuleTreeContext::Private : public PropertyMapper<ModuleTreeContext::Private>
+{
+ public:
+ TemplateVariant tree() const
+ {
+ return TemplateVariant(&m_moduleList);
+ }
+ TemplateVariant fileName() const
+ {
+ return "modules";
+ }
+ TemplateVariant relPath() const
+ {
+ return "";
+ }
+ TemplateVariant highlight() const
+ {
+ return "modules";
+ }
+ TemplateVariant subhighlight() const
+ {
+ return "";
+ }
+ TemplateVariant title() const
+ {
+ return theTranslator->trModules();
+ }
+ Private()
+ {
+ // Add modules
+ if (Doxygen::groupSDict)
+ {
+ m_moduleList.addModules(*Doxygen::groupSDict);
+ }
+
+ //%% ModuleList tree:
+ insert("tree", new PropertyFunc(this,&Private::tree));
+ insert("fileName", new PropertyFunc(this,&Private::fileName));
+ insert("relPath", new PropertyFunc(this,&Private::relPath));
+ insert("highlight", new PropertyFunc(this,&Private::highlight));
+ insert("subhighlight",new PropertyFunc(this,&Private::subhighlight));
+ insert("title", new PropertyFunc(this,&Private::title));
+ }
+ private:
+ ModuleListContext m_moduleList;
+};
+//%% }
+
+ModuleTreeContext::ModuleTreeContext()
+{
+ p = new Private;
+}
+
+ModuleTreeContext::~ModuleTreeContext()
+{
+ delete p;
+}
+
+TemplateVariant ModuleTreeContext::get(const char *name) const
+{
+ return p->get(name);
+}
+
+//------------------------------------------------------------------------
+
+//%% struct ExampleList: list of examples page
+//%% {
+class ExampleListContext::Private : public PropertyMapper<ExampleListContext::Private>
+{
+ public:
+ TemplateVariant items() const
+ {
+ return TemplateVariant(&m_pageList);
+ }
+ TemplateVariant fileName() const
+ {
+ return "examples";
+ }
+ TemplateVariant relPath() const
+ {
+ return "";
+ }
+ TemplateVariant highlight() const
+ {
+ return "examples";
+ }
+ TemplateVariant subhighlight() const
+ {
+ return "";
+ }
+ TemplateVariant title() const
+ {
+ return theTranslator->trExamples();
+ }
+ Private()
+ {
+ // Add pages
+ if (Doxygen::exampleSDict)
+ {
+ m_pageList.addPages(*Doxygen::exampleSDict,FALSE);
+ }
+
+ //%% PageNodeList items:
+ insert("items", new PropertyFunc(this,&Private::items));
+ insert("fileName", new PropertyFunc(this,&Private::fileName));
+ insert("relPath", new PropertyFunc(this,&Private::relPath));
+ insert("highlight", new PropertyFunc(this,&Private::highlight));
+ insert("subhighlight",new PropertyFunc(this,&Private::subhighlight));
+ insert("title", new PropertyFunc(this,&Private::title));
+ }
+ private:
+ PageNodeListContext m_pageList;
+};
+//%% }
+
+ExampleListContext::ExampleListContext()
+{
+ p = new Private;
+}
+
+ExampleListContext::~ExampleListContext()
+{
+ delete p;
+}
+
+TemplateVariant ExampleListContext::get(const char *name) const
+{
+ return p->get(name);
+}
+
+//------------------------------------------------------------------------
+
+class HtmlEscaper : public TemplateEscapeIntf
+{
+ public:
+ QCString escape(const QCString &s)
+ {
+ return convertToHtml(s,TRUE);
+ }
+};
+
+//------------------------------------------------------------------------
+
+void generateOutputViaTemplate()
+{
+ TemplateEngine e;
+ TemplateContext *ctx = e.createContext();
+ HtmlEscaper esc;
+ ctx->setEscapeIntf(&esc);
+ if (ctx)
+ {
+ DoxygenContext doxygen;
+ ConfigContext config;
+ TranslateContext tr;
+ ClassListContext classList;
+ ClassTreeContext classTree;
+ ClassHierarchyContext classHierarchy;
+ NamespaceListContext namespaceList;
+ NamespaceTreeContext namespaceTree;
+ FileListContext fileList;
+ FileTreeContext fileTree;
+ PageTreeContext pageTree;
+ PageListContext pageList;
+ ModuleTreeContext moduleTree;
+ ExampleListContext exampleList;
+
+ //%% Doxygen doxygen:
+ ctx->set("doxygen",&doxygen);
+ //%% Translator tr:
+ ctx->set("tr",&tr);
+ //%% Config config:
+ ctx->set("config",&config);
+ //%% ClassList classList:
+ ctx->set("classList",&classList); // not used for standard HTML
+ //%% ClassTree classTree:
+ ctx->set("classTree",&classTree);
+ // classIndex
+ //%% ClassHierarchy classHierarchy:
+ ctx->set("classHierarchy",&classHierarchy);
+ //%% NamespaceList namespaceList:
+ ctx->set("namespaceList",&namespaceList);
+ //%% NamespaceTree namespaceTree:
+ ctx->set("namespaceTree",&namespaceTree);
+ //%% FileList fileList:
+ ctx->set("fileList",&fileList);
+ //%% FileTree fileTree:
+ ctx->set("fileTree",&fileTree);
+ //%% PageList pageList
+ ctx->set("pageList",&pageList);
+ //%% PageTree pageTree
+ ctx->set("pageTree",&pageTree);
+ //%% ModuleTree moduleTree
+ ctx->set("moduleTree",&moduleTree);
+ //%% ExampleList exampleList
+ ctx->set("exampleList",&exampleList);
+
+ // render HTML output
+ Template *tpl = e.loadByName("htmllayout.tpl");
+ if (tpl)
+ {
+ ctx->setOutputDirectory(Config_getString("HTML_OUTPUT"));
+ FTextStream ts;
+ tpl->render(ts,ctx);
+ }
+
+ // TODO: render other outputs
+ }
+}
+
diff --git a/src/context.h b/src/context.h
new file mode 100644
index 0000000..4940403
--- /dev/null
+++ b/src/context.h
@@ -0,0 +1,535 @@
+#ifndef CONTEXT_H
+#define CONTEXT_H
+
+#include "template.h"
+
+class Definition;
+class ClassDef;
+class ClassSDict;
+class PageDef;
+class GroupDef;
+class NamespaceDef;
+class BaseClassList;
+class NamespaceSDict;
+class FileDef;
+class FileList;
+class FileNameList;
+class DirSDict;
+class DirList;
+class DirDef;
+class PageSDict;
+class GroupSDict;
+class GroupDef;
+class GroupList;
+
+//----------------------------------------------------
+
+class ConfigContext : public TemplateStructIntf
+{
+ public:
+ ConfigContext();
+ ~ConfigContext();
+
+ // TemplateStructIntf methods
+ virtual TemplateVariant get(const char *name) const;
+
+ private:
+ class Private;
+ Private *p;
+};
+
+//----------------------------------------------------
+
+class DoxygenContext : public TemplateStructIntf
+{
+ public:
+ DoxygenContext();
+ ~DoxygenContext();
+
+ // TemplateStructIntf methods
+ virtual TemplateVariant get(const char *name) const;
+
+ private:
+ class Private;
+ Private *p;
+};
+
+//----------------------------------------------------
+
+class TranslateContext : public TemplateStructIntf
+{
+ public:
+ TranslateContext();
+ ~TranslateContext();
+
+ // TemplateStructIntf methods
+ virtual TemplateVariant get(const char *name) const;
+
+ private:
+ class Private;
+ Private *p;
+};
+
+//----------------------------------------------------
+
+class ClassContext : public TemplateStructIntf
+{
+ public:
+ ClassContext(ClassDef *);
+ ~ClassContext();
+
+ // TemplateStructIntf methods
+ virtual TemplateVariant get(const char *name) const;
+
+ private:
+ class Private;
+ Private *p;
+};
+
+//----------------------------------------------------
+
+class NamespaceContext : public TemplateStructIntf
+{
+ public:
+ NamespaceContext(NamespaceDef *);
+ ~NamespaceContext();
+
+ // TemplateStructIntf methods
+ virtual TemplateVariant get(const char *name) const;
+
+ private:
+ class Private;
+ Private *p;
+};
+
+//----------------------------------------------------
+
+class FileContext : public TemplateStructIntf
+{
+ public:
+ FileContext(FileDef *);
+ ~FileContext();
+
+ // TemplateStructIntf methods
+ virtual TemplateVariant get(const char *name) const;
+
+ private:
+ class Private;
+ Private *p;
+};
+//----------------------------------------------------
+
+class DirContext : public TemplateStructIntf
+{
+ public:
+ DirContext(DirDef *);
+ ~DirContext();
+
+ // TemplateStructIntf methods
+ virtual TemplateVariant get(const char *name) const;
+
+ private:
+ class Private;
+ Private *p;
+};
+
+
+//----------------------------------------------------
+
+class PageContext : public TemplateStructIntf
+{
+ public:
+ PageContext(PageDef *);
+ ~PageContext();
+
+ // TemplateStructIntf methods
+ virtual TemplateVariant get(const char *name) const;
+
+ private:
+ class Private;
+ Private *p;
+};
+
+//----------------------------------------------------
+
+class ModuleContext : public TemplateStructIntf
+{
+ public:
+ ModuleContext(GroupDef *);
+ ~ModuleContext();
+
+ // TemplateStructIntf methods
+ virtual TemplateVariant get(const char *name) const;
+
+ private:
+ class Private;
+ Private *p;
+};
+
+//----------------------------------------------------
+
+class ClassListContext : public TemplateListIntf
+{
+ public:
+ ClassListContext();
+ ~ClassListContext();
+
+ // TemplateListIntf
+ virtual int count() const;
+ virtual TemplateVariant at(int index) const;
+ virtual TemplateListIntf::ConstIterator *createIterator() const;
+
+ private:
+ class Private;
+ Private *p;
+};
+
+//----------------------------------------------------
+
+class ClassInheritanceNodeContext : public TemplateStructIntf
+{
+ public:
+ ClassInheritanceNodeContext(ClassDef *);
+ ~ClassInheritanceNodeContext();
+
+ // TemplateStructIntf methods
+ virtual TemplateVariant get(const char *name) const;
+
+ void addChildren(const BaseClassList *bcl,bool hideSuper);
+ private:
+ class Private;
+ Private *p;
+};
+
+//----------------------------------------------------
+
+class ClassInheritanceContext : public TemplateListIntf
+{
+ public:
+ ClassInheritanceContext();
+ ~ClassInheritanceContext();
+
+ // TemplateListIntf
+ virtual int count() const;
+ virtual TemplateVariant at(int index) const;
+ virtual TemplateListIntf::ConstIterator *createIterator() const;
+
+ private:
+ class Private;
+ Private *p;
+};
+
+//----------------------------------------------------
+
+class ClassHierarchyContext : public TemplateStructIntf
+{
+ public:
+ ClassHierarchyContext();
+ ~ClassHierarchyContext();
+
+ // TemplateStructIntf methods
+ virtual TemplateVariant get(const char *name) const;
+
+ private:
+ class Private;
+ Private *p;
+};
+
+//----------------------------------------------------
+
+class NestingNodeContext : public TemplateStructIntf
+{
+ public:
+ NestingNodeContext(Definition *,bool addClasses);
+ ~NestingNodeContext();
+
+ // TemplateStructIntf methods
+ virtual TemplateVariant get(const char *name) const;
+
+ private:
+ class Private;
+ Private *p;
+};
+
+//----------------------------------------------------
+
+class NestingContext : public TemplateListIntf
+{
+ public:
+ NestingContext();
+ ~NestingContext();
+
+ // TemplateListIntf
+ virtual int count() const;
+ virtual TemplateVariant at(int index) const;
+ virtual TemplateListIntf::ConstIterator *createIterator() const;
+
+ void addNamespaces(const NamespaceSDict &nsDict,bool rootOnly,bool addClasses);
+ void addClasses(const ClassSDict &clDict,bool rootOnly);
+ private:
+ class Private;
+ Private *p;
+};
+
+//----------------------------------------------------
+
+class ClassTreeContext : public TemplateStructIntf
+{
+ public:
+ ClassTreeContext();
+ ~ClassTreeContext();
+
+ // TemplateStructIntf methods
+ virtual TemplateVariant get(const char *name) const;
+
+ private:
+ class Private;
+ Private *p;
+};
+
+//----------------------------------------------------
+
+class NamespaceListContext : public TemplateListIntf
+{
+ public:
+ NamespaceListContext();
+ ~NamespaceListContext();
+
+ // TemplateListIntf
+ virtual int count() const;
+ virtual TemplateVariant at(int index) const;
+ virtual TemplateListIntf::ConstIterator *createIterator() const;
+
+ private:
+ class Private;
+ Private *p;
+};
+
+//----------------------------------------------------
+
+class NamespaceTreeContext : public TemplateStructIntf
+{
+ public:
+ NamespaceTreeContext();
+ ~NamespaceTreeContext();
+
+ // TemplateStructIntf methods
+ virtual TemplateVariant get(const char *name) const;
+
+ private:
+ class Private;
+ Private *p;
+};
+
+//----------------------------------------------------
+
+class DirFileNodeContext : public TemplateStructIntf
+{
+ public:
+ DirFileNodeContext(Definition *);
+ ~DirFileNodeContext();
+
+ // TemplateStructIntf methods
+ virtual TemplateVariant get(const char *name) const;
+
+ private:
+ class Private;
+ Private *p;
+};
+
+//----------------------------------------------------
+
+class DirFileContext : public TemplateListIntf
+{
+ public:
+ DirFileContext();
+ ~DirFileContext();
+
+ // TemplateListIntf
+ virtual int count() const;
+ virtual TemplateVariant at(int index) const;
+ virtual TemplateListIntf::ConstIterator *createIterator() const;
+
+ void addDirs(const DirSDict &);
+ void addDirs(const DirList &);
+ void addFiles(const FileNameList &);
+ void addFiles(const FileList &);
+ private:
+ class Private;
+ Private *p;
+};
+
+//----------------------------------------------------
+
+class FileListContext : public TemplateListIntf
+{
+ public:
+ FileListContext();
+ ~FileListContext();
+
+ // TemplateListIntf
+ virtual int count() const;
+ virtual TemplateVariant at(int index) const;
+ virtual TemplateListIntf::ConstIterator *createIterator() const;
+
+ private:
+ class Private;
+ Private *p;
+};
+
+//----------------------------------------------------
+
+class FileTreeContext : public TemplateStructIntf
+{
+ public:
+ FileTreeContext();
+ ~FileTreeContext();
+
+ // TemplateStructIntf methods
+ virtual TemplateVariant get(const char *name) const;
+
+ private:
+ class Private;
+ Private *p;
+};
+
+//----------------------------------------------------
+
+class PageNodeContext : public TemplateStructIntf
+{
+ public:
+ PageNodeContext(PageDef *);
+ ~PageNodeContext();
+
+ // TemplateStructIntf methods
+ virtual TemplateVariant get(const char *name) const;
+
+ private:
+ class Private;
+ Private *p;
+};
+
+//----------------------------------------------------
+
+class PageNodeListContext : public TemplateListIntf
+{
+ public:
+ PageNodeListContext();
+ ~PageNodeListContext();
+
+ // TemplateListIntf
+ virtual int count() const;
+ virtual TemplateVariant at(int index) const;
+ virtual TemplateListIntf::ConstIterator *createIterator() const;
+
+ void addPages(const PageSDict &,bool rootOnly);
+ private:
+ class Private;
+ Private *p;
+};
+
+//----------------------------------------------------
+
+class PageListContext : public TemplateStructIntf
+{
+ public:
+ PageListContext();
+ ~PageListContext();
+
+ // TemplateStructIntf methods
+ virtual TemplateVariant get(const char *name) const;
+
+ private:
+ class Private;
+ Private *p;
+};
+
+//----------------------------------------------------
+
+class PageTreeContext : public TemplateStructIntf
+{
+ public:
+ PageTreeContext();
+ ~PageTreeContext();
+
+ // TemplateStructIntf methods
+ virtual TemplateVariant get(const char *name) const;
+
+ private:
+ class Private;
+ Private *p;
+};
+
+//----------------------------------------------------
+
+class ModuleNodeContext : public TemplateStructIntf
+{
+ public:
+ ModuleNodeContext(GroupDef *);
+ ~ModuleNodeContext();
+
+ // TemplateStructIntf methods
+ virtual TemplateVariant get(const char *name) const;
+
+ private:
+ class Private;
+ Private *p;
+};
+
+//----------------------------------------------------
+
+class ModuleListContext : public TemplateListIntf
+{
+ public:
+ ModuleListContext();
+ ~ModuleListContext();
+
+ // TemplateListIntf
+ virtual int count() const;
+ virtual TemplateVariant at(int index) const;
+ virtual TemplateListIntf::ConstIterator *createIterator() const;
+
+ void addModules(const GroupSDict &);
+ void addModules(const GroupList &);
+ private:
+ class Private;
+ Private *p;
+};
+
+//----------------------------------------------------
+
+class ModuleTreeContext : public TemplateStructIntf
+{
+ public:
+ ModuleTreeContext();
+ ~ModuleTreeContext();
+
+ // TemplateStructIntf methods
+ virtual TemplateVariant get(const char *name) const;
+
+ private:
+ class Private;
+ Private *p;
+};
+
+//----------------------------------------------------
+
+class ExampleListContext : public TemplateStructIntf
+{
+ public:
+ ExampleListContext();
+ ~ExampleListContext();
+
+ // TemplateStructIntf methods
+ virtual TemplateVariant get(const char *name) const;
+
+ private:
+ class Private;
+ Private *p;
+};
+
+//----------------------------------------------------
+
+void generateOutputViaTemplate();
+
+#endif
diff --git a/src/definition.cpp b/src/definition.cpp
index b259088..2140a59 100644
--- a/src/definition.cpp
+++ b/src/definition.cpp
@@ -1815,7 +1815,7 @@ int Definition::getEndBodyLine() const
return m_impl->body ? m_impl->body->endLine : -1;
}
-FileDef *Definition::getBodyDef()
+FileDef *Definition::getBodyDef() const
{
return m_impl->body ? m_impl->body->fileDef : 0;
}
diff --git a/src/definition.h b/src/definition.h
index 6b6e1d7..e3502a0 100644
--- a/src/definition.h
+++ b/src/definition.h
@@ -243,7 +243,7 @@ class Definition : public DefinitionIntf
/*! Returns the file in which the body of this item is located or 0 if no
* body is available.
*/
- FileDef *getBodyDef();
+ FileDef *getBodyDef() const;
/** Returns the programming language this definition was written in. */
SrcLangExt getLanguage() const;
diff --git a/src/dirdef.cpp b/src/dirdef.cpp
index fe6e47d..5df047a 100644
--- a/src/dirdef.cpp
+++ b/src/dirdef.cpp
@@ -329,12 +329,16 @@ void DirDef::endMemberDeclarations(OutputList &ol)
ol.endMemberSections();
}
+QCString DirDef::shortTitle() const
+{
+ return theTranslator->trDirReference(m_shortName);
+}
+
void DirDef::writeDocumentation(OutputList &ol)
{
static bool generateTreeView = Config_getBool("GENERATE_TREEVIEW");
ol.pushGeneratorState();
- QCString shortTitle=theTranslator->trDirReference(m_shortName);
QCString title=theTranslator->trDirReference(m_dispName);
startFile(ol,getOutputFileBase(),name(),title,HLI_None,!generateTreeView);
@@ -348,7 +352,7 @@ void DirDef::writeDocumentation(OutputList &ol)
startTitle(ol,getOutputFileBase());
ol.pushGeneratorState();
ol.disableAllBut(OutputGenerator::Html);
- ol.parseText(shortTitle);
+ ol.parseText(shortTitle());
ol.enableAll();
ol.disable(OutputGenerator::Html);
ol.parseText(title);
diff --git a/src/dirdef.h b/src/dirdef.h
index 99e2137..8b11b2e 100644
--- a/src/dirdef.h
+++ b/src/dirdef.h
@@ -66,6 +66,7 @@ class DirDef : public Definition
const QDict<UsedDir> *usedDirs() const { return m_usedDirs; }
bool isParentOf(DirDef *dir) const;
bool depGraphIsTrivial() const;
+ QCString shortTitle() const;
// generate output
void writeDocumentation(OutputList &ol);
diff --git a/src/doxygen.cpp b/src/doxygen.cpp
index 5b7ba1d..6f9a8bf 100644
--- a/src/doxygen.cpp
+++ b/src/doxygen.cpp
@@ -97,6 +97,7 @@
#include "docsets.h"
#include "formula.h"
#include "settings.h"
+#include "context.h"
#define RECURSE_ENTRYTREE(func,var) \
do { if (var->children()) { \
@@ -177,6 +178,7 @@ static QDict<FileDef> g_usingDeclarations(1009); // used classes
static FileStorage *g_storage = 0;
static bool g_successfulRun = FALSE;
static bool g_dumpSymbolMap = FALSE;
+static bool g_useOutputTemplate = FALSE;
void clearAll()
{
@@ -10230,6 +10232,12 @@ void readConfiguration(int argc, char **argv)
setvbuf(stdout,NULL,_IONBF,0);
Doxygen::outputToWizard=TRUE;
break;
+ case 'T':
+ msg("Warning: this option activates output generation via Django like template files. "
+ "This option is scheduled for doxygen 2.0, is currently incomplete and highly experimental! "
+ "Only use if you are a doxygen developer\n");
+ g_useOutputTemplate=TRUE;
+ break;
case 'h':
case '?':
usage(argv[0]);
@@ -11309,6 +11317,17 @@ void generateOutput()
Doxygen::formulaList->generateBitmaps(Config_getString("HTML_OUTPUT"));
g_s.end();
}
+
+ if (Config_getBool("SORT_GROUP_NAMES"))
+ {
+ Doxygen::groupSDict->sort();
+ GroupSDict::Iterator gli(*Doxygen::groupSDict);
+ GroupDef *gd;
+ for (gli.toFirst();(gd=gli.current());++gli)
+ {
+ gd->sortSubGroups();
+ }
+ }
writeMainPageTagFileData();
@@ -11475,6 +11494,8 @@ void generateOutput()
msg("finished...\n");
}
+ if (g_useOutputTemplate) generateOutputViaTemplate();
+
/**************************************************************************
* Start cleaning up *
**************************************************************************/
diff --git a/src/filedef.cpp b/src/filedef.cpp
index b12ecd3..e75c7b0 100644
--- a/src/filedef.cpp
+++ b/src/filedef.cpp
@@ -1794,3 +1794,9 @@ void FileDef::getAllIncludeFilesRecursively(QStrList &incFiles) const
QDict<void> includes(257);
::getAllIncludeFilesRecursively(&includes,this,incFiles);
}
+
+QCString FileDef::title() const
+{
+ return theTranslator->trFileReference(name());
+}
+
diff --git a/src/filedef.h b/src/filedef.h
index 9ccffc6..d1d7496 100644
--- a/src/filedef.h
+++ b/src/filedef.h
@@ -131,6 +131,8 @@ class FileDef : public Definition
MemberGroupSDict *getMemberGroupSDict() const { return m_memberGroupSDict; }
NamespaceSDict *getNamespaceSDict() const { return m_namespaceSDict; }
ClassSDict *getClassSDict() const { return m_classSDict; }
+
+ QCString title() const;
//---------------------------------
diff --git a/src/fortranscanner.l b/src/fortranscanner.l
index 2102a20..2102a20 100755..100644
--- a/src/fortranscanner.l
+++ b/src/fortranscanner.l
diff --git a/src/ftextstream.h b/src/ftextstream.h
index 9167ae9..d073f40 100644
--- a/src/ftextstream.h
+++ b/src/ftextstream.h
@@ -48,14 +48,14 @@ class FTextStream
inline FTextStream &FTextStream::operator<<( char c)
{
- m_dev->putch(c);
+ if (m_dev) m_dev->putch(c);
return *this;
}
inline FTextStream &FTextStream::operator<<( const char* s)
{
uint len = qstrlen( s );
- m_dev->writeBlock( s, len );
+ if (m_dev) m_dev->writeBlock( s, len );
return *this;
}
diff --git a/src/index.cpp b/src/index.cpp
index cfa3e02..ae96c80 100644
--- a/src/index.cpp
+++ b/src/index.cpp
@@ -414,38 +414,11 @@ void addMembersToIndex(T *def,LayoutDocManager::LayoutPart part,
}
}
-//----------------------------------------------------------------------------
-
-static bool classHasVisibleChildren(ClassDef *cd)
-{
- BaseClassList *bcl;
-
- if (cd->getLanguage()==SrcLangExt_VHDL) // reverse baseClass/subClass relation
- {
- if (cd->baseClasses()==0) return FALSE;
- bcl=cd->baseClasses();
- }
- else
- {
- if (cd->subClasses()==0) return FALSE;
- bcl=cd->subClasses();
- }
-
- BaseClassListIterator bcli(*bcl);
- for ( ; bcli.current() ; ++bcli)
- {
- if (bcli.current()->classDef->isVisibleInHierarchy())
- {
- return TRUE;
- }
- }
- return FALSE;
-}
//----------------------------------------------------------------------------
/*! Generates HTML Help tree of classes */
-static void writeClassTree(OutputList &ol,BaseClassList *bcl,bool hideSuper,int level,FTVHelp* ftv,bool addToIndex)
+static void writeClassTree(OutputList &ol,const BaseClassList *bcl,bool hideSuper,int level,FTVHelp* ftv,bool addToIndex)
{
if (bcl==0) return;
BaseClassListIterator bcli(*bcl);
@@ -562,14 +535,6 @@ static void writeClassTree(OutputList &ol,BaseClassList *bcl,bool hideSuper,int
//----------------------------------------------------------------------------
-static bool classVisibleInIndex(ClassDef *cd)
-{
- static bool allExternals = Config_getBool("ALLEXTERNALS");
- return (allExternals && cd->isLinkable()) || cd->isLinkableInProject();
-}
-
-//----------------------------------------------------------------------------
-
static bool dirHasVisibleChildren(DirDef *dd)
{
if (dd->hasDocumentation()) return TRUE;
@@ -1409,39 +1374,6 @@ void writeClassTree(ClassSDict *clDict,FTVHelp *ftv,bool addToIndex,bool globalO
}
}
-static bool containsVisibleChild(NamespaceDef *nd,bool includeClasses)
-{
- if (nd->getNamespaceSDict())
- {
- NamespaceSDict::Iterator cnli(*nd->getNamespaceSDict());
- NamespaceDef *cnd;
- for (cnli.toFirst();(cnd=cnli.current());++cnli)
- {
- if (cnd->isLinkable() && cnd->localName().find('@')==-1)
- {
- return TRUE;
- }
- else if (containsVisibleChild(cnd,includeClasses))
- {
- return TRUE;
- }
- }
- }
- if (includeClasses && nd->getClassSDict())
- {
- ClassSDict::Iterator cli(*nd->getClassSDict());
- ClassDef *cd;
- for (;(cd=cli.current());++cli)
- {
- if (cd->isLinkableInProject() && cd->templateMaster()==0)
- {
- return TRUE;
- }
- }
- }
- return FALSE;
-}
-
static void writeNamespaceTree(NamespaceSDict *nsDict,FTVHelp *ftv,
bool rootOnly,bool showClasses,bool addToIndex)
{
@@ -1455,7 +1387,7 @@ static void writeNamespaceTree(NamespaceSDict *nsDict,FTVHelp *ftv,
(!rootOnly || nd->getOuterScope()==Doxygen::globalScope))
{
- bool hasChildren = containsVisibleChild(nd,showClasses);
+ bool hasChildren = namespaceHasVisibleChild(nd,showClasses);
bool isLinkable = nd->isLinkableInProject();
QCString ref;
@@ -3562,7 +3494,6 @@ static void writeGroupTreeNode(OutputList &ol, GroupDef *gd, int level, FTVHelp*
if (gd->getSubGroups()->count()>0)
{
startIndexHierarchy(ol,level+1);
- if (Config_getBool("SORT_GROUP_NAMES")) gd->sortSubGroups();
QListIterator<GroupDef> gli(*gd->getSubGroups());
GroupDef *subgd = 0;
for (gli.toFirst();(subgd=gli.current());++gli)
@@ -3596,10 +3527,6 @@ static void writeGroupHierarchy(OutputList &ol, FTVHelp* ftv,bool addToIndex)
ol.disable(OutputGenerator::Html);
}
startIndexHierarchy(ol,0);
- if (Config_getBool("SORT_GROUP_NAMES"))
- {
- Doxygen::groupSDict->sort();
- }
GroupSDict::Iterator gli(*Doxygen::groupSDict);
GroupDef *gd;
for (gli.toFirst();(gd=gli.current());++gli)
diff --git a/src/libdoxygen.pro.in b/src/libdoxygen.pro.in
index 96b7b9e..b230b2f 100644
--- a/src/libdoxygen.pro.in
+++ b/src/libdoxygen.pro.in
@@ -30,6 +30,7 @@ HEADERS = arguments.h \
compound.xsd.h \
condparser.h \
config.h \
+ context.h \
constexp.h \
cppvalue.h \
debug.h \
@@ -129,6 +130,7 @@ HEADERS = arguments.h \
store.h \
tagreader.h \
tclscanner.h \
+ template.h \
textdocvisitor.h \
tooltip.h \
translator.h \
@@ -155,6 +157,7 @@ SOURCES = arguments.cpp \
commentcnv.cpp \
commentscan.cpp \
condparser.cpp \
+ context.cpp \
cppvalue.cpp \
dbusxmlscanner.cpp \
debug.cpp \
@@ -224,6 +227,7 @@ SOURCES = arguments.cpp \
store.cpp \
tagreader.cpp \
tclscanner.cpp \
+ template.cpp \
textdocvisitor.cpp \
tooltip.cpp \
util.cpp \
@@ -239,8 +243,8 @@ SOURCES = arguments.cpp \
win32:TMAKE_CXXFLAGS += -DQT_NODLL
win32-msvc:TMAKE_CXXFLAGS += -Zm200
-win32-g++:TMAKE_CXXFLAGS += -fno-exceptions -fno-rtti
-linux-g++:TMAKE_CXXFLAGS += -fno-exceptions -fno-rtti
+win32-g++:TMAKE_CXXFLAGS += -fno-exceptions
+linux-g++:TMAKE_CXXFLAGS += -fno-exceptions
INCLUDEPATH += ../qtools
#INCLUDEPATH += ../libpng
INCLUDEPATH += ../libmd5
diff --git a/src/namespacedef.cpp b/src/namespacedef.cpp
index ee1568e..b0ba6b4 100644
--- a/src/namespacedef.cpp
+++ b/src/namespacedef.cpp
@@ -460,27 +460,8 @@ void NamespaceDef::writeDocumentation(OutputList &ol)
static bool generateTreeView = Config_getBool("GENERATE_TREEVIEW");
//static bool outputJava = Config_getBool("OPTIMIZE_OUTPUT_JAVA");
//static bool fortranOpt = Config_getBool("OPTIMIZE_FOR_FORTRAN");
- SrcLangExt lang = getLanguage();
- QCString pageTitle;
- if (lang==SrcLangExt_Java || lang==SrcLangExt_CSharp)
- {
- pageTitle = theTranslator->trPackage(displayName());
- }
- else if (lang==SrcLangExt_Fortran)
- {
- pageTitle = theTranslator->trModuleReference(displayName());
- }
- else if (lang==SrcLangExt_IDL)
- {
- pageTitle = isConstantGroup()
- ? theTranslator->trConstantGroupReference(displayName())
- : theTranslator->trModuleReference(displayName());
- }
- else
- {
- pageTitle = theTranslator->trNamespaceReference(displayName());
- }
+ QCString pageTitle = title();
startFile(ol,getOutputFileBase(),name(),pageTitle,HLI_NamespaceVisible,!generateTreeView);
if (!generateTreeView)
@@ -522,6 +503,7 @@ void NamespaceDef::writeDocumentation(OutputList &ol)
//---------------------------------------- start flexible part -------------------------------
+ SrcLangExt lang = getLanguage();
QListIterator<LayoutDocEntry> eli(
LayoutDocManager::instance().docEntries(LayoutDocManager::Namespace));
LayoutDocEntry *lde;
@@ -1096,3 +1078,27 @@ MemberDef * NamespaceDef::getMemberByName(const QCString &n) const
return md;
}
+QCString NamespaceDef::title() const
+{
+ SrcLangExt lang = getLanguage();
+ QCString pageTitle;
+ if (lang==SrcLangExt_Java || lang==SrcLangExt_CSharp)
+ {
+ pageTitle = theTranslator->trPackage(displayName());
+ }
+ else if (lang==SrcLangExt_Fortran)
+ {
+ pageTitle = theTranslator->trModuleReference(displayName());
+ }
+ else if (lang==SrcLangExt_IDL)
+ {
+ pageTitle = isConstantGroup()
+ ? theTranslator->trConstantGroupReference(displayName())
+ : theTranslator->trModuleReference(displayName());
+ }
+ else
+ {
+ pageTitle = theTranslator->trNamespaceReference(displayName());
+ }
+ return pageTitle;
+}
diff --git a/src/namespacedef.h b/src/namespacedef.h
index ff64107..06d9d1d 100644
--- a/src/namespacedef.h
+++ b/src/namespacedef.h
@@ -92,6 +92,8 @@ class NamespaceDef : public Definition
/*! Returns the namespaces contained in this namespace */
NamespaceSDict *getNamespaceSDict() const { return namespaceSDict; }
+ QCString title() const;
+
bool visited;
private:
diff --git a/src/template.cpp b/src/template.cpp
new file mode 100644
index 0000000..3c60304
--- /dev/null
+++ b/src/template.cpp
@@ -0,0 +1,2968 @@
+#include "template.h"
+
+#include <stdio.h>
+#include <stdarg.h>
+
+#include <qlist.h>
+#include <qarray.h>
+#include <qdict.h>
+#include <qstrlist.h>
+#include <qvaluelist.h>
+#include <qstack.h>
+#include <qfile.h>
+#include <qregexp.h>
+
+#include "sortdict.h"
+#include "ftextstream.h"
+#include "message.h"
+#include "util.h"
+
+#define ENABLE_TRACING 0
+
+#if ENABLE_TRACING
+#define TRACE(x) printf x
+#else
+#define TRACE(x)
+#endif
+
+class TemplateToken;
+
+//-------------------------------------------------------------------
+
+static QValueList<QCString> split(const QCString &str,const QCString &sep,bool allowEmptyEntries=FALSE,bool cleanup=TRUE)
+{
+ QValueList<QCString> lst;
+
+ int j = 0;
+ int i = str.find( sep, j );
+
+ while (i!=-1)
+ {
+ if ( str.mid(j,i-j).length() > 0 )
+ {
+ if (cleanup)
+ {
+ lst.append(str.mid(j,i-j).stripWhiteSpace());
+ }
+ else
+ {
+ lst.append(str.mid(j,i-j));
+ }
+ }
+ else if (allowEmptyEntries)
+ {
+ lst.append("");
+ }
+ j = i + sep.length();
+ i = str.find(sep,j);
+ }
+
+ int l = str.length() - 1;
+ if (str.mid(j,l-j+1).length()>0)
+ {
+ if (cleanup)
+ {
+ lst.append(str.mid(j,l-j+1).stripWhiteSpace());
+ }
+ else
+ {
+ lst.append(str.mid(j,l-j+1));
+ }
+ }
+ else if (allowEmptyEntries)
+ {
+ lst.append("");
+ }
+
+ return lst;
+}
+
+//----------------------------------------------------------------------------
+
+#if ENABLE_TRACING
+static QCString replace(const char *s,char csrc,char cdst)
+{
+ QCString result = s;
+ for (char *p=result.data();*p;p++)
+ {
+ if (*p==csrc) *p=cdst;
+ }
+ return result;
+}
+#endif
+
+//- TemplateVariant implementation -------------------------------------------
+
+/** @brief Private data of a template variant object */
+class TemplateVariant::Private
+{
+ public:
+ Private() : raw(FALSE) {}
+ Type type;
+ int intVal;
+ QCString strVal;
+ bool boolVal;
+ const TemplateStructIntf *strukt;
+ const TemplateListIntf *list;
+ FuncType func;
+ const void *obj;
+ bool raw;
+};
+
+TemplateVariant::TemplateVariant()
+{
+ p = new Private;
+ p->type=None;
+}
+
+TemplateVariant::TemplateVariant(bool b)
+{
+ p = new Private;
+ p->type = Bool;
+ p->boolVal = b;
+}
+
+TemplateVariant::TemplateVariant(int v)
+{
+ p = new Private;
+ p->type = Integer;
+ p->intVal = v;
+}
+
+TemplateVariant::TemplateVariant(const char *s)
+{
+ p = new Private;
+ p->type = String;
+ p->strVal = s;
+}
+
+TemplateVariant::TemplateVariant(const QCString &s)
+{
+ p = new Private;
+ p->type = String;
+ p->strVal = s;
+}
+
+TemplateVariant::TemplateVariant(const TemplateStructIntf *s)
+{
+ p = new Private;
+ p->type = Struct;
+ p->strukt = s; }
+
+TemplateVariant::TemplateVariant(const TemplateListIntf *l)
+{
+ p = new Private;
+ p->type = List;
+ p->list = l;
+}
+
+TemplateVariant::TemplateVariant(const void *obj,FuncType f)
+{
+ p = new Private;
+ p->type = Function;
+ p->func = f;
+ p->obj = obj;
+}
+
+TemplateVariant::~TemplateVariant()
+{
+ delete p;
+}
+
+TemplateVariant::TemplateVariant(const TemplateVariant &v)
+{
+ p = new Private;
+ p->type = v.p->type;
+ p->raw = v.p->raw;
+ switch (p->type)
+ {
+ case None: break;
+ case Bool: p->boolVal = v.p->boolVal; break;
+ case Integer: p->intVal = v.p->intVal; break;
+ case String: p->strVal = v.p->strVal; break;
+ case Struct: p->strukt = v.p->strukt; break;
+ case List: p->list = v.p->list; break;
+ case Function: p->func = v.p->func;
+ p->obj = v.p->obj; break;
+ }
+}
+
+TemplateVariant &TemplateVariant::operator=(const TemplateVariant &v)
+{
+ p->type = v.p->type;
+ p->raw = v.p->raw;
+ switch (p->type)
+ {
+ case None: break;
+ case Bool: p->boolVal = v.p->boolVal; break;
+ case Integer: p->intVal = v.p->intVal; break;
+ case String: p->strVal = v.p->strVal; break;
+ case Struct: p->strukt = v.p->strukt; break;
+ case List: p->list = v.p->list; break;
+ case Function: p->func = v.p->func;
+ p->obj = v.p->obj; break;
+ }
+ return *this;
+}
+
+QCString TemplateVariant::toString() const
+{
+ QCString result;
+ switch (p->type)
+ {
+ case None:
+ break;
+ case Bool:
+ result=p->boolVal ? "true" : "false";
+ break;
+ case Integer:
+ result=QCString().setNum(p->intVal);
+ break;
+ case String:
+ result=p->strVal;
+ break;
+ case Struct:
+ result="[struct]";
+ break;
+ case List:
+ result="[list]";
+ break;
+ case Function:
+ result="[function]";
+ break;
+ }
+ return result;
+}
+
+bool TemplateVariant::toBool() const
+{
+ bool result=FALSE;
+ switch (p->type)
+ {
+ case None:
+ break;
+ case Bool:
+ result = p->boolVal;
+ break;
+ case Integer:
+ result = p->intVal!=0;
+ break;
+ case String:
+ result = !p->strVal.isEmpty() && p->strVal!="false" && p->strVal!="0";
+ break;
+ case Struct:
+ result = TRUE;
+ break;
+ case List:
+ result = p->list->count()!=0;
+ break;
+ case Function:
+ result = FALSE;
+ break;
+ }
+ return result;
+}
+
+int TemplateVariant::toInt() const
+{
+ int result=0;
+ switch (p->type)
+ {
+ case None:
+ break;
+ case Bool:
+ result = p->boolVal ? 1 : 0;
+ break;
+ case Integer:
+ result = p->intVal;
+ break;
+ case String:
+ result = p->strVal.toInt();
+ break;
+ case Struct:
+ break;
+ case List:
+ result = p->list->count();
+ break;
+ case Function:
+ result = 0;
+ break;
+ }
+ return result;
+}
+
+const TemplateStructIntf *TemplateVariant::toStruct() const
+{
+ return p->type==Struct ? p->strukt : 0;
+}
+
+const TemplateListIntf *TemplateVariant::toList() const
+{
+ return p->type==List ? p->list : 0;
+}
+
+QCString TemplateVariant::call(const QValueList<TemplateVariant> &args)
+{
+ if (p->type==Function) return p->func(p->obj,args);
+ return QCString();
+}
+
+bool TemplateVariant::operator==(TemplateVariant &other)
+{
+ if (p->type==None)
+ {
+ return FALSE;
+ }
+ if (p->type==TemplateVariant::List && other.p->type==TemplateVariant::List)
+ {
+ return p->list==other.p->list; // TODO: improve me
+ }
+ else if (p->type==TemplateVariant::Struct && other.p->type==TemplateVariant::Struct)
+ {
+ return p->strukt==other.p->strukt; // TODO: improve me
+ }
+ else
+ {
+ return toString()==other.toString();
+ }
+}
+
+TemplateVariant::Type TemplateVariant::type() const
+{
+ return p->type;
+}
+
+bool TemplateVariant::isValid() const
+{
+ return p->type!=None;
+}
+
+void TemplateVariant::setRaw(bool b)
+{
+ p->raw = b;
+}
+
+bool TemplateVariant::raw() const
+{
+ return p->raw;
+}
+
+//- Template struct implementation --------------------------------------------
+
+
+/** @brief Private data of a template struct object */
+class TemplateStruct::Private
+{
+ public:
+ Private() : fields(17)
+ { fields.setAutoDelete(TRUE); }
+ QDict<TemplateVariant> fields;
+};
+
+TemplateStruct::TemplateStruct()
+{
+ p = new Private;
+}
+
+TemplateStruct::~TemplateStruct()
+{
+ delete p;
+}
+
+void TemplateStruct::set(const char *name,const TemplateVariant &v)
+{
+ TemplateVariant *pv = p->fields.find(name);
+ if (pv) // change existing field
+ {
+ *pv = v;
+ }
+ else // insert new field
+ {
+ p->fields.insert(name,new TemplateVariant(v));
+ }
+}
+
+TemplateVariant TemplateStruct::get(const char *name) const
+{
+ TemplateVariant *v = p->fields.find(name);
+ return v ? *v : TemplateVariant();
+}
+
+//- Template list implementation ----------------------------------------------
+
+
+/** @brief Private data of a template list object */
+class TemplateList::Private
+{
+ public:
+ Private() : index(-1) {}
+ QValueList<TemplateVariant> elems;
+ int index;
+};
+
+
+TemplateList::TemplateList()
+{
+ p = new Private;
+}
+
+TemplateList::~TemplateList()
+{
+ delete p;
+}
+
+int TemplateList::count() const
+{
+ return p->elems.count();
+}
+
+void TemplateList::append(const TemplateVariant &v)
+{
+ p->elems.append(v);
+}
+
+// iterator support
+class TemplateListConstIterator : public TemplateListIntf::ConstIterator
+{
+ public:
+ TemplateListConstIterator(const TemplateList &l) : m_list(l) { m_index=-1; }
+ virtual ~TemplateListConstIterator() {}
+ virtual void toFirst()
+ {
+ m_it = m_list.p->elems.begin();
+ m_index=0;
+ }
+ virtual void toLast()
+ {
+ m_it = m_list.p->elems.fromLast();
+ m_index=m_list.count()-1;
+ }
+ virtual void toNext()
+ {
+ if (m_it!=m_list.p->elems.end())
+ {
+ ++m_it;
+ ++m_index;
+ }
+ }
+ virtual void toPrev()
+ {
+ if (m_index>0)
+ {
+ --m_it;
+ --m_index;
+ }
+ else
+ {
+ m_index=-1;
+ }
+ }
+ virtual bool current(TemplateVariant &v) const
+ {
+ if (m_index<0 || m_it==m_list.p->elems.end())
+ {
+ v = TemplateVariant();
+ return FALSE;
+ }
+ else
+ {
+ v = *m_it;
+ return TRUE;
+ }
+ }
+ private:
+ const TemplateList &m_list;
+ QValueList<TemplateVariant>::ConstIterator m_it;
+ int m_index;
+};
+
+TemplateListIntf::ConstIterator *TemplateList::createIterator() const
+{
+ return new TemplateListConstIterator(*this);
+}
+
+TemplateVariant TemplateList::at(int index) const
+{
+ if (index>=0 && index<(int)p->elems.count())
+ {
+ return p->elems[index];
+ }
+ else
+ {
+ return TemplateVariant();
+ }
+}
+
+//- Operator types ------------------------------------------------------------
+
+/** @brief Class representing operators that can appear in template expressions */
+class Operator
+{
+ public:
+ /* Operator precedence (low to high)
+ or
+ and
+ not
+ in
+ ==, !=, <, >, <=, >=
+ |
+ :
+ */
+ enum Type
+ {
+ Or, And, Not, In, Equal, NotEqual, Less, Greater, LessEqual,
+ GreaterEqual, Filter, Colon, Last
+ };
+
+ static const char *toString(Type op)
+ {
+ switch(op)
+ {
+ case Or: return "or";
+ case And: return "and";
+ case Not: return "not";
+ case In: return "in";
+ case Equal: return "==";
+ case NotEqual: return "!=";
+ case Less: return "<";
+ case Greater: return ">";
+ case LessEqual: return "<=";
+ case GreaterEqual: return ">=";
+ case Filter: return "|";
+ case Colon: return ":";
+ case Last: return "?";
+ }
+ return "?";
+ }
+};
+
+//-----------------------------------------------------------------------------
+
+class TemplateNodeBlock;
+
+/** @brief Class holding stacks of blocks available in the context */
+class TemplateBlockContext
+{
+ public:
+ TemplateBlockContext();
+ TemplateNodeBlock *get(const QCString &name) const;
+ TemplateNodeBlock *pop(const QCString &name) const;
+ void add(TemplateNodeBlock *block);
+ void add(TemplateBlockContext *ctx);
+ void push(TemplateNodeBlock *block);
+ void clear();
+ private:
+ QDict< QList<TemplateNodeBlock> > m_blocks;
+};
+
+
+/** @brief Internal class representing the implementation of a template
+ * context */
+class TemplateContextImpl : public TemplateContext
+{
+ public:
+ TemplateContextImpl();
+ virtual ~TemplateContextImpl();
+
+ // TemplateContext methods
+ void push();
+ void pop();
+ void set(const char *name,const TemplateVariant &v);
+ TemplateVariant get(const QCString &name) const;
+ const TemplateVariant *getRef(const QCString &name) const;
+ void setOutputDirectory(const QCString &dir)
+ { m_outputDir = dir; }
+ void setEscapeIntf(TemplateEscapeIntf *intf)
+ { m_escapeIntf = intf; }
+
+ // internal methods
+ TemplateBlockContext *blockContext();
+ TemplateVariant getPrimary(const QCString &name) const;
+ void setLocation(const QCString &templateName,int line)
+ { m_templateName=templateName; m_line=line; }
+ QCString templateName() const { return m_templateName; }
+ int line() const { return m_line; }
+ QCString outputDirectory() const { return m_outputDir; }
+ TemplateEscapeIntf *escapeIntf() const { return m_escapeIntf; }
+
+ private:
+ QCString m_templateName;
+ int m_line;
+ QCString m_outputDir;
+ QList< QDict<TemplateVariant> > m_contextStack;
+ TemplateBlockContext m_blockContext;
+ TemplateEscapeIntf *m_escapeIntf;
+};
+
+//-----------------------------------------------------------------------------
+
+/** @brief The implementation of the "add" filter */
+class FilterAdd
+{
+ public:
+ static int variantIntValue(const TemplateVariant &v,bool &isInt)
+ {
+ isInt = v.type()==TemplateVariant::Integer;
+ if (!isInt && v.type()==TemplateVariant::String)
+ {
+ return v.toString().toInt(&isInt);
+ }
+ return isInt ? v.toInt() : 0;
+ }
+ static TemplateVariant apply(const TemplateVariant &v,const TemplateVariant &arg)
+ {
+ if (!v.isValid())
+ {
+ return arg;
+ }
+ bool lhsIsInt;
+ int lhsValue = variantIntValue(v,lhsIsInt);
+ bool rhsIsInt;
+ int rhsValue = variantIntValue(arg,rhsIsInt);
+ if (lhsIsInt && rhsIsInt)
+ {
+ return lhsValue+rhsValue;
+ }
+ else if (v.type()==TemplateVariant::String && arg.type()==TemplateVariant::String)
+ {
+ return TemplateVariant(v.toString() + arg.toString());
+ }
+ else
+ {
+ return v;
+ }
+ }
+};
+
+//-----------------------------------------------------------------------------
+
+/** @brief The implementation of the "prepend" filter */
+class FilterPrepend
+{
+ public:
+ static TemplateVariant apply(const TemplateVariant &v,const TemplateVariant &arg)
+ {
+ if (v.type()==TemplateVariant::String && arg.type()==TemplateVariant::String)
+ {
+ return TemplateVariant(arg.toString() + v.toString());
+ }
+ else
+ {
+ return v;
+ }
+ }
+};
+
+//--------------------------------------------------------------------
+
+/** @brief The implementation of the "length" filter */
+class FilterLength
+{
+ public:
+ static TemplateVariant apply(const TemplateVariant &v,const TemplateVariant &)
+ {
+ if (!v.isValid())
+ {
+ return TemplateVariant();
+ }
+ if (v.type()==TemplateVariant::List)
+ {
+ return TemplateVariant(v.toList()->count());
+ }
+ else if (v.type()==TemplateVariant::String)
+ {
+ return TemplateVariant((int)v.toString().length());
+ }
+ else
+ {
+ return TemplateVariant();
+ }
+ }
+};
+
+//--------------------------------------------------------------------
+
+/** @brief The implementation of the "default" filter */
+class FilterDefault
+{
+ public:
+ static TemplateVariant apply(const TemplateVariant &v,const TemplateVariant &arg)
+ {
+ if (!v.isValid())
+ {
+ return arg;
+ }
+ else if (v.type()==TemplateVariant::String && v.toString().isEmpty())
+ {
+ return arg;
+ }
+ else
+ {
+ return v;
+ }
+ }
+};
+
+//--------------------------------------------------------------------
+
+/** @brief The implementation of the "default" filter */
+class FilterStripPath
+{
+ public:
+ static TemplateVariant apply(const TemplateVariant &v,const TemplateVariant &)
+ {
+ if (!v.isValid() || v.type()!=TemplateVariant::String)
+ {
+ return v;
+ }
+ QCString result = v.toString();
+ int i=result.findRev('/');
+ if (i!=-1)
+ {
+ result=result.mid(i+1);
+ }
+ i=result.findRev('\\');
+ if (i!=-1)
+ {
+ result=result.mid(i+1);
+ }
+ return result;
+ }
+};
+
+//--------------------------------------------------------------------
+
+/** @brief The implementation of the "default" filter */
+class FilterNoWrap
+{
+ public:
+ static TemplateVariant apply(const TemplateVariant &v,const TemplateVariant &)
+ {
+ if (!v.isValid() || v.type()!=TemplateVariant::String)
+ {
+ return v;
+ }
+ QCString s = v.toString();
+ return substitute(s," ","&#160;");
+ }
+};
+
+
+//--------------------------------------------------------------------
+
+/** @brief Factory singleton for registering and creating filters */
+class TemplateFilterFactory
+{
+ public:
+ typedef TemplateVariant (FilterFunction)(const TemplateVariant &v,const TemplateVariant &arg);
+
+ static TemplateFilterFactory *instance()
+ {
+ static TemplateFilterFactory *instance = 0;
+ if (instance==0) instance = new TemplateFilterFactory;
+ return instance;
+ }
+
+ TemplateVariant apply(const QCString &name,const TemplateVariant &v,const TemplateVariant &arg, bool &ok)
+ {
+ FilterFunction *func = (FilterFunction*)m_registry.find(name);
+ if (func)
+ {
+ ok=TRUE;
+ return (*func)(v,arg);
+ }
+ else
+ {
+ ok=FALSE;
+ return v;
+ }
+ }
+
+ void registerFilter(const QCString &name,FilterFunction *func)
+ {
+ m_registry.insert(name,(void*)func);
+ }
+
+ /** @brief Helper class for registering a filter function */
+ template<class T> class AutoRegister
+ {
+ public:
+ AutoRegister<T>(const QCString &key)
+ {
+ TemplateFilterFactory::instance()->registerFilter(key,&T::apply);
+ }
+ };
+
+ private:
+ QDict<void> m_registry;
+};
+
+// register a handlers for each filter we support
+static TemplateFilterFactory::AutoRegister<FilterAdd> fAdd("add");
+static TemplateFilterFactory::AutoRegister<FilterPrepend> fPrepend("prepend");
+static TemplateFilterFactory::AutoRegister<FilterLength> fLength("length");
+static TemplateFilterFactory::AutoRegister<FilterDefault> fDefault("default");
+static TemplateFilterFactory::AutoRegister<FilterStripPath> fStripPath("strippath");
+static TemplateFilterFactory::AutoRegister<FilterNoWrap> fNoWrap("nowrap");
+
+//--------------------------------------------------------------------
+
+/** @brief Base class for all nodes in the abstract syntax tree of an
+ * expression.
+ */
+class ExprAst
+{
+ public:
+ virtual ~ExprAst() {}
+ virtual TemplateVariant resolve(TemplateContext *) { return TemplateVariant(); }
+};
+
+/** @brief Class representing a number in the AST */
+class ExprAstNumber : public ExprAst
+{
+ public:
+ ExprAstNumber(int num) : m_number(num)
+ { TRACE(("ExprAstNumber(%d)\n",num)); }
+ int number() const { return m_number; }
+ virtual TemplateVariant resolve(TemplateContext *) { return TemplateVariant(m_number); }
+ private:
+ int m_number;
+};
+
+/** @brief Class representing a variable in the AST */
+class ExprAstVariable : public ExprAst
+{
+ public:
+ ExprAstVariable(const char *name) : m_name(name)
+ { TRACE(("ExprAstVariable(%s)\n",name)); }
+ const QCString &name() const { return m_name; }
+ virtual TemplateVariant resolve(TemplateContext *c)
+ {
+ TemplateContextImpl *ci = dynamic_cast<TemplateContextImpl*>(c);
+ TemplateVariant v = c->get(m_name);
+ if (!v.isValid())
+ {
+ warn(ci->templateName(),ci->line(),"undefined variable '%s' in expression",m_name.data());
+ }
+ return v;
+ }
+ private:
+ QCString m_name;
+};
+
+/** @brief Class representing a filter in the AST */
+class ExprAstFilter : public ExprAst
+{
+ public:
+ ExprAstFilter(const char *name,ExprAst *arg) : m_name(name), m_arg(arg)
+ { TRACE(("ExprAstFilter(%s)\n",name)); }
+ ~ExprAstFilter() { delete m_arg; }
+ const QCString &name() const { return m_name; }
+ TemplateVariant apply(const TemplateVariant &v,TemplateContext *c)
+ {
+ TemplateContextImpl *ci = dynamic_cast<TemplateContextImpl*>(c);
+ TRACE(("Applying filter '%s' to '%s' (type=%d)\n",m_name.data(),v.toString().data(),v.type()));
+ TemplateVariant arg;
+ if (m_arg) arg = m_arg->resolve(c);
+ bool ok;
+ TemplateVariant result = TemplateFilterFactory::instance()->apply(m_name,v,arg,ok);
+ if (!ok)
+ {
+ warn(ci->templateName(),ci->line(),"unknown filter '%s'",m_name.data());
+ }
+ return result;
+ }
+ private:
+ QCString m_name;
+ ExprAst *m_arg;
+};
+
+/** @brief Class representing a filter applied to an expression in the AST */
+class ExprAstFilterAppl : public ExprAst
+{
+ public:
+ ExprAstFilterAppl(ExprAst *expr,ExprAstFilter *filter)
+ : m_expr(expr), m_filter(filter)
+ { TRACE(("ExprAstFilterAppl\n")); }
+ ~ExprAstFilterAppl() { delete m_expr; delete m_filter; }
+ virtual TemplateVariant resolve(TemplateContext *c)
+ {
+ return m_filter->apply(m_expr->resolve(c),c);
+ }
+ private:
+ ExprAst *m_expr;
+ ExprAstFilter *m_filter;
+};
+
+/** @brief Class representing a string literal in the AST */
+class ExprAstLiteral : public ExprAst
+{
+ public:
+ ExprAstLiteral(const char *lit) : m_literal(lit)
+ { TRACE(("ExprAstLiteral(%s)\n",lit)); }
+ const QCString &literal() const { return m_literal; }
+ virtual TemplateVariant resolve(TemplateContext *) { return TemplateVariant(m_literal); }
+ private:
+ QCString m_literal;
+};
+
+/** @brief Class representing a negation (not) operator in the AST */
+class ExprAstNegate : public ExprAst
+{
+ public:
+ ExprAstNegate(ExprAst *expr) : m_expr(expr)
+ { TRACE(("ExprAstNegate\n")); }
+ ~ExprAstNegate() { delete m_expr; }
+ virtual TemplateVariant resolve(TemplateContext *c)
+ { return TemplateVariant(!m_expr->resolve(c).toBool()); }
+ private:
+ ExprAst *m_expr;
+};
+
+/** @brief Class representing a binary operator in the AST */
+class ExprAstBinary : public ExprAst
+{
+ public:
+ ExprAstBinary(Operator::Type op,ExprAst *lhs,ExprAst *rhs)
+ : m_operator(op), m_lhs(lhs), m_rhs(rhs)
+ { TRACE(("ExprAstBinary %s\n",Operator::toString(op))); }
+ ~ExprAstBinary() { delete m_lhs; delete m_rhs; }
+ virtual TemplateVariant resolve(TemplateContext *c)
+ {
+ TemplateVariant lhs = m_lhs->resolve(c);
+ TemplateVariant rhs = m_rhs ? m_rhs->resolve(c) : TemplateVariant();
+ switch(m_operator)
+ {
+ case Operator::Or:
+ return TemplateVariant(lhs.toBool() || rhs.toBool());
+ case Operator::And:
+ return TemplateVariant(lhs.toBool() && rhs.toBool());
+ case Operator::Equal:
+ return TemplateVariant(lhs == rhs);
+ case Operator::NotEqual:
+ return TemplateVariant(!(lhs == rhs));
+ case Operator::Less:
+ if (lhs.type()==TemplateVariant::String && rhs.type()==TemplateVariant::String)
+ {
+ return lhs.toString()<rhs.toString();
+ }
+ else
+ {
+ return lhs.toInt()<rhs.toInt();
+ }
+ case Operator::Greater:
+ if (lhs.type()==TemplateVariant::String && rhs.type()==TemplateVariant::String)
+ {
+ return !(lhs.toString()<rhs.toString());
+ }
+ else
+ {
+ return lhs.toInt()>rhs.toInt();
+ }
+ case Operator::LessEqual:
+ if (lhs.type()==TemplateVariant::String && rhs.type()==TemplateVariant::String)
+ {
+ return lhs.toString()==rhs.toString() || lhs.toString()<rhs.toString();
+ }
+ else
+ {
+ return lhs.toInt()<=rhs.toInt();
+ }
+ case Operator::GreaterEqual:
+ if (lhs.type()==TemplateVariant::String && rhs.type()==TemplateVariant::String)
+ {
+ return lhs.toString()==rhs.toString() || !(lhs.toString()<rhs.toString());
+ }
+ else
+ {
+ return lhs.toInt()>=rhs.toInt();
+ }
+ default:
+ return TemplateVariant();
+ }
+ }
+ private:
+ Operator::Type m_operator;
+ ExprAst *m_lhs;
+ ExprAst *m_rhs;
+};
+
+//--------------------------------------------------------------------
+
+/** @brief Recursive decent parser for Django style template expressions.
+ */
+class ExpressionParser
+{
+ public:
+ ExpressionParser(const QCString &templateName,int line)
+ : m_templateName(templateName), m_line(line), m_tokenStream(0)
+ {
+ }
+ virtual ~ExpressionParser()
+ {
+ }
+
+ ExprAst *parse(const char *expr)
+ {
+ if (expr==0) return 0;
+ m_tokenStream = expr;
+ getNextToken();
+ return parseOrExpression();
+ }
+
+ ExprAst *parsePrimary(const char *expr)
+ {
+ if (expr==0) return 0;
+ m_tokenStream = expr;
+ getNextToken();
+ return parsePrimaryExpression();
+ }
+
+ ExprAst *parseVariable(const char *varExpr)
+ {
+ if (varExpr==0) return 0;
+ m_tokenStream = varExpr;
+ getNextToken();
+ return parseFilteredVariable();
+ }
+
+ private:
+
+ /** @brief Class representing a token within an expression. */
+ class ExprToken
+ {
+ public:
+ ExprToken() : type(Unknown), num(-1), op(Operator::Or)
+ {
+ }
+ enum Type
+ {
+ Unknown, Operator, Number, Identifier, Literal
+ };
+
+ Type type;
+ int num;
+ QCString id;
+ Operator::Type op;
+ };
+
+ ExprAst *parseOrExpression()
+ {
+ TRACE(("{parseOrExpression(%s)\n",m_tokenStream));
+ ExprAst *lhs = parseAndExpression();
+ if (lhs)
+ {
+ while (m_curToken.type==ExprToken::Operator &&
+ m_curToken.op==Operator::Or)
+ {
+ getNextToken();
+ ExprAst *rhs = parseAndExpression();
+ lhs = new ExprAstBinary(Operator::Or,lhs,rhs);
+ }
+ }
+ TRACE(("}parseOrExpression(%s)\n",m_tokenStream));
+ return lhs;
+ }
+
+ ExprAst *parseAndExpression()
+ {
+ TRACE(("{parseAndExpression(%s)\n",m_tokenStream));
+ ExprAst *lhs = parseNotExpression();
+ if (lhs)
+ {
+ while (m_curToken.type==ExprToken::Operator &&
+ m_curToken.op==Operator::And)
+ {
+ getNextToken();
+ ExprAst *rhs = parseNotExpression();
+ lhs = new ExprAstBinary(Operator::And,lhs,rhs);
+ }
+ }
+ TRACE(("}parseAndExpression(%s)\n",m_tokenStream));
+ return lhs;
+ }
+
+ ExprAst *parseNotExpression()
+ {
+ TRACE(("{parseNotExpression(%s)\n",m_tokenStream));
+ ExprAst *result=0;
+ if (m_curToken.type==ExprToken::Operator &&
+ m_curToken.op==Operator::Not)
+ {
+ getNextToken();
+ ExprAst *expr = parseCompareExpression();
+ if (expr==0)
+ {
+ warn(m_templateName,m_line,"argument missing for not operator");
+ return 0;
+ }
+ result = new ExprAstNegate(expr);
+ }
+ else
+ {
+ result = parseCompareExpression();
+ }
+ TRACE(("}parseNotExpression(%s)\n",m_tokenStream));
+ return result;
+ }
+
+ ExprAst *parseCompareExpression()
+ {
+ TRACE(("{parseCompareExpression(%s)\n",m_tokenStream));
+ ExprAst *lhs = parsePrimaryExpression();
+ if (lhs)
+ {
+ Operator::Type op = m_curToken.op;
+ if (m_curToken.type==ExprToken::Operator &&
+ (op==Operator::Less ||
+ op==Operator::Greater ||
+ op==Operator::Equal ||
+ op==Operator::NotEqual ||
+ op==Operator::LessEqual ||
+ op==Operator::GreaterEqual
+ )
+ )
+ {
+ getNextToken();
+ ExprAst *rhs = parseNotExpression();
+ lhs = new ExprAstBinary(op,lhs,rhs);
+ }
+ }
+ TRACE(("}parseCompareExpression(%s)\n",m_tokenStream));
+ return lhs;
+ }
+
+ ExprAst *parsePrimaryExpression()
+ {
+ TRACE(("{parsePrimary(%s)\n",m_tokenStream));
+ ExprAst *result=0;
+ switch (m_curToken.type)
+ {
+ case ExprToken::Number:
+ result = parseNumber();
+ break;
+ case ExprToken::Identifier:
+ result = parseFilteredVariable();
+ break;
+ case ExprToken::Literal:
+ result = parseLiteral();
+ break;
+ default:
+ if (m_curToken.type==ExprToken::Operator)
+ {
+ warn(m_templateName,m_line,"unexpected operator '%s' in expression",
+ Operator::toString(m_curToken.op));
+ }
+ else
+ {
+ warn(m_templateName,m_line,"unexpected token in expression");
+ }
+ }
+ TRACE(("}parsePrimary(%s)\n",m_tokenStream));
+ return result;
+ }
+
+ ExprAst *parseNumber()
+ {
+ TRACE(("{parseNumber(%d)\n",m_curToken.num));
+ ExprAst *num = new ExprAstNumber(m_curToken.num);
+ getNextToken();
+ TRACE(("}parseNumber()\n"));
+ return num;
+ }
+
+ ExprAst *parseIdentifier()
+ {
+ TRACE(("{parseIdentifier(%s)\n",m_curToken.id.data()));
+ ExprAst *id = new ExprAstVariable(m_curToken.id);
+ getNextToken();
+ TRACE(("}parseIdentifier()\n"));
+ return id;
+ }
+
+ ExprAst *parseLiteral()
+ {
+ TRACE(("{parseLiteral(%s)\n",m_curToken.id.data()));
+ ExprAst *lit = new ExprAstLiteral(m_curToken.id);
+ getNextToken();
+ TRACE(("}parseLiteral()\n"));
+ return lit;
+ }
+
+ ExprAst *parseFilteredVariable()
+ {
+ TRACE(("{parseFilteredVariable()\n"));
+ ExprAst *expr = parseIdentifier();
+ 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(("}parseFilteredVariable()\n"));
+ return expr;
+ }
+
+ ExprAstFilter *parseFilter()
+ {
+ TRACE(("{parseFilter(%s)\n",m_curToken.id.data()));
+ QCString filterName = m_curToken.id;
+ getNextToken();
+ ExprAst *argExpr=0;
+ if (m_curToken.type==ExprToken::Operator &&
+ m_curToken.op==Operator::Colon)
+ {
+ getNextToken();
+ argExpr = parsePrimaryExpression();
+ }
+ ExprAstFilter *filter = new ExprAstFilter(filterName,argExpr);
+ TRACE(("}parseFilter()\n"));
+ return filter;
+ }
+
+
+ bool getNextToken()
+ {
+ const char *p = m_tokenStream;
+ char s[2];
+ s[1]=0;
+ if (p==0 || *p=='\0') return FALSE;
+ while (*p==' ') p++; // skip over spaces
+ char c=*p;
+ if (strncmp(p,"not ",4)==0)
+ {
+ m_curToken.type = ExprToken::Operator;
+ m_curToken.op = Operator::Not;
+ p+=4;
+ }
+ else if (strncmp(p,"and ",4)==0)
+ {
+ m_curToken.type = ExprToken::Operator;
+ m_curToken.op = Operator::And;
+ p+=4;
+ }
+ else if (strncmp(p,"or ",3)==0)
+ {
+ m_curToken.type = ExprToken::Operator;
+ m_curToken.op = Operator::Or;
+ p+=3;
+ }
+ else if (c=='=' && *(p+1)=='=')
+ {
+ m_curToken.type = ExprToken::Operator;
+ m_curToken.op = Operator::Equal;
+ p+=2;
+ }
+ else if (c=='!' && *(p+1)=='=')
+ {
+ m_curToken.type = ExprToken::Operator;
+ m_curToken.op = Operator::NotEqual;
+ p+=2;
+ }
+ else if (c=='<' && *(p+1)=='=')
+ {
+ m_curToken.type = ExprToken::Operator;
+ m_curToken.op = Operator::LessEqual;
+ p+=2;
+ }
+ else if (c=='>' && *(p+1)=='=')
+ {
+ m_curToken.type = ExprToken::Operator;
+ m_curToken.op = Operator::GreaterEqual;
+ p+=2;
+ }
+ else if (c=='<')
+ {
+ m_curToken.type = ExprToken::Operator;
+ m_curToken.op = Operator::Less;
+ p++;
+ }
+ else if (c=='>')
+ {
+ m_curToken.type = ExprToken::Operator;
+ m_curToken.op = Operator::Greater;
+ p++;
+ }
+ else if (c=='|')
+ {
+ m_curToken.type = ExprToken::Operator;
+ m_curToken.op = Operator::Filter;
+ p++;
+ }
+ else if (c==':')
+ {
+ m_curToken.type = ExprToken::Operator;
+ m_curToken.op = Operator::Colon;
+ p++;
+ }
+ else if ((c=='-' && *(p+1)>='0' && *(p+1)<='9') || (c>='0' && c<='9'))
+ {
+ m_curToken.type = ExprToken::Number;
+ const char *np = p;
+ if (c=='-') np++;
+ m_curToken.num = 0;
+ while (*np>='0' && *np<='9')
+ {
+ m_curToken.num*=10;
+ m_curToken.num+=*np-'0';
+ np++;
+ }
+ if (c=='-') m_curToken.num=-m_curToken.num;
+ p=np;
+ }
+ else if (c=='_' || (c>='a' && c<='z') || (c>='A' && c<='Z'))
+ {
+ m_curToken.type = ExprToken::Identifier;
+ s[0]=c;
+ m_curToken.id = s;
+ p++;
+ while ((c=*p) &&
+ (c=='_' || c=='.' ||
+ (c>='a' && c<='z') ||
+ (c>='A' && c<='Z') ||
+ (c>='0' && c<='9'))
+ )
+ {
+ s[0]=c;
+ m_curToken.id+=s;
+ p++;
+ }
+ }
+ else if (c=='"' || c=='\'')
+ {
+ m_curToken.type = ExprToken::Literal;
+ m_curToken.id.resize(0);
+ p++;
+ char tokenChar = c;
+ char cp=0;
+ while ((c=*p) && (c!=tokenChar || (c==tokenChar && cp=='\\')))
+ {
+ s[0]=c;
+ if (c!='\\' || cp=='\\') // don't add escapes
+ {
+ m_curToken.id+=s;
+ }
+ cp=c;
+ p++;
+ }
+ if (*p==tokenChar) p++;
+ }
+ else
+ {
+ m_curToken.type = ExprToken::Unknown;
+ char s[2];
+ s[0]=c;
+ s[1]=0;
+ warn(m_templateName,m_line,"Found unknown token %s while parsing %s",s,m_tokenStream);
+ m_curToken.id = s;
+ p++;
+ }
+ //TRACE(("token type=%d op=%d num=%d id=%s\n",
+ // m_curToken.type,m_curToken.op,m_curToken.num,m_curToken.id.data()));
+
+ m_tokenStream = p;
+ return TRUE;
+ }
+
+ ExprToken m_curToken;
+ QCString m_templateName;
+ int m_line;
+ const char *m_tokenStream;
+};
+
+//----------------------------------------------------------
+
+/** @brief Base class of all nodes in a template's AST */
+class TemplateNode
+{
+ public:
+ TemplateNode(TemplateNode *parent) : m_parent(parent) {}
+ virtual ~TemplateNode() {}
+
+ virtual void render(FTextStream &ts, TemplateContext *c) = 0;
+
+ TemplateNode *parent() { return m_parent; }
+
+ private:
+ TemplateNode *m_parent;
+};
+
+//----------------------------------------------------------
+
+/** @brief Parser for templates */
+class TemplateParser
+{
+ public:
+ TemplateParser(const QCString &templateName,QList<TemplateToken> &tokens);
+ void parse(TemplateNode *parent,int line,const QStrList &stopAt,
+ QList<TemplateNode> &nodes);
+ bool hasNextToken() const;
+ TemplateToken *takeNextToken();
+ void removeNextToken();
+ void prependToken(const TemplateToken *token);
+ const TemplateToken *currentToken() const;
+ QCString templateName() const { return m_templateName; }
+ private:
+ QCString m_templateName;
+ QList<TemplateToken> &m_tokens;
+};
+
+//----------------------------------------------------------
+
+/** @brief Class representing a lexical token in a template */
+class TemplateToken
+{
+ public:
+ enum Type { Text, Variable, Block };
+ TemplateToken(Type t,const char *d,int l) : type(t), data(d), line(l) {}
+ Type type;
+ QCString data;
+ int line;
+};
+
+//----------------------------------------------------------
+
+/** @brief Class representing a list of AST nodes in a template */
+class TemplateNodeList : public QList<TemplateNode>
+{
+ public:
+ TemplateNodeList()
+ {
+ setAutoDelete(TRUE);
+ }
+ void render(FTextStream &ts,TemplateContext *c)
+ {
+ TRACE(("{TemplateNodeList::render\n"));
+ QListIterator<TemplateNode> it(*this);
+ TemplateNode *tn=0;
+ for (it.toFirst();(tn=it.current());++it)
+ {
+ tn->render(ts,c);
+ }
+ TRACE(("}TemplateNodeList::render\n"));
+ }
+};
+
+//----------------------------------------------------------
+
+/** @brief Internal class representing the implementation of a template */
+class TemplateImpl : public TemplateNode, public Template
+{
+ public:
+ TemplateImpl(TemplateEngine *e,const QCString &name,const QCString &data);
+ void render(FTextStream &ts, TemplateContext *c);
+
+ TemplateEngine *engine() const { return m_engine; }
+ TemplateBlockContext *blockContext() { return &m_blockContext; }
+
+ private:
+ QCString m_name;
+ TemplateNodeList m_nodes;
+ TemplateEngine *m_engine;
+ TemplateBlockContext m_blockContext;
+};
+
+//----------------------------------------------------------
+
+
+TemplateContextImpl::TemplateContextImpl()
+ : m_templateName("<unknown>"), m_line(1), m_escapeIntf(0)
+{
+ m_contextStack.setAutoDelete(TRUE);
+ push();
+}
+
+TemplateContextImpl::~TemplateContextImpl()
+{
+ pop();
+}
+
+void TemplateContextImpl::set(const char *name,const TemplateVariant &v)
+{
+ TemplateVariant *pv = m_contextStack.first()->find(name);
+ if (pv)
+ {
+ m_contextStack.first()->remove(name);
+ }
+ m_contextStack.first()->insert(name,new TemplateVariant(v));
+}
+
+TemplateVariant TemplateContextImpl::get(const QCString &name) const
+{
+ int i=name.find('.');
+ if (i==-1) // simple name
+ {
+ return getPrimary(name);
+ }
+ else // obj.prop
+ {
+ TemplateVariant v;
+ QCString objName = name.left(i);
+ v = getPrimary(objName);
+ QCString propName = name.mid(i+1);
+ while (!propName.isEmpty())
+ {
+ //printf("getPrimary(%s) type=%d:%s\n",objName.data(),v.type(),v.toString().data());
+ if (v.type()==TemplateVariant::Struct)
+ {
+ i = propName.find(".");
+ int l = i==-1 ? propName.length() : i;
+ v = v.toStruct()->get(propName.left(l));
+ if (!v.isValid())
+ {
+ warn(m_templateName,m_line,"requesting non-existing property '%s' for object '%s'",propName.left(l).data(),objName.data());
+ }
+ if (i!=-1)
+ {
+ objName = propName.left(i);
+ propName = propName.mid(i+1);
+ }
+ else
+ {
+ propName.resize(0);
+ }
+ }
+ else if (v.type()==TemplateVariant::List)
+ {
+ i = propName.find(".");
+ int l = i==-1 ? propName.length() : i;
+ bool b;
+ int index = propName.left(l).toInt(&b);
+ if (b)
+ {
+ v = v.toList()->at(index);
+ }
+ else
+ {
+ warn(m_templateName,m_line,"list index '%s' is not valid",propName.data());
+ break;
+ }
+ if (i!=-1)
+ {
+ propName = propName.mid(i+1);
+ }
+ else
+ {
+ propName.resize(0);
+ }
+ }
+ else
+ {
+ warn(m_templateName,m_line,"using . on an object '%s' is not an struct or list",objName.data());
+ return TemplateVariant();
+ }
+ } while (i!=-1);
+ return v;
+ }
+}
+
+const TemplateVariant *TemplateContextImpl::getRef(const QCString &name) const
+{
+ QListIterator< QDict<TemplateVariant> > it(m_contextStack);
+ QDict<TemplateVariant> *dict;
+ for (it.toFirst();(dict=it.current());++it)
+ {
+ TemplateVariant *v = dict->find(name);
+ if (v) return v;
+ }
+ return 0; // not found
+}
+
+TemplateVariant TemplateContextImpl::getPrimary(const QCString &name) const
+{
+ const TemplateVariant *v = getRef(name);
+ return v ? *v : TemplateVariant();
+}
+
+void TemplateContextImpl::push()
+{
+ QDict<TemplateVariant> *dict = new QDict<TemplateVariant>;
+ dict->setAutoDelete(TRUE);
+ m_contextStack.prepend(dict);
+}
+
+void TemplateContextImpl::pop()
+{
+ if (!m_contextStack.removeFirst())
+ {
+ warn(m_templateName,m_line,"pop() called on empty context stack!\n");
+ }
+}
+
+TemplateBlockContext *TemplateContextImpl::blockContext()
+{
+ return &m_blockContext;
+}
+
+//----------------------------------------------------------
+
+/** @brief Class representing a piece of plain text in a template */
+class TemplateNodeText : public TemplateNode
+{
+ public:
+ TemplateNodeText(TemplateParser *,TemplateNode *parent,int,const QCString &data)
+ : TemplateNode(parent), m_data(data)
+ {
+ TRACE(("TemplateNodeText('%s')\n",replace(data,'\n',' ').data()));
+ }
+
+ void render(FTextStream &ts, TemplateContext *)
+ {
+ //printf("TemplateNodeText::render(%s)\n",m_data.data());
+ ts << m_data;
+ }
+ private:
+ QCString m_data;
+};
+
+//----------------------------------------------------------
+
+/** @brief Class representing a variable in a template */
+class TemplateNodeVariable : public TemplateNode
+{
+ public:
+ TemplateNodeVariable(TemplateParser *parser,TemplateNode *parent,int line,const QCString &var)
+ : TemplateNode(parent), m_templateName(parser->templateName()), m_line(line)
+ {
+ TRACE(("TemplateNodeVariable(%s)\n",var.data()));
+ ExpressionParser expParser(m_templateName,line);
+ int i=var.find(':');
+ int j=var.find('|');
+ if (i==-1 || (j!=-1 && j<i)) // no arguments or arg belongs to filter
+ {
+ m_var = expParser.parseVariable(var);
+ }
+ else
+ {
+ QValueList<QCString> args = split(var.mid(i+1),",");
+ for (uint j=0;j<args.count();j++)
+ {
+ ExprAst *expr = expParser.parsePrimary(args[j]);
+ if (expr)
+ {
+ m_args.append(expr);
+ }
+ }
+ m_var = expParser.parseVariable(var.left(i));
+ }
+ }
+ ~TemplateNodeVariable()
+ {
+ delete m_var;
+ }
+
+ void render(FTextStream &ts, TemplateContext *c)
+ {
+ TemplateContextImpl* ci = dynamic_cast<TemplateContextImpl*>(c);
+ ci->setLocation(m_templateName,m_line);
+ QValueList<TemplateVariant> args;
+ for (uint i=0;i<m_args.count();i++)
+ {
+ TemplateVariant v = m_args.at(i)->resolve(c);
+ args.append(v);
+ }
+ TemplateVariant v = m_var->resolve(c);
+ QCString value;
+ if (v.type()==TemplateVariant::Function)
+ {
+ value = v.call(args);
+ }
+ else
+ {
+ value = v.toString();
+ }
+ //printf("TemplateNodeVariable::render(%s) raw=%d\n",value.data(),v.raw());
+ if (ci->escapeIntf() && !v.raw())
+ {
+ ts << ci->escapeIntf()->escape(value);
+ }
+ else
+ {
+ ts << value;
+ }
+ }
+
+ private:
+ QCString m_templateName;
+ int m_line;
+ ExprAst *m_var;
+ QList<ExprAst> m_args;
+};
+
+//----------------------------------------------------------
+
+/** @brief Helper class for creating template AST tag nodes and returning
+ * the template for a given node.
+ */
+template<class T> class TemplateNodeCreator : public TemplateNode
+{
+ public:
+ TemplateNodeCreator(TemplateParser *parser,TemplateNode *parent,int line)
+ : TemplateNode(parent), m_templateName(parser->templateName()), m_line(line) {}
+ static TemplateNode *createInstance(TemplateParser *parser,
+ TemplateNode *parent,
+ int line,
+ const QCString &data)
+ {
+ return new T(parser,parent,line,data);
+ }
+ TemplateImpl *getTemplate()
+ {
+ TemplateNode *root = this;
+ while (root && root->parent())
+ {
+ root = root->parent();
+ }
+ return dynamic_cast<TemplateImpl*>(root);
+ }
+ protected:
+ QCString m_templateName;
+ int m_line;
+};
+
+//----------------------------------------------------------
+
+/** @brief Class representing an 'if' tag in a template */
+class TemplateNodeIf : public TemplateNodeCreator<TemplateNodeIf>
+{
+ public:
+ TemplateNodeIf(TemplateParser *parser,TemplateNode *parent,int line,const QCString &data) :
+ TemplateNodeCreator<TemplateNodeIf>(parser,parent,line)
+ {
+ TRACE(("{TemplateNodeIf(%s)\n",data.data()));
+ if (data.isEmpty())
+ {
+ warn(m_templateName,line,"missing argument for if tag");
+ }
+ QStrList stopAt;
+ stopAt.append("endif");
+ stopAt.append("else");
+ parser->parse(this,line,stopAt,m_trueNodes);
+ TemplateToken *tok = parser->takeNextToken();
+ ExpressionParser ex(parser->templateName(),line);
+ m_guardAst = ex.parse(data);
+
+ if (tok && tok->data=="else")
+ {
+ stopAt.removeLast();
+ parser->parse(this,line,stopAt,m_falseNodes);
+ parser->removeNextToken(); // skip over endif
+ }
+ delete tok;
+ TRACE(("}TemplateNodeIf(%s)\n",data.data()));
+ }
+ ~TemplateNodeIf()
+ {
+ delete m_guardAst;
+ }
+
+ void render(FTextStream &ts, TemplateContext *c)
+ {
+ dynamic_cast<TemplateContextImpl*>(c)->setLocation(m_templateName,m_line);
+ //printf("TemplateNodeIf::render #trueNodes=%d #falseNodes=%d\n",m_trueNodes.count(),m_falseNodes.count());
+ if (m_guardAst)
+ {
+ TemplateVariant guardValue = m_guardAst->resolve(c);
+ if (guardValue.toBool()) // guard is true, render corresponding nodes
+ {
+ m_trueNodes.render(ts,c);
+ }
+ else // guard is false, render corresponding nodes
+ {
+ m_falseNodes.render(ts,c);
+ }
+ }
+ }
+ private:
+ ExprAst *m_guardAst;
+ TemplateNodeList m_trueNodes;
+ TemplateNodeList m_falseNodes;
+};
+
+//----------------------------------------------------------
+
+/** @brief Class representing a 'for' tag in a template */
+class TemplateNodeFor : public TemplateNodeCreator<TemplateNodeFor>
+{
+ public:
+ TemplateNodeFor(TemplateParser *parser,TemplateNode *parent,int line,const QCString &data)
+ : TemplateNodeCreator<TemplateNodeFor>(parser,parent,line)
+ {
+ TRACE(("{TemplateNodeFor(%s)\n",data.data()));
+ QCString exprStr;
+ int i = data.find(" in ");
+ if (i==-1)
+ {
+ if (data.right(3)==" in")
+ {
+ warn(m_templateName,line,"for is missing container after 'in' keyword");
+ }
+ else if (data=="in")
+ {
+ warn(m_templateName,line,"for needs at least one iterator variable");
+ }
+ else
+ {
+ warn(m_templateName,line,"for is missing 'in' keyword");
+ }
+ }
+ else
+ {
+ m_vars = split(data.left(i),",");
+ if (m_vars.count()==0)
+ {
+ warn(m_templateName,line,"for needs at least one iterator variable");
+ }
+
+ int j = data.find(" reversed",i);
+ m_reversed = (j!=-1);
+
+ if (j==-1) j=data.length();
+ if (j>i+4)
+ {
+ exprStr = data.mid(i+4,j-i-4); // skip over " in " part
+ }
+ if (exprStr.isEmpty())
+ {
+ warn(m_templateName,line,"for is missing container after 'in' keyword");
+ }
+ }
+ ExpressionParser expParser(parser->templateName(),line);
+ m_expr = expParser.parseVariable(exprStr);
+
+ QStrList stopAt;
+ stopAt.append("endfor");
+ stopAt.append("empty");
+ parser->parse(this,line,stopAt,m_loopNodes);
+ TemplateToken *tok = parser->takeNextToken();
+ if (tok && tok->data=="empty")
+ {
+ stopAt.removeLast();
+ parser->parse(this,line,stopAt,m_emptyNodes);
+ parser->removeNextToken(); // skip over endfor
+ }
+ delete tok;
+ TRACE(("}TemplateNodeFor(%s)\n",data.data()));
+ }
+
+ ~TemplateNodeFor()
+ {
+ delete m_expr;
+ }
+
+ void render(FTextStream &ts, TemplateContext *c)
+ {
+ dynamic_cast<TemplateContextImpl*>(c)->setLocation(m_templateName,m_line);
+ //printf("TemplateNodeFor::render #loopNodes=%d #emptyNodes=%d\n",
+ // m_loopNodes.count(),m_emptyNodes.count());
+ if (m_expr)
+ {
+ TemplateVariant v = m_expr->resolve(c);
+ const TemplateListIntf *list = v.toList();
+ if (list)
+ {
+ uint listSize = list->count();
+ if (listSize==0) // empty for loop
+ {
+ m_emptyNodes.render(ts,c);
+ return;
+ }
+ c->push();
+ //int index = m_reversed ? list.count() : 0;
+ TemplateVariant v;
+ const TemplateVariant *parentLoop = c->getRef("forloop");
+ uint index = m_reversed ? listSize-1 : 0;
+ TemplateListIntf::ConstIterator *it = list->createIterator();
+ for (m_reversed ? it->toLast() : it->toFirst();
+ (it->current(v));
+ m_reversed ? it->toPrev() : it->toNext())
+ {
+ TemplateStruct s;
+ s.set("counter0", (int)index);
+ s.set("counter", (int)(index+1));
+ s.set("revcounter", (int)(listSize-index));
+ s.set("revcounter0", (int)(listSize-index-1));
+ s.set("first",index==0);
+ s.set("last", index==listSize-1);
+ s.set("parentloop",parentLoop ? *parentLoop : TemplateVariant());
+ c->set("forloop",&s);
+
+ // add variables for this loop to the context
+ //obj->addVariableToContext(index,m_vars,c);
+ uint vi=0;
+ if (m_vars.count()==1) // loop variable represents an item
+ {
+ c->set(m_vars[vi++],v);
+ }
+ else if (m_vars.count()>1 && v.type()==TemplateVariant::Struct)
+ // loop variables represent elements in a list item
+ {
+ for (uint i=0;i<m_vars.count();i++,vi++)
+ {
+ c->set(m_vars[vi],v.toStruct()->get(m_vars[vi]));
+ }
+ }
+ for (;vi<m_vars.count();vi++)
+ {
+ c->set(m_vars[vi],TemplateVariant());
+ }
+
+ // render all items for this iteration of the loop
+ m_loopNodes.render(ts,c);
+
+ if (m_reversed) index--; else index++;
+ }
+ c->pop();
+ delete it;
+ }
+ else // simple type...
+ {
+ warn(m_templateName,m_line,"for requires a variable of list type!");
+ }
+ }
+ }
+
+ private:
+ bool m_reversed;
+ ExprAst *m_expr;
+ QValueList<QCString> m_vars;
+ TemplateNodeList m_loopNodes;
+ TemplateNodeList m_emptyNodes;
+};
+
+//----------------------------------------------------------
+
+/** @brief Class representing a 'block' tag in a template */
+class TemplateNodeBlock : public TemplateNodeCreator<TemplateNodeBlock>
+{
+ public:
+ TemplateNodeBlock(TemplateParser *parser,TemplateNode *parent,int line,const QCString &data)
+ : TemplateNodeCreator<TemplateNodeBlock>(parser,parent,line)
+ {
+ TRACE(("{TemplateNodeBlock(%s)\n",data.data()));
+ m_blockName = data;
+ if (m_blockName.isEmpty())
+ {
+ warn(parser->templateName(),line,"block tag without name");
+ }
+ QStrList stopAt;
+ stopAt.append("endblock");
+ parser->parse(this,line,stopAt,m_nodes);
+ parser->removeNextToken(); // skip over endblock
+ TRACE(("}TemplateNodeBlock(%s)\n",data.data()));
+ }
+
+ void render(FTextStream &ts, TemplateContext *c)
+ {
+ TemplateContextImpl *ci = dynamic_cast<TemplateContextImpl*>(c);
+ ci->setLocation(m_templateName,m_line);
+ TemplateImpl *t = getTemplate();
+ if (t)
+ {
+ // remove block from the context, so block.super can work
+ TemplateNodeBlock *nb = ci->blockContext()->pop(m_blockName);
+ if (nb) // block is overruled
+ {
+ ci->push();
+ QGString super;
+ FTextStream ss(&super);
+ // get super block of block nb
+ TemplateNodeBlock *sb = ci->blockContext()->get(m_blockName);
+ if (sb && sb!=nb && sb!=this) // nb and sb both overrule this block
+ {
+ sb->render(ss,c); // render parent of nb to string
+ }
+ else if (nb!=this) // only nb overrules this block
+ {
+ m_nodes.render(ss,c); // render parent of nb to string
+ }
+ // add 'block.super' variable to allow access to parent block content
+ TemplateStruct superBlock;
+ superBlock.set("super",super.data());
+ ci->set("block",&superBlock);
+ // render the overruled block contents
+ nb->m_nodes.render(ts,c);
+ ci->pop();
+ // re-add block to the context
+ ci->blockContext()->push(nb);
+ }
+ else // block has no overrule
+ {
+ m_nodes.render(ts,c);
+ }
+ }
+ }
+
+ QCString name() const
+ {
+ return m_blockName;
+ }
+
+ private:
+ QCString m_blockName;
+ TemplateNodeList m_nodes;
+};
+
+//----------------------------------------------------------
+
+/** @brief Class representing a 'extend' tag in a template */
+class TemplateNodeExtend : public TemplateNodeCreator<TemplateNodeExtend>
+{
+ public:
+ TemplateNodeExtend(TemplateParser *parser,TemplateNode *parent,int line,const QCString &data)
+ : TemplateNodeCreator<TemplateNodeExtend>(parser,parent,line)
+ {
+ TRACE(("{TemplateNodeExtend(%s)\n",data.data()));
+ ExpressionParser ep(m_templateName,line);
+ if (data.isEmpty())
+ {
+ warn(m_templateName,line,"extend tag is missing template file argument");
+ }
+ m_extendExpr = ep.parsePrimary(data);
+ QStrList stopAt;
+ parser->parse(this,line,stopAt,m_nodes);
+ TRACE(("}TemplateNodeExtend(%s)\n",data.data()));
+ }
+ ~TemplateNodeExtend()
+ {
+ delete m_extendExpr;
+ }
+
+ void render(FTextStream &ts, TemplateContext *c)
+ {
+ dynamic_cast<TemplateContextImpl*>(c)->setLocation(m_templateName,m_line);
+ if (m_extendExpr==0) return;
+
+ QCString extendFile = m_extendExpr->resolve(c).toString();
+ if (extendFile.isEmpty())
+ {
+ warn(m_templateName,m_line,"invalid parameter for extend command");
+ }
+
+ // goto root of tree (template node)
+ TemplateImpl *t = getTemplate();
+ if (t)
+ {
+ TemplateImpl *baseTemplate = dynamic_cast<TemplateImpl*>(t->engine()->loadByName(extendFile));
+ if (baseTemplate)
+ {
+ // fill block context
+ TemplateContextImpl *ci = dynamic_cast<TemplateContextImpl*>(c);
+ TemplateBlockContext *bc = ci->blockContext();
+
+ // add overruling blocks to the context
+ QListIterator<TemplateNode> li(m_nodes);
+ TemplateNode *n;
+ for (li.toFirst();(n=li.current());++li)
+ {
+ TemplateNodeBlock *nb = dynamic_cast<TemplateNodeBlock*>(n);
+ if (nb)
+ {
+ bc->add(nb);
+ }
+ }
+
+ // render the base template with the given context
+ baseTemplate->render(ts,c);
+
+ // clean up
+ bc->clear();
+ delete baseTemplate;
+ }
+ else
+ {
+ warn(m_templateName,m_line,"failed to load template %s for extend",extendFile.data());
+ }
+ }
+ }
+
+ private:
+ ExprAst *m_extendExpr;
+ TemplateNodeList m_nodes;
+};
+
+/** @brief Class representing an 'include' tag in a template */
+class TemplateNodeInclude : public TemplateNodeCreator<TemplateNodeInclude>
+{
+ public:
+ TemplateNodeInclude(TemplateParser *parser,TemplateNode *parent,int line,const QCString &data)
+ : TemplateNodeCreator<TemplateNodeInclude>(parser,parent,line)
+ {
+ TRACE(("TemplateNodeInclude(%s)\n",data.data()));
+ ExpressionParser ep(m_templateName,line);
+ if (data.isEmpty())
+ {
+ warn(m_templateName,line,"include tag is missing template file argument");
+ }
+ m_includeExpr = ep.parsePrimary(data);
+ }
+ ~TemplateNodeInclude()
+ {
+ delete m_includeExpr;
+ }
+ void render(FTextStream &ts, TemplateContext *c)
+ {
+ dynamic_cast<TemplateContextImpl*>(c)->setLocation(m_templateName,m_line);
+ if (m_includeExpr)
+ {
+ QCString includeFile = m_includeExpr->resolve(c).toString();
+ if (includeFile.isEmpty())
+ {
+ warn(m_templateName,m_line,"invalid parameter for include command\n");
+ }
+ else
+ {
+ TemplateImpl *t = getTemplate();
+ if (t)
+ {
+ TemplateImpl *incTemplate = dynamic_cast<TemplateImpl*>(t->engine()->loadByName(includeFile));
+ if (incTemplate)
+ {
+ incTemplate->render(ts,c);
+ }
+ else
+ {
+ warn(m_templateName,m_line,"failed to load template '%s' for include",includeFile.data()?includeFile.data():"");
+ }
+ }
+ }
+ }
+ }
+
+ private:
+ ExprAst *m_includeExpr;
+};
+
+//----------------------------------------------------------
+
+/** @brief Class representing an 'instantiate' tag in a template */
+class TemplateNodeCreate : public TemplateNodeCreator<TemplateNodeCreate>
+{
+ public:
+ TemplateNodeCreate(TemplateParser *parser,TemplateNode *parent,int line,const QCString &data)
+ : TemplateNodeCreator<TemplateNodeCreate>(parser,parent,line)
+ {
+ TRACE(("TemplateNodeCreate(%s)\n",data.data()));
+ ExpressionParser ep(m_templateName,line);
+ if (data.isEmpty())
+ {
+ warn(m_templateName,line,"create tag is missing arguments");
+ }
+ int i = data.find(" from ");
+ if (i==-1)
+ {
+ if (data.right(3)==" from")
+ {
+ warn(m_templateName,line,"create is missing template name after 'from' keyword");
+ }
+ else if (data=="from")
+ {
+ warn(m_templateName,line,"create needs a file name and a template name");
+ }
+ else
+ {
+ warn(m_templateName,line,"create is missing 'from' keyword");
+ }
+ }
+ else
+ {
+ ExpressionParser ep(m_templateName,line);
+ m_fileExpr = ep.parsePrimary(data.left(i).stripWhiteSpace());
+ m_templateExpr = ep.parsePrimary(data.mid(i+6).stripWhiteSpace());
+ }
+ }
+ ~TemplateNodeCreate()
+ {
+ delete m_templateExpr;
+ delete m_fileExpr;
+ }
+ void render(FTextStream &, TemplateContext *c)
+ {
+ TemplateContextImpl* ci = dynamic_cast<TemplateContextImpl*>(c);
+ ci->setLocation(m_templateName,m_line);
+ if (m_templateExpr && m_fileExpr)
+ {
+ QCString templateFile = m_templateExpr->resolve(c).toString();
+ QCString outputFile = m_fileExpr->resolve(c).toString();
+ if (templateFile.isEmpty())
+ {
+ warn(m_templateName,m_line,"empty template name parameter for create command\n");
+ }
+ else if (outputFile.isEmpty())
+ {
+ warn(m_templateName,m_line,"empty file name parameter for create command\n");
+ }
+ else
+ {
+ TemplateImpl *t = getTemplate();
+ if (t)
+ {
+ TemplateImpl *createTemplate = dynamic_cast<TemplateImpl*>(t->engine()->loadByName(templateFile));
+ if (createTemplate)
+ {
+ if (!ci->outputDirectory().isEmpty())
+ {
+ outputFile.prepend(ci->outputDirectory()+"/");
+ }
+ QFile f(outputFile);
+ if (f.open(IO_WriteOnly))
+ {
+ FTextStream ts(&f);
+ createTemplate->render(ts,c);
+ delete createTemplate;
+ }
+ else
+ {
+ warn(m_templateName,m_line,"failed to open output file '%s' for create command",outputFile.data());
+ }
+ }
+ else
+ {
+ warn(m_templateName,m_line,"failed to load template '%s' for include",templateFile.data());
+ }
+ }
+ }
+ }
+ }
+
+ private:
+ ExprAst *m_templateExpr;
+ ExprAst *m_fileExpr;
+};
+
+//----------------------------------------------------------
+
+/** @brief Class representing an 'instantiate' tag in a template */
+class TemplateNodeTree : public TemplateNodeCreator<TemplateNodeTree>
+{
+ struct TreeContext
+ {
+ TreeContext(TemplateNodeTree *o,const TemplateListIntf *l,TemplateContext *c)
+ : object(o), list(l), templateCtx(c) {}
+ TemplateNodeTree *object;
+ const TemplateListIntf *list;
+ TemplateContext *templateCtx;
+ };
+ public:
+ TemplateNodeTree(TemplateParser *parser,TemplateNode *parent,int line,const QCString &data)
+ : TemplateNodeCreator<TemplateNodeTree>(parser,parent,line)
+ {
+ TRACE(("{TemplateNodeTree(%s)\n",data.data()));
+ ExpressionParser ep(m_templateName,line);
+ if (data.isEmpty())
+ {
+ warn(m_templateName,line,"recursetree tag is missing data argument");
+ }
+ m_treeExpr = ep.parsePrimary(data);
+ QStrList stopAt;
+ stopAt.append("endrecursetree");
+ parser->parse(this,line,stopAt,m_treeNodes);
+ parser->removeNextToken(); // skip over endrecursetree
+ TRACE(("}TemplateNodeTree(%s)\n",data.data()));
+ }
+ ~TemplateNodeTree()
+ {
+ delete m_treeExpr;
+ }
+ static QCString renderChildrenStub(const void *ctx, const QValueList<TemplateVariant> &)
+ {
+ return ((TreeContext*)ctx)->object->renderChildren((const TreeContext*)ctx);
+ }
+ QCString renderChildren(const TreeContext *ctx)
+ {
+ //printf("TemplateNodeTree::renderChildren(%d)\n",ctx->list->count());
+ // render all children of node to a string and return it
+ QGString result;
+ FTextStream ss(&result);
+ TemplateContext *c = ctx->templateCtx;
+ c->push();
+ TemplateVariant node;
+ TemplateListIntf::ConstIterator *it = ctx->list->createIterator();
+ for (it->toFirst();(it->current(node));it->toNext())
+ {
+ c->set("node",node);
+ bool hasChildren=FALSE;
+ const TemplateStructIntf *ns = node.toStruct();
+ if (ns) // node is a struct
+ {
+ TemplateVariant v = ns->get("children");
+ if (v.isValid()) // with a field 'children'
+ {
+ const TemplateListIntf *list = v.toList();
+ if (list && list->count()>0) // non-empty list
+ {
+ TreeContext childCtx(this,list,ctx->templateCtx);
+ TemplateVariant children(&childCtx,renderChildrenStub);
+ children.setRaw(TRUE);
+ c->set("children",children);
+ m_treeNodes.render(ss,c);
+ hasChildren=TRUE;
+ }
+ }
+ }
+ if (!hasChildren)
+ {
+ c->set("children",TemplateVariant("")); // provide default
+ m_treeNodes.render(ss,c);
+ }
+ }
+ c->pop();
+ return result.data();
+ }
+ void render(FTextStream &ts, TemplateContext *c)
+ {
+ //printf("TemplateNodeTree::render()\n");
+ TemplateContextImpl* ci = dynamic_cast<TemplateContextImpl*>(c);
+ ci->setLocation(m_templateName,m_line);
+ TemplateVariant v = m_treeExpr->resolve(c);
+ const TemplateListIntf *list = v.toList();
+ if (list)
+ {
+ TreeContext ctx(this,list,c);
+ ts << renderChildren(&ctx);
+ }
+ else
+ {
+ warn(m_templateName,m_line,"recursetree's argument should be a list type");
+ }
+ }
+
+ private:
+ ExprAst *m_treeExpr;
+ TemplateNodeList m_treeNodes;
+};
+
+//----------------------------------------------------------
+
+/** @brief Class representing an 'instantiate' tag in a template */
+class TemplateNodeWith : public TemplateNodeCreator<TemplateNodeWith>
+{
+ struct Mapping
+ {
+ Mapping(const QCString &n,ExprAst *e) : name(n), value(e) {}
+ ~Mapping() { delete value; }
+ QCString name;
+ ExprAst *value;
+ };
+ public:
+ TemplateNodeWith(TemplateParser *parser,TemplateNode *parent,int line,const QCString &data)
+ : TemplateNodeCreator<TemplateNodeWith>(parser,parent,line)
+ {
+ m_args.setAutoDelete(TRUE);
+ ExpressionParser expParser(parser->templateName(),line);
+ QValueList<QCString> args = split(data," ");
+ QValueListIterator<QCString> it = args.begin();
+ while (it!=args.end())
+ {
+ QCString arg = *it;
+ int j=arg.find('=');
+ if (j>0)
+ {
+ ExprAst *expr = expParser.parsePrimary(arg.mid(j+1));
+ if (expr)
+ {
+ m_args.append(new Mapping(arg.left(j),expr));
+ }
+ }
+ else
+ {
+ warn(parser->templateName(),line,"invalid argument '%s' for with tag",arg.data());
+ }
+ ++it;
+ }
+ QStrList stopAt;
+ stopAt.append("endwith");
+ parser->parse(this,line,stopAt,m_nodes);
+ parser->removeNextToken(); // skip over endwith
+ }
+ ~TemplateNodeWith()
+ {
+ }
+ void render(FTextStream &ts, TemplateContext *c)
+ {
+ TemplateContextImpl *ci = dynamic_cast<TemplateContextImpl*>(c);
+ c->push();
+ QListIterator<Mapping> it(m_args);
+ Mapping *mapping;
+ for (it.toFirst();(mapping=it.current());++it)
+ {
+ TemplateVariant value = mapping->value->resolve(c);
+ ci->set(mapping->name,value);
+ }
+ m_nodes.render(ts,c);
+ c->pop();
+ }
+ private:
+ TemplateNodeList m_nodes;
+ QList<Mapping> m_args;
+};
+
+//----------------------------------------------------------
+
+/** @brief Factory class for creating tag AST nodes found in a template */
+class TemplateNodeFactory
+{
+ public:
+ typedef TemplateNode *(*CreateFunc)(TemplateParser *parser,
+ TemplateNode *parent,
+ int line,
+ const QCString &data);
+
+ static TemplateNodeFactory *instance()
+ {
+ static TemplateNodeFactory *instance = 0;
+ if (instance==0) instance = new TemplateNodeFactory;
+ return instance;
+ }
+
+ TemplateNode *create(const QCString &name,
+ TemplateParser *parser,
+ TemplateNode *parent,
+ int line,
+ const QCString &data)
+ {
+ if (m_registry.find(name)==0) return 0;
+ return ((CreateFunc)m_registry[name])(parser,parent,line,data);
+ }
+
+ void registerTemplateNode(const QCString &name,CreateFunc func)
+ {
+ m_registry.insert(name,(void*)func);
+ }
+
+ /** @brief Helper class for registering a template AST node */
+ template<class T> class AutoRegister
+ {
+ public:
+ AutoRegister<T>(const QCString &key)
+ {
+ TemplateNodeFactory::instance()->registerTemplateNode(key,T::createInstance);
+ }
+ };
+
+ private:
+ QDict<void> m_registry;
+};
+
+// register a handler for each start tag we support
+static TemplateNodeFactory::AutoRegister<TemplateNodeIf> autoRefIf("if");
+static TemplateNodeFactory::AutoRegister<TemplateNodeFor> autoRefFor("for");
+static TemplateNodeFactory::AutoRegister<TemplateNodeTree> autoRefTree("recursetree");
+static TemplateNodeFactory::AutoRegister<TemplateNodeWith> autoRefWith("with");
+static TemplateNodeFactory::AutoRegister<TemplateNodeBlock> autoRefBlock("block");
+static TemplateNodeFactory::AutoRegister<TemplateNodeExtend> autoRefExtend("extend");
+static TemplateNodeFactory::AutoRegister<TemplateNodeCreate> autoRefCreate("create");
+static TemplateNodeFactory::AutoRegister<TemplateNodeInclude> autoRefInclude("include");
+
+//----------------------------------------------------------
+
+TemplateBlockContext::TemplateBlockContext() : m_blocks(257)
+{
+ m_blocks.setAutoDelete(TRUE);
+}
+
+TemplateNodeBlock *TemplateBlockContext::get(const QCString &name) const
+{
+ QList<TemplateNodeBlock> *list = m_blocks.find(name);
+ if (list==0 || list->count()==0)
+ {
+ return 0;
+ }
+ else
+ {
+ return list->getLast();
+ }
+}
+
+TemplateNodeBlock *TemplateBlockContext::pop(const QCString &name) const
+{
+ QList<TemplateNodeBlock> *list = m_blocks.find(name);
+ if (list==0 || list->count()==0)
+ {
+ return 0;
+ }
+ else
+ {
+ return list->take(list->count()-1);
+ }
+}
+
+void TemplateBlockContext::add(TemplateNodeBlock *block)
+{
+ QList<TemplateNodeBlock> *list = m_blocks.find(block->name());
+ if (list==0)
+ {
+ list = new QList<TemplateNodeBlock>;
+ m_blocks.insert(block->name(),list);
+ }
+ list->prepend(block);
+}
+
+void TemplateBlockContext::add(TemplateBlockContext *ctx)
+{
+ QDictIterator< QList<TemplateNodeBlock> > di(ctx->m_blocks);
+ QList<TemplateNodeBlock> *list;
+ for (di.toFirst();(list=di.current());++di)
+ {
+ QListIterator<TemplateNodeBlock> li(*list);
+ TemplateNodeBlock *nb;
+ for (li.toFirst();(nb=li.current());++li)
+ {
+ add(nb);
+ }
+ }
+}
+
+void TemplateBlockContext::clear()
+{
+ m_blocks.clear();
+}
+
+void TemplateBlockContext::push(TemplateNodeBlock *block)
+{
+ QList<TemplateNodeBlock> *list = m_blocks.find(block->name());
+ if (list==0)
+ {
+ list = new QList<TemplateNodeBlock>;
+ m_blocks.insert(block->name(),list);
+ }
+ list->append(block);
+}
+
+
+//----------------------------------------------------------
+
+/** @brief Lexer class for turning a template into a list of tokens */
+class TemplateLexer
+{
+ public:
+ TemplateLexer(const QCString &fileName,const QCString &data);
+ void tokenize(QList<TemplateToken> &tokens);
+ private:
+ void addToken(QList<TemplateToken> &tokens,
+ const char *data,int line,int startPos,int endPos,
+ TemplateToken::Type type);
+ void reset();
+ QCString m_fileName;
+ QCString m_data;
+};
+
+TemplateLexer::TemplateLexer(const QCString &fileName,const QCString &data) :
+ m_fileName(fileName), m_data(data)
+{
+}
+
+void TemplateLexer::tokenize(QList<TemplateToken> &tokens)
+{
+ enum LexerStates
+ {
+ StateText,
+ StateBeginTemplate,
+ StateTag,
+ StateEndTag,
+ StateComment,
+ StateEndComment,
+ StateMaybeVar,
+ StateVariable,
+ StateEndVariable
+ };
+
+ const char *p=m_data.data();
+ int state=StateText;
+ int pos=0;
+ int lastTokenPos=0;
+ int startLinePos=0;
+ bool emptyOutputLine=TRUE;
+ int line=1;
+ char c;
+ int markStartPos=-1;
+ for (;(c=*p);p++,pos++)
+ {
+ switch (state)
+ {
+ case StateText:
+ if (c=='{') // {{ or {% or {# or something else
+ {
+ state=StateBeginTemplate;
+ }
+ else if (c!=' ' && c!='\t' && c!='\n') // non-whitepace text
+ {
+ emptyOutputLine=FALSE;
+ }
+ break;
+ case StateBeginTemplate:
+ switch (c)
+ {
+ case '%': // {%
+ state=StateTag;
+ markStartPos=pos-1;
+ break;
+ case '#': // {#
+ state=StateComment;
+ markStartPos=pos-1;
+ break;
+ case '{': // {{
+ state=StateMaybeVar;
+ markStartPos=pos-1;
+ break;
+ default:
+ state=StateText;
+ emptyOutputLine=FALSE;
+ break;
+ }
+ break;
+ case StateTag:
+ if (c=='\n')
+ {
+ warn(m_fileName,line,"unexpected new line inside {%%...%%} block");
+ }
+ else if (c=='%') // %} or something else
+ {
+ state=StateEndTag;
+ }
+ break;
+ case StateEndTag:
+ if (c=='}') // %}
+ {
+ // found tag!
+ state=StateText;
+ addToken(tokens,m_data.data(),line,lastTokenPos,
+ emptyOutputLine ? startLinePos : markStartPos,
+ TemplateToken::Text);
+ addToken(tokens,m_data.data(),line,markStartPos+2,
+ pos-1,TemplateToken::Block);
+ lastTokenPos = pos+1;
+ }
+ else // something else
+ {
+ if (c=='\n')
+ {
+ warn(m_fileName,line,"unexpected new line inside {%%...%%} block");
+ }
+ state=StateTag;
+ }
+ break;
+ case StateComment:
+ if (c=='\n')
+ {
+ warn(m_fileName,line,"unexpected new line inside {#...#} block");
+ }
+ else if (c=='#') // #} or something else
+ {
+ state=StateEndComment;
+ }
+ break;
+ case StateEndComment:
+ if (c=='}') // #}
+ {
+ // found comment tag!
+ state=StateText;
+ addToken(tokens,m_data.data(),line,lastTokenPos,
+ emptyOutputLine ? startLinePos : markStartPos,
+ TemplateToken::Text);
+ lastTokenPos = pos+1;
+ }
+ else // something else
+ {
+ if (c=='\n')
+ {
+ warn(m_fileName,line,"unexpected new line inside {#...#} block");
+ }
+ state=StateComment;
+ }
+ break;
+ case StateMaybeVar:
+ switch (c)
+ {
+ case '#': // {{#
+ state=StateComment;
+ markStartPos=pos-1;
+ break;
+ case '%': // {{%
+ state=StateTag;
+ markStartPos=pos-1;
+ break;
+ default: // {{
+ state=StateVariable;
+ break;
+ }
+ break;
+ case StateVariable:
+ if (c=='\n')
+ {
+ warn(m_fileName,line,"unexpected new line inside {{...}} block");
+ }
+ else if (c=='}') // }} or something else
+ {
+ state=StateEndVariable;
+ }
+ break;
+ case StateEndVariable:
+ if (c=='}') // }}
+ {
+ // found variable tag!
+ state=StateText;
+ addToken(tokens,m_data.data(),line,lastTokenPos,
+ emptyOutputLine ? startLinePos : markStartPos,
+ TemplateToken::Text);
+ addToken(tokens,m_data.data(),line,markStartPos+2,
+ pos-1,TemplateToken::Variable);
+ lastTokenPos = pos+1;
+ }
+ else // something else
+ {
+ if (c=='\n')
+ {
+ warn(m_fileName,line,"unexpected new line inside {{...}} block");
+ }
+ state=StateVariable;
+ }
+ break;
+ }
+ if (c=='\n') // new line
+ {
+ state=StateText;
+ startLinePos=pos+1;
+ // if the current line only contain commands and whitespace,
+ // then skip it in the output by moving lastTokenPos
+ if (markStartPos!=-1 && emptyOutputLine) lastTokenPos = startLinePos;
+ // reset markers
+ markStartPos=-1;
+ line++;
+ emptyOutputLine=TRUE;
+ }
+ }
+ if (lastTokenPos<pos)
+ {
+ addToken(tokens,m_data.data(),line,
+ lastTokenPos,pos,
+ TemplateToken::Text);
+ }
+}
+
+void TemplateLexer::addToken(QList<TemplateToken> &tokens,
+ const char *data,int line,
+ int startPos,int endPos,
+ TemplateToken::Type type)
+{
+ if (startPos<endPos)
+ {
+ int len = endPos-startPos+1;
+ QCString text(len+1);
+ qstrncpy(text.data(),data+startPos,len);
+ text[len]='\0';
+ if (type!=TemplateToken::Text) text = text.stripWhiteSpace();
+ tokens.append(new TemplateToken(type,text,line));
+ }
+}
+
+//----------------------------------------------------------
+
+TemplateParser::TemplateParser(const QCString &templateName,
+ QList<TemplateToken> &tokens) :
+ m_templateName(templateName), m_tokens(tokens)
+{
+}
+
+void TemplateParser::parse(
+ TemplateNode *parent,int line,const QStrList &stopAt,
+ QList<TemplateNode> &nodes)
+{
+ TRACE(("{TemplateParser::parse\n"));
+ // process the tokens. Build node list
+ while (hasNextToken())
+ {
+ TemplateToken *tok = takeNextToken();
+ //printf("%p:Token type=%d data='%s' line=%d\n",
+ // parent,tok->type,tok->data.data(),tok->line);
+ switch(tok->type)
+ {
+ case TemplateToken::Text:
+ nodes.append(new TemplateNodeText(this,parent,tok->line,tok->data));
+ break;
+ case TemplateToken::Variable:
+ nodes.append(new TemplateNodeVariable(this,parent,tok->line,tok->data));
+ break;
+ case TemplateToken::Block:
+ {
+ QCString command = tok->data;
+ int sep = command.find(' ');
+ if (sep!=-1)
+ {
+ command=command.left(sep);
+ }
+ if (stopAt.contains(command))
+ {
+ prependToken(tok);
+ TRACE(("}TemplateParser::parse: stop\n"));
+ return;
+ }
+ QCString arg;
+ if (sep!=-1)
+ {
+ arg = tok->data.mid(sep+1);
+ }
+ TemplateNode *node = TemplateNodeFactory::instance()->
+ create(command,this,parent,tok->line,arg);
+ if (node)
+ {
+ nodes.append(node);
+ }
+ else if (command=="empty" || command=="else" ||
+ command=="endif" || command=="endfor" ||
+ command=="endblock" || command=="endwith" ||
+ command=="endrecursetree")
+ {
+ warn(m_templateName,tok->line,"Found tag '%s' without matching start tag",command.data());
+ }
+ else
+ {
+ warn(m_templateName,tok->line,"Unknown tag '%s'",command.data());
+ }
+ }
+ break;
+ }
+ delete tok;
+ }
+ if (!stopAt.isEmpty())
+ {
+ QStrListIterator it(stopAt);
+ const char *s;
+ QCString options;
+ for (it.toFirst();(s=it.current());++it)
+ {
+ if (!options.isEmpty()) options+=", ";
+ options+=s;
+ }
+ warn(m_templateName,line,"Unclosed tag in template, expected one of: %s",
+ options.data());
+ }
+ TRACE(("}TemplateParser::parse: last token\n"));
+}
+
+bool TemplateParser::hasNextToken() const
+{
+ return !m_tokens.isEmpty();
+}
+
+TemplateToken *TemplateParser::takeNextToken()
+{
+ return m_tokens.take(0);
+}
+
+const TemplateToken *TemplateParser::currentToken() const
+{
+ return m_tokens.first();
+};
+
+void TemplateParser::removeNextToken()
+{
+ m_tokens.removeFirst();
+}
+
+void TemplateParser::prependToken(const TemplateToken *token)
+{
+ m_tokens.prepend(token);
+}
+
+
+
+//----------------------------------------------------------
+
+
+TemplateImpl::TemplateImpl(TemplateEngine *engine,const QCString &name,const QCString &data)
+ : TemplateNode(0)
+{
+ m_name = name;
+ m_engine = engine;
+ TemplateLexer lexer(name,data);
+ QList<TemplateToken> tokens;
+ tokens.setAutoDelete(TRUE);
+ lexer.tokenize(tokens);
+ TemplateParser parser(name,tokens);
+ parser.parse(this,1,QStrList(),m_nodes);
+}
+
+void TemplateImpl::render(FTextStream &ts, TemplateContext *c)
+{
+ if (!m_nodes.isEmpty())
+ {
+ TemplateNodeExtend *ne = dynamic_cast<TemplateNodeExtend*>(m_nodes.getFirst());
+ if (ne==0) // normal template, add blocks to block context
+ {
+ TemplateContextImpl *ci = dynamic_cast<TemplateContextImpl*>(c);
+ TemplateBlockContext *bc = ci->blockContext();
+ QListIterator<TemplateNode> li(m_nodes);
+ TemplateNode *n;
+ for (li.toFirst();(n=li.current());++li)
+ {
+ TemplateNodeBlock *nb = dynamic_cast<TemplateNodeBlock*>(n);
+ if (nb)
+ {
+ bc->add(nb);
+ }
+ }
+ }
+ m_nodes.render(ts,c);
+ }
+}
+
+//----------------------------------------------------------
+
+/** @brief Private data of the template engine */
+class TemplateEngine::Private
+{
+ public:
+ Private() { templates.setAutoDelete(TRUE); }
+ QList<Template> templates;
+};
+
+TemplateEngine::TemplateEngine()
+{
+ p = new Private;
+}
+
+TemplateEngine::~TemplateEngine()
+{
+ delete p;
+}
+
+TemplateContext *TemplateEngine::createContext() const
+{
+ return new TemplateContextImpl;
+}
+
+Template *TemplateEngine::newTemplate(const QCString &name,const QCString &data)
+{
+ Template *t = new TemplateImpl(this,name,data);
+ p->templates.append(t);
+ return t;
+}
+
+
+Template *TemplateEngine::loadByName(const QCString &fileName)
+{
+ Template *t=0;
+ QFile f(fileName);
+ if (f.open(IO_ReadOnly))
+ {
+ uint size=f.size();
+ char *data = new char[size+1];
+ if (data)
+ {
+ data[size]=0;
+ if (f.readBlock(data,f.size()))
+ {
+ t = new TemplateImpl(this,fileName,data);
+ }
+ delete[] data;
+ }
+ }
+ return t;
+}
+
diff --git a/src/template.h b/src/template.h
new file mode 100644
index 0000000..454a70b
--- /dev/null
+++ b/src/template.h
@@ -0,0 +1,395 @@
+#ifndef TEMPLATE_H
+#define TEMPLATE_H
+
+#include <qcstring.h>
+#include <qvaluelist.h>
+
+class FTextStream;
+
+class TemplateListIntf;
+class TemplateStructIntf;
+class TemplateEngine;
+
+/** @defgroup template_api Template API
+ *
+ * This is the API for a
+ * <a href="https://docs.djangoproject.com/en/1.6/topics/templates/">Django</a>
+ * compatible template system written in C++.
+ * It is somewhat inspired by Stephen Kelly's
+ * <a href="http://www.gitorious.org/grantlee/pages/Home">Grantlee</a>.
+ *
+ * A template is simply a text file.
+ * A template contains \b variables, which get replaced with values when the
+ * template is evaluated, and \b tags, which control the logic of the template.
+ *
+ * Variables look like this: `{{ variable }}`
+ * When the template engine encounters a variable, it evaluates that variable and
+ * replaces it with the result. Variable names consist of any combination of
+ * alphanumeric characters and the underscore ("_").
+ * Use a dot (.) to access attributes of a variable.
+ *
+ * One can modify variables for display by using \b filters, for example:
+ * `{{ value|default:"nothing" }}`
+ *
+ * Tags look like this: `{% tag %}`. Tags are more complex than variables:
+ * Some create text in the output, some control flow by performing loops or logic,
+ * and some load external information into the template to be used by later variables.
+ *
+ * To comment-out part of a line in a template, use the comment syntax:
+ * `{# comment text #}`.
+ *
+ * Supported Django tags:
+ * - `for ... empty ... endfor`
+ * - `if ... else ... endif`
+ * - `block ... endblock`
+ * - `extends`
+ * - `include`
+ *
+ * Supported Django filters:
+ * - `default`
+ * - `length`
+ * - `add`
+ *
+ * Extension tags:
+ * - `create` which instantiates a template and writes the result to a file.
+ * The syntax is `{% create 'filename' from 'template' %}`.
+ *
+ * @{
+ */
+
+/** @brief Variant type which can hold one value of a fixed set of types. */
+class TemplateVariant
+{
+ public:
+ /** Signature of the callback function, used for function type variants */
+ typedef QCString (*FuncType)(const void *obj, const QValueList<TemplateVariant> &args);
+
+ /** Types of data that can be stored in a TemplateVariant */
+ enum Type { None, Bool, Integer, String, Struct, List, Function };
+
+ /** Returns the type of the value stored in the variant */
+ Type type() const;
+
+ /** Returns TRUE if the variant holds a valid value, or FALSE otherwise */
+ bool isValid() const;
+
+ /** Constructs an invalid variant. */
+ TemplateVariant();
+
+ /** Constructs a new variant with a boolean value \a b. */
+ explicit TemplateVariant(bool b);
+
+ /** Constructs a new variant with a integer value \a v. */
+ TemplateVariant(int v);
+
+ /** Constructs a new variant with a string value \a s. */
+ TemplateVariant(const char *s);
+
+ /** Constructs a new variant with a string value \a s. */
+ TemplateVariant(const QCString &s);
+
+ /** Constructs a new variant with a struct value \a s.
+ * @note. Only a pointer to the struct is stored. The caller
+ * is responsible to manage the memory for the struct object.
+ */
+ TemplateVariant(const TemplateStructIntf *s);
+
+ /** Constructs a new variant with a list value \a l.
+ * @note. Only a pointer to the struct is stored. The caller
+ * is responsible to manage the memory for the list object.
+ */
+ TemplateVariant(const TemplateListIntf *l);
+
+ /** Constructs a new variant which represents a function
+ * @param[in] obj Opaque user defined pointer, which
+ * is passed back when call() is invoked.
+ * @param[in] func Callback function to invoke when
+ * calling call() on this variant.
+ */
+ TemplateVariant(const void *obj,FuncType func);
+
+ /** Destroys the Variant object */
+ ~TemplateVariant();
+
+ /** Constructs a copy of the variant, \a v,
+ * passed as the argument to this constructor.
+ */
+ TemplateVariant(const TemplateVariant &v);
+
+ /** Assigns the value of the variant \a v to this variant. */
+ TemplateVariant &operator=(const TemplateVariant &v);
+
+ /** Compares this QVariant with v and returns true if they are equal;
+ * otherwise returns false.
+ */
+ bool operator==(TemplateVariant &other);
+
+ /** Returns the variant as a string. */
+ QCString toString() const;
+
+ /** Returns the variant as a boolean. */
+ bool toBool() const;
+
+ /** Returns the variant as an integer. */
+ int toInt() const;
+
+ /** Returns the pointer to list referenced by this variant
+ * or 0 if this variant does not have list type.
+ */
+ const TemplateListIntf *toList() const;
+
+ /** Returns the pointer to struct referenced by this variant
+ * or 0 if this variant does not have struct type.
+ */
+ const TemplateStructIntf *toStruct() const;
+
+ /** Return the result of apply this function with \a args.
+ * Returns an empty string if the variant type is not a function.
+ */
+ QCString call(const QValueList<TemplateVariant> &args);
+
+ /** Sets whether or not the value of the Variant should be
+ * escaped or written as-is (raw).
+ * @param[in] b TRUE means write as-is, FALSE means apply escaping.
+ */
+ void setRaw(bool b);
+
+ /** Returns whether or not the value of the Value is raw.
+ * @see setRaw()
+ */
+ bool raw() const;
+
+ private:
+ class Private;
+ Private *p;
+};
+
+//------------------------------------------------------------------------
+
+/** @brief Abstract read-only interface for a context value of type list.
+ * @note The values of the list are TemplateVariants.
+ */
+class TemplateListIntf
+{
+ public:
+ /** @brief Abstract interface for a iterator of a list. */
+ class ConstIterator
+ {
+ public:
+ /** Destructor for the iterator */
+ virtual ~ConstIterator() {}
+ /** Moves iterator to the first element in the list */
+ virtual void toFirst() = 0;
+ /** Moves iterator to the last element in the list */
+ virtual void toLast() = 0;
+ /** Moves iterator to the next element in the list */
+ virtual void toNext() = 0;
+ /** Moves iterator to the previous element in the list */
+ virtual void toPrev() = 0;
+ /* Returns TRUE if the iterator points to a valid element
+ * in the list, or FALSE otherwise.
+ * If TRUE is returned, the value pointed to be the
+ * iterator is assigned to \a v.
+ */
+ virtual bool current(TemplateVariant &v) const = 0;
+ };
+
+ /** Destroys the list */
+ virtual ~TemplateListIntf() {}
+
+ /** Returns the number of elements in the list */
+ virtual int count() const = 0;
+
+ /** Returns the element at index position \a index. */
+ virtual TemplateVariant at(int index) const = 0;
+
+ /** Creates a new iterator for this list.
+ * @note the user should call delete on the returned pointer.
+ */
+ virtual TemplateListIntf::ConstIterator *createIterator() const = 0;
+};
+
+/** @brief Default implementation of a context value of type list. */
+class TemplateList : public TemplateListIntf
+{
+ public:
+ /** Creates a list */
+ TemplateList();
+ /** Destroys the list */
+ ~TemplateList();
+
+ // TemplateListIntf methods
+ virtual int count() const;
+ virtual TemplateVariant at(int index) const;
+ virtual TemplateListIntf::ConstIterator *createIterator() const;
+
+ /** Appends element \a v to the end of the list */
+ virtual void append(const TemplateVariant &v);
+
+ private:
+ friend class TemplateListConstIterator;
+ class Private;
+ Private *p;
+};
+
+//------------------------------------------------------------------------
+
+/** @brief Abstract interface for a context value of type struct. */
+class TemplateStructIntf
+{
+ public:
+ /** Destroys the struct */
+ virtual ~TemplateStructIntf() {}
+
+ /** Gets the value for a field name.
+ * @param[in] name The name of the field.
+ */
+ virtual TemplateVariant get(const char *name) const = 0;
+};
+
+
+/** @brief Default implementation of a context value of type struct. */
+class TemplateStruct : public TemplateStructIntf
+{
+ public:
+ /** Creates a struct */
+ TemplateStruct();
+ /** Destroys the struct */
+ virtual ~TemplateStruct();
+
+ // TemplateStructIntf methods
+ virtual TemplateVariant get(const char *name) const;
+
+ /** Sets the value the field of a struct
+ * @param[in] name The name of the field.
+ * @param[in] v The value to set.
+ */
+ virtual void set(const char *name,const TemplateVariant &v);
+
+ private:
+ class Private;
+ Private *p;
+};
+
+//------------------------------------------------------------------------
+
+/** @brief Interface used to escape characters in a string */
+class TemplateEscapeIntf
+{
+ public:
+ /** Returns the \a input after escaping certain characters */
+ virtual QCString escape(const QCString &input) = 0;
+};
+
+//------------------------------------------------------------------------
+
+/** @brief Abstract interface for a template context.
+ *
+ * A Context consists of a stack of dictionaries.
+ * A dictionary consists of a mapping of string keys onto TemplateVariant values.
+ * A key is searched starting with the dictionary at the top of the stack
+ * and searching downwards until it is found. The stack is used to create
+ * local scopes.
+ * @note This object must be created by TemplateEngine
+ */
+class TemplateContext
+{
+ public:
+ virtual ~TemplateContext() {}
+
+ /** Push a new scope on the stack. */
+ virtual void push() = 0;
+
+ /** Pop the current scope from the stack. */
+ virtual void pop() = 0;
+
+ /** Sets a value in the current scope.
+ * @param[in] name The name of the value; the key in the dictionary.
+ * @param[in] v The value associated with the key.
+ * @note When a given key is already present,
+ * its value will be replaced by \a v
+ */
+ virtual void set(const char *name,const TemplateVariant &v) = 0;
+
+ /** Gets the value for a given key
+ * @param[in] name The name of key.
+ * @returns The value, which can be an invalid variant in case the
+ * key was not found.
+ */
+ virtual TemplateVariant get(const QCString &name) const = 0;
+
+ /** Returns a pointer to the value corresponding to a given key.
+ * @param[in] name The name of key.
+ * @returns A pointer to the value, or 0 in case the key was not found.
+ */
+ virtual const TemplateVariant *getRef(const QCString &name) const = 0;
+
+ /** When files are create (i.e. by {% create ... %}) they written
+ * to the directory \a dir.
+ */
+ virtual void setOutputDirectory(const QCString &dir) = 0;
+
+ /** Sets the interface that will be used for escaping the result
+ * of variable expansion before writing it to the output.
+ */
+ virtual void setEscapeIntf(TemplateEscapeIntf *intf) = 0;
+};
+
+//------------------------------------------------------------------------
+
+/** @brief Abstract interface for a template.
+ * @note Must be created by TemplateEngine
+ */
+class Template
+{
+ public:
+ /** Destructor */
+ virtual ~Template() {}
+
+ /** Renders a template instance to a stream.
+ * @param[in] ts The text stream to write the results to.
+ * @param[in] c The context containing data that can be used
+ * when instantiating the template.
+ */
+ virtual void render(FTextStream &ts,TemplateContext *c) = 0;
+};
+
+//------------------------------------------------------------------------
+
+/** @brief Engine to create templates and template contexts. */
+class TemplateEngine
+{
+ public:
+ /** Create a template engine. */
+ TemplateEngine();
+
+ /** Destroys the template engine. */
+ ~TemplateEngine();
+
+ /** Creates a new context that can be using to render a template.
+ * @see Template::render()
+ */
+ TemplateContext *createContext() const;
+
+ /** Creates a new template whose contents are given by a string.
+ * @param[in] name The name of the template.
+ * @param[in] data The contents of the template.
+ * @return the new template, the caller will be the owner.
+ */
+ Template *newTemplate(const QCString &name,const QCString &data);
+
+ /** Creates a new template whole contents are in a file.
+ * @param[in] fileName The name of the file containing the
+ * template data
+ * @return the new template, the caller will be the owner.
+ */
+ Template *loadByName(const QCString &fileName);
+
+ private:
+ class Private;
+ Private *p;
+};
+
+/** @} */
+
+#endif
diff --git a/src/util.cpp b/src/util.cpp
index 380ae94..c127362 100644
--- a/src/util.cpp
+++ b/src/util.cpp
@@ -5076,6 +5076,34 @@ static void initBaseClassHierarchy(BaseClassList *bcl)
cd->visited=FALSE;
}
}
+//----------------------------------------------------------------------------
+
+bool classHasVisibleChildren(ClassDef *cd)
+{
+ BaseClassList *bcl;
+
+ if (cd->getLanguage()==SrcLangExt_VHDL) // reverse baseClass/subClass relation
+ {
+ if (cd->baseClasses()==0) return FALSE;
+ bcl=cd->baseClasses();
+ }
+ else
+ {
+ if (cd->subClasses()==0) return FALSE;
+ bcl=cd->subClasses();
+ }
+
+ BaseClassListIterator bcli(*bcl);
+ for ( ; bcli.current() ; ++bcli)
+ {
+ if (bcli.current()->classDef->isVisibleInHierarchy())
+ {
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+
//----------------------------------------------------------------------------
@@ -7988,3 +8016,44 @@ uint getUtf8CodeToUpper( const QCString& s, int idx )
//--------------------------------------------------------------------------------------
+bool namespaceHasVisibleChild(NamespaceDef *nd,bool includeClasses)
+{
+ if (nd->getNamespaceSDict())
+ {
+ NamespaceSDict::Iterator cnli(*nd->getNamespaceSDict());
+ NamespaceDef *cnd;
+ for (cnli.toFirst();(cnd=cnli.current());++cnli)
+ {
+ if (cnd->isLinkable() && cnd->localName().find('@')==-1)
+ {
+ return TRUE;
+ }
+ else if (namespaceHasVisibleChild(cnd,includeClasses))
+ {
+ return TRUE;
+ }
+ }
+ }
+ if (includeClasses && nd->getClassSDict())
+ {
+ ClassSDict::Iterator cli(*nd->getClassSDict());
+ ClassDef *cd;
+ for (;(cd=cli.current());++cli)
+ {
+ if (cd->isLinkableInProject() && cd->templateMaster()==0)
+ {
+ return TRUE;
+ }
+ }
+ }
+ return FALSE;
+}
+
+//----------------------------------------------------------------------------
+
+bool classVisibleInIndex(ClassDef *cd)
+{
+ static bool allExternals = Config_getBool("ALLEXTERNALS");
+ return (allExternals && cd->isLinkable()) || cd->isLinkableInProject();
+}
+
diff --git a/src/util.h b/src/util.h
index 0cbe450..28d4a0c 100644
--- a/src/util.h
+++ b/src/util.h
@@ -257,6 +257,9 @@ QCString replaceAnonymousScopes(const QCString &s,const char *replacement=0);
void initClassHierarchy(ClassSDict *cl);
bool hasVisibleRoot(BaseClassList *bcl);
+bool classHasVisibleChildren(ClassDef *cd);
+bool namespaceHasVisibleChild(NamespaceDef *nd,bool includeClasses);
+bool classVisibleInIndex(ClassDef *cd);
int minClassDistance(const ClassDef *cd,const ClassDef *bcd,int level=0);
Protection classInheritedProtectionLevel(ClassDef *cd,ClassDef *bcd,Protection prot=Public,int level=0);
@@ -443,5 +446,7 @@ uint getUtf8Code( const QCString& s, int idx );
uint getUtf8CodeToLower( const QCString& s, int idx );
uint getUtf8CodeToUpper( const QCString& s, int idx );
+
+
#endif