Commit 784a67d2 authored by Dimitri van Heesch's avatar Dimitri van Heesch

Added rudimentary support for django like template system for output creation.

parent 74815268
......@@ -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;
}
......@@ -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 ----
......
#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
}
}
#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
......@@ -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;
}
......
......@@ -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;
......
......@@ -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);
......
......@@ -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);
......
......@@ -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 *
**************************************************************************/
......
......@@ -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());
}
......@@ -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;
//---------------------------------
......
File mode changed from 100755 to 100644
......@@ -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;
}
......
......@@ -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)
......
......@@ -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
......
......@@ -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;
}
......@@ -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:
......
#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;
}
#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
......@@ -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();
}
......@@ -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
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment