Commit c736b03f authored by dimitri's avatar dimitri

Release-1.2.12

parent fba77445
DOXYGEN Version 1.2.11-20011111
DOXYGEN Version 1.2.12
Please read the installation section of the manual for instructions.
--------
Dimitri van Heesch (11 November 2001)
Dimitri van Heesch (18 November 2001)
DOXYGEN Version 1.2.11_20011111
DOXYGEN Version 1.2.12
Please read INSTALL for compilation instructions.
......@@ -17,4 +17,4 @@ to subscribe to the lists or to visit the archives.
Enjoy,
Dimitri van Heesch (dimitri@stack.nl) (11 November 2001)
Dimitri van Heesch (dimitri@stack.nl) (18 November 2001)
1.2.11-20011111
1.2.12
......@@ -136,3 +136,13 @@ void CompoundHandler::addSubClass(const QXmlAttributes& attrib)
m_subClasses.append(sc);
}
void CompoundHandler::initialize(MainHandler *m)
{
QListIterator<ISection> msi(m_sections);
SectionHandler *sec;
for (;(sec=(SectionHandler *)msi.current());++msi)
{
sec->initialize(m);
}
}
......@@ -23,6 +23,7 @@
#include "sectionhandler.h"
#include "doxmlintf.h"
class MainHandler;
class DocHandler;
class ProgramListingHandler;
......@@ -48,6 +49,7 @@ class CompoundHandler : public ICompound, public BaseHandler<CompoundHandler>
QString id() const { return m_id; }
QString kind() const { return m_kind; }
QListIterator<ISection> getSectionIterator() const { return m_sections; }
void initialize(MainHandler *m);
private:
struct SuperClass
......
......@@ -744,55 +744,6 @@ void VariableListHandler::startListItem(const QXmlAttributes& attrib)
m_curEntry->startListItem(attrib);
}
//----------------------------------------------------------------------
// AnchorHandler
//----------------------------------------------------------------------
AnchorHandler::AnchorHandler(IBaseHandler *parent)
: DocNode(Anchor), m_parent(parent)
{
m_children.setAutoDelete(TRUE);
addEndHandler("anchor",this,&AnchorHandler::endAnchor);
addStartHandler("ref",this,&AnchorHandler::startRef);
}
AnchorHandler::~AnchorHandler()
{
}
void AnchorHandler::startAnchor(const QXmlAttributes& attrib)
{
m_id = attrib.value("id");
m_curString="";
m_parent->setDelegate(this);
}
void AnchorHandler::endAnchor()
{
addTextNode();
printf("anchor id=`%s'\n",m_id.data());
m_parent->setDelegate(0);
}
void AnchorHandler::startRef(const QXmlAttributes& attrib)
{
addTextNode();
RefHandler *rh = new RefHandler(this);
m_children.append(rh);
rh->startRef(attrib);
}
void AnchorHandler::addTextNode()
{
if (!m_curString.isEmpty())
{
m_children.append(new TextNode(m_curString,DocNode::Normal));
printf("addTextNode() text=\"%s\"\n",
m_curString.data());
m_curString="";
}
}
//----------------------------------------------------------------------
// HighlightHandler
//----------------------------------------------------------------------
......@@ -833,7 +784,7 @@ CodeLineHandler::CodeLineHandler(IBaseHandler *parent)
addEndHandler("linenumber",this,&CodeLineHandler::endLineNumber);
addStartHandler("highlight",this,&CodeLineHandler::startHighlight);
addStartHandler("ref",this,&CodeLineHandler::startRef);
addStartHandler("anchor",this,&CodeLineHandler::startAnchor);
m_lineNumber = 0;
}
CodeLineHandler::~CodeLineHandler()
......@@ -853,16 +804,16 @@ void CodeLineHandler::endCodeLine()
m_parent->setDelegate(0);
}
void CodeLineHandler::startLineNumber(const QXmlAttributes& /*attrib*/)
void CodeLineHandler::startLineNumber(const QXmlAttributes& attrib)
{
m_parent->setDelegate(this);
printf("start linenumber\n");
m_lineNumber = attrib.value("line").toInt();
m_refId = attrib.value("refid");
}
void CodeLineHandler::endLineNumber()
{
addTextNode();
printf("end linenumber\n");
m_parent->setDelegate(0);
}
......@@ -874,14 +825,6 @@ void CodeLineHandler::startHighlight(const QXmlAttributes& attrib)
hlh->startHighlight(attrib);
}
void CodeLineHandler::startAnchor(const QXmlAttributes& attrib)
{
addTextNode();
AnchorHandler *ah = new AnchorHandler(this);
m_children.append(ah);
ah->startAnchor(attrib);
}
void CodeLineHandler::startRef(const QXmlAttributes& attrib)
{
addTextNode();
......@@ -1092,6 +1035,106 @@ void IndexEntryHandler::endSecondaryIE()
m_secondary = m_curString;
}
//----------------------------------------------------------------------
// EntryHandler
//----------------------------------------------------------------------
EntryHandler::EntryHandler(IBaseHandler *parent)
: DocNode(Entry), m_parent(parent)
{
m_children.setAutoDelete(TRUE);
addEndHandler("entry",this,&EntryHandler::endEntry);
addStartHandler("para",this,&EntryHandler::startParagraph);
}
EntryHandler::~EntryHandler()
{
}
void EntryHandler::startEntry(const QXmlAttributes&)
{
m_parent->setDelegate(this);
}
void EntryHandler::endEntry()
{
m_parent->setDelegate(0);
}
void EntryHandler::startParagraph(const QXmlAttributes& attrib)
{
ParagraphHandler *ph = new ParagraphHandler(this);
ph->startParagraph(attrib);
m_children.append(ph);
}
//----------------------------------------------------------------------
// RowHandler
//----------------------------------------------------------------------
RowHandler::RowHandler(IBaseHandler *parent)
: DocNode(Row), m_parent(parent)
{
m_children.setAutoDelete(TRUE);
addEndHandler("row",this,&RowHandler::endRow);
addStartHandler("entry",this,&RowHandler::startEntry);
}
RowHandler::~RowHandler()
{
}
void RowHandler::startRow(const QXmlAttributes&)
{
m_parent->setDelegate(this);
}
void RowHandler::endRow()
{
m_parent->setDelegate(0);
}
void RowHandler::startEntry(const QXmlAttributes& attrib)
{
EntryHandler *eh = new EntryHandler(this);
eh->startEntry(attrib);
m_children.append(eh);
}
//----------------------------------------------------------------------
// TableHandler
//----------------------------------------------------------------------
TableHandler::TableHandler(IBaseHandler *parent)
: DocNode(Table), m_parent(parent)
{
m_children.setAutoDelete(TRUE);
addEndHandler("table",this,&TableHandler::endTable);
addStartHandler("row",this,&TableHandler::startRow);
}
TableHandler::~TableHandler()
{
}
void TableHandler::startTable(const QXmlAttributes& attrib)
{
m_parent->setDelegate(this);
m_numColumns = attrib.value("cols").toInt();
printf("table cols=%d\n",m_numColumns);
}
void TableHandler::endTable()
{
m_parent->setDelegate(0);
}
void TableHandler::startRow(const QXmlAttributes& attrib)
{
RowHandler *rh = new RowHandler(this);
rh->startRow(attrib);
m_children.append(rh);
}
//----------------------------------------------------------------------
// ParagraphHandler
......@@ -1123,6 +1166,7 @@ ParagraphHandler::ParagraphHandler(IBaseHandler *parent)
addStartHandler("image",this,&ParagraphHandler::startImage);
addStartHandler("dotfile",this,&ParagraphHandler::startDotFile);
addStartHandler("indexentry",this,&ParagraphHandler::startIndexEntry);
addStartHandler("table",this,&ParagraphHandler::startTable);
}
ParagraphHandler::~ParagraphHandler()
......@@ -1177,6 +1221,7 @@ void ParagraphHandler::startSimpleSect(const QXmlAttributes& attrib)
void ParagraphHandler::startRef(const QXmlAttributes& attrib)
{
addTextNode();
RefHandler *ref = new RefHandler(this);
ref->startRef(attrib);
m_children.append(ref);
......@@ -1184,6 +1229,7 @@ void ParagraphHandler::startRef(const QXmlAttributes& attrib)
void ParagraphHandler::startVariableList(const QXmlAttributes& attrib)
{
addTextNode();
VariableListHandler *vl = new VariableListHandler(this);
vl->startVariableList(attrib);
m_children.append(vl);
......@@ -1191,6 +1237,7 @@ void ParagraphHandler::startVariableList(const QXmlAttributes& attrib)
void ParagraphHandler::startHRuler(const QXmlAttributes& attrib)
{
addTextNode();
HRulerHandler *hr = new HRulerHandler(this);
hr->startHRuler(attrib);
m_children.append(hr);
......@@ -1198,6 +1245,7 @@ void ParagraphHandler::startHRuler(const QXmlAttributes& attrib)
void ParagraphHandler::startLineBreak(const QXmlAttributes& attrib)
{
addTextNode();
LineBreakHandler *lb = new LineBreakHandler(this);
lb->startLineBreak(attrib);
m_children.append(lb);
......@@ -1205,6 +1253,7 @@ void ParagraphHandler::startLineBreak(const QXmlAttributes& attrib)
void ParagraphHandler::startULink(const QXmlAttributes& attrib)
{
addTextNode();
ULinkHandler *uh = new ULinkHandler(this);
uh->startULink(attrib);
m_children.append(uh);
......@@ -1212,6 +1261,7 @@ void ParagraphHandler::startULink(const QXmlAttributes& attrib)
void ParagraphHandler::startEMail(const QXmlAttributes& attrib)
{
addTextNode();
EMailHandler *eh = new EMailHandler(this);
eh->startEMail(attrib);
m_children.append(eh);
......@@ -1219,6 +1269,7 @@ void ParagraphHandler::startEMail(const QXmlAttributes& attrib)
void ParagraphHandler::startLink(const QXmlAttributes& attrib)
{
addTextNode();
LinkHandler *lh = new LinkHandler(this);
lh->startLink(attrib);
m_children.append(lh);
......@@ -1226,6 +1277,7 @@ void ParagraphHandler::startLink(const QXmlAttributes& attrib)
void ParagraphHandler::startProgramListing(const QXmlAttributes& attrib)
{
addTextNode();
ProgramListingHandler *pl = new ProgramListingHandler(this);
pl->startProgramListing(attrib);
m_children.append(pl);
......@@ -1233,6 +1285,7 @@ void ParagraphHandler::startProgramListing(const QXmlAttributes& attrib)
void ParagraphHandler::startFormula(const QXmlAttributes& attrib)
{
addTextNode();
FormulaHandler *fh = new FormulaHandler(this);
fh->startFormula(attrib);
m_children.append(fh);
......@@ -1240,6 +1293,7 @@ void ParagraphHandler::startFormula(const QXmlAttributes& attrib)
void ParagraphHandler::startImage(const QXmlAttributes& attrib)
{
addTextNode();
ImageHandler *ih = new ImageHandler(this);
ih->startImage(attrib);
m_children.append(ih);
......@@ -1247,6 +1301,7 @@ void ParagraphHandler::startImage(const QXmlAttributes& attrib)
void ParagraphHandler::startDotFile(const QXmlAttributes& attrib)
{
addTextNode();
DotFileHandler *df = new DotFileHandler(this);
df->startDotFile(attrib);
m_children.append(df);
......@@ -1254,11 +1309,20 @@ void ParagraphHandler::startDotFile(const QXmlAttributes& attrib)
void ParagraphHandler::startIndexEntry(const QXmlAttributes& attrib)
{
addTextNode();
IndexEntryHandler *df = new IndexEntryHandler(this);
df->startIndexEntry(attrib);
m_children.append(df);
}
void ParagraphHandler::startTable(const QXmlAttributes& attrib)
{
addTextNode();
TableHandler *th = new TableHandler(this);
th->startTable(attrib);
m_children.append(th);
}
void ParagraphHandler::addTextNode()
{
if (!m_curString.isEmpty())
......
......@@ -70,7 +70,10 @@ class DocNode
Formula,
Image,
DotFile,
IndexEntry
IndexEntry,
Table,
Row,
Entry
};
DocNode(NodeKind k) : m_kind(k) {}
virtual ~DocNode() {}
......@@ -412,6 +415,9 @@ class SimpleSectHandler : public DocNode,
//-----------------------------------------------------------------------------
/* \brief Node representing an named item of a VariableList.
*
*/
class VariableListEntryHandler : public DocNode, public BaseHandler<VariableListEntryHandler>
{
public:
......@@ -457,28 +463,6 @@ class VariableListHandler : public DocNode, public BaseHandler<VariableListHandl
//-----------------------------------------------------------------------------
/*! \brief Node representing a text anchor
*
*/
// children: ref
class AnchorHandler : public DocNode, public BaseHandler<AnchorHandler>
{
public:
AnchorHandler(IBaseHandler *parent);
virtual ~AnchorHandler();
void startAnchor(const QXmlAttributes& attrib);
void endAnchor();
void startRef(const QXmlAttributes& attrib);
private:
void addTextNode();
IBaseHandler *m_parent;
QList<DocNode> m_children;
QString m_id;
};
//-----------------------------------------------------------------------------
/*! \brief Node representing a highlighted text fragment.
*
*/
......@@ -512,7 +496,6 @@ class CodeLineHandler : public DocNode, public BaseHandler<CodeLineHandler>
virtual void startLineNumber(const QXmlAttributes&);
virtual void endLineNumber();
virtual void startHighlight(const QXmlAttributes&);
virtual void startAnchor(const QXmlAttributes&);
virtual void startRef(const QXmlAttributes&);
CodeLineHandler(IBaseHandler *parent);
......@@ -523,8 +506,7 @@ class CodeLineHandler : public DocNode, public BaseHandler<CodeLineHandler>
IBaseHandler *m_parent;
int m_lineNumber;
QString m_anchor;
QString m_ref;
QString m_refId;
QList<DocNode> m_children;
};
......@@ -636,18 +618,79 @@ class IndexEntryHandler : public DocNode, public BaseHandler<IndexEntryHandler>
//-----------------------------------------------------------------------------
/*! \brief Node representing an entry in the table entry.
*
*/
// children: para
class EntryHandler : public DocNode, public BaseHandler<EntryHandler>
{
public:
EntryHandler(IBaseHandler *parent);
virtual ~EntryHandler();
void startEntry(const QXmlAttributes& attrib);
void endEntry();
void startParagraph(const QXmlAttributes& attrib);
private:
IBaseHandler *m_parent;
QList<DocNode> m_children;
};
//-----------------------------------------------------------------------------
/*! \brief Node representing an entry in the table row.
*
*/
// children: entry
class RowHandler : public DocNode, public BaseHandler<RowHandler>
{
public:
RowHandler(IBaseHandler *parent);
virtual ~RowHandler();
void startRow(const QXmlAttributes& attrib);
void endRow();
void startEntry(const QXmlAttributes& attrib);
private:
IBaseHandler *m_parent;
QList<EntryHandler> m_children;
};
//-----------------------------------------------------------------------------
/*! \brief Node representing an entry in the table.
*
*/
// children: row
class TableHandler : public DocNode, public BaseHandler<TableHandler>
{
public:
TableHandler(IBaseHandler *parent);
virtual ~TableHandler();
void startTable(const QXmlAttributes& attrib);
void endTable();
void startRow(const QXmlAttributes& attrib);
private:
IBaseHandler *m_parent;
QList<RowHandler> m_children;
int m_numColumns;
};
//-----------------------------------------------------------------------------
/*! \brief Node representing a paragraph of text and commands.
*
*/
// children: itemizedlist, orderedlist, parameterlist, simplesect, ref,
// variablelist, hruler, linebreak, ulink, email, link
// programlisting, formula, image, dotfile, indexentry
// programlisting, formula, image, dotfile, indexentry,
// table
//
// children handled by MarkupHandler:
// bold, computeroutput, emphasis, center,
// small, subscript, superscript.
// TODO:
// table
//
class ParagraphHandler : public DocNode, public BaseHandler<ParagraphHandler>
{
public:
......@@ -669,6 +712,7 @@ class ParagraphHandler : public DocNode, public BaseHandler<ParagraphHandler>
virtual void startImage(const QXmlAttributes& attrib);
virtual void startDotFile(const QXmlAttributes& attrib);
virtual void startIndexEntry(const QXmlAttributes& attrib);
virtual void startTable(const QXmlAttributes& attrib);
ParagraphHandler(IBaseHandler *parent);
virtual ~ParagraphHandler();
......
......@@ -51,6 +51,20 @@ class IDoxygen
* of compounds found in the project.
*/
virtual QListIterator<ICompound> getCompoundIterator() const = 0;
/*! Returns a compound given its unique \a id. If you have a
* compound id this function is much more efficient than iterating
* over the compound list. Returns 0 if the id is not valid.
*/
virtual ICompound *getCompoundById(const QString &id) const = 0;
/*! Returns a compound given its name (including the scope).
* Returns 0 if the name is not found in the project.
*/
virtual ICompound *getCompoundByName(const QString &name) const = 0;
virtual IMember *getMemberById(const QString &id) const = 0;
virtual QList<IMember> *getMemberByName(const QString &name) const = 0;
};
/*! Factory method that creates an object model given an XML file generated
......
......@@ -16,15 +16,7 @@
#include <qxml.h>
#include "mainhandler.h"
void MainHandler::startCompound(const QXmlAttributes& attrib)
{
CompoundHandler *compHandler = new CompoundHandler(this);
compHandler->startCompound(attrib);
m_compounds.append(compHandler);
m_compoundDict.insert(compHandler->id(),compHandler);
}
MainHandler::MainHandler() : m_compoundDict(10007)
MainHandler::MainHandler() : m_compoundDict(10007), m_compoundNameDict(10007)
{
m_compounds.setAutoDelete(TRUE);
addStartHandler("doxygen");
......@@ -38,6 +30,44 @@ MainHandler::~MainHandler()
printf("MainHandler::~MainHandler()\n");
}
void MainHandler::startCompound(const QXmlAttributes& attrib)
{
CompoundHandler *compHandler = new CompoundHandler(this);
compHandler->startCompound(attrib);
m_compounds.append(compHandler);
}
void MainHandler::insertMemberById(const QString &id,IMember *h)
{
m_memberDict.insert(id,h);
}
void MainHandler::insertMemberByName(const QString &name,IMember *h)
{
QList<IMember> *ml = m_memberNameDict[name];
if (ml)
{
ml->append(h);
}
else
{
ml = new QList<IMember>;
ml->append(h);
m_memberNameDict.insert(name,ml);
}
}
void MainHandler::initialize()
{
QListIterator<ICompound> mci(m_compounds);
CompoundHandler *compHandler;
for (;(compHandler=(CompoundHandler *)mci.current());++mci)
{
compHandler->initialize(this);
m_compoundNameDict.insert(compHandler->name(),compHandler);
m_compoundDict.insert(compHandler->id(),compHandler);
}
}
class ErrorHandler : public QXmlErrorHandler
{
......@@ -74,6 +104,7 @@ IDoxygen *createObjectModelFromXML(const char * xmlFileName)
reader.setContentHandler( handler );
reader.setErrorHandler( &errorHandler );
reader.parse( source );
handler->initialize();
return handler;
}
......@@ -28,7 +28,6 @@ class MainHandler : public IDoxygen, public BaseHandler<MainHandler>
MainHandler();
virtual ~MainHandler();
// IDoxygen
QListIterator<ICompound> getCompoundIterator() const
{
return m_compounds;
......@@ -37,10 +36,29 @@ class MainHandler : public IDoxygen, public BaseHandler<MainHandler>
{
return m_compoundDict[id];
}
virtual ICompound *getCompoundByName(const QString &name) const
{
return name.isEmpty() ? 0 : m_compoundNameDict[name];
}
virtual IMember *getMemberById(const QString &id) const
{
return m_memberDict[id];
}
virtual QList<IMember> *getMemberByName(const QString &name) const
{
return m_memberNameDict[name];
}
void insertMemberById(const QString &id,IMember *h);
void insertMemberByName(const QString &name,IMember *h);
void initialize();
private:
QList<ICompound> m_compounds;
QDict<ICompound> m_compoundDict;
QDict<ICompound> m_compoundNameDict;
QDict<IMember> m_memberDict;
QDict<QList<IMember> > m_memberNameDict;
};
#endif
......@@ -37,7 +37,15 @@ MemberHandler::MemberHandler(IBaseHandler *parent)
addStartHandler("location",this,&MemberHandler::startLocation);
addEndHandler("location");
addStartHandler("references",this,&MemberHandler::startReferences);
addEndHandler("references",this,&MemberHandler::endReferences);
addStartHandler("referencedby",this,&MemberHandler::startReferencedBy);
addEndHandler("referencedby",this,&MemberHandler::endReferencedBy);
m_params.setAutoDelete(TRUE);
m_references.setAutoDelete(TRUE);
m_referencedBy.setAutoDelete(TRUE);
}
......@@ -78,6 +86,32 @@ void MemberHandler::startLocation(const QXmlAttributes& attrib)
m_defLine = attrib.value("line").toInt();
}
void MemberHandler::startReferences(const QXmlAttributes& attrib)
{
MemberReference *mr = new MemberReference;
mr->m_memId = attrib.value("id");
m_references.append(mr);
m_curString="";
}
void MemberHandler::endReferences()
{
m_references.getLast()->m_name = m_curString;
}
void MemberHandler::startReferencedBy(const QXmlAttributes& attrib)
{
MemberReference *mr = new MemberReference;
mr->m_memId = attrib.value("id");
m_referencedBy.append(mr);
m_curString="";
}
void MemberHandler::endReferencedBy()
{
m_referencedBy.getLast()->m_name = m_curString;
}
void MemberHandler::endMember()
{
m_parent->setDelegate(0);
......
......@@ -37,6 +37,10 @@ class MemberHandler : public IMember, public BaseHandler<MemberHandler>
virtual void startBriefDesc(const QXmlAttributes& attrib);
virtual void startDetailedDesc(const QXmlAttributes& attrib);
virtual void startLocation(const QXmlAttributes& attrib);
virtual void startReferences(const QXmlAttributes& attrib);
virtual void endReferences();
virtual void startReferencedBy(const QXmlAttributes& attrib);
virtual void endReferencedBy();
MemberHandler(IBaseHandler *parent);
virtual ~MemberHandler();
......@@ -51,6 +55,13 @@ class MemberHandler : public IMember, public BaseHandler<MemberHandler>
virtual QListIterator<IParam> getParamIterator() const { return m_params; }
private:
struct MemberReference
{
QString m_memId;
QString m_name;
int line;
};
IBaseHandler *m_parent;
QString m_kind;
QString m_id;
......@@ -61,6 +72,8 @@ class MemberHandler : public IMember, public BaseHandler<MemberHandler>
DocHandler *m_brief;
DocHandler *m_detailed;
QList<IParam> m_params;
QList<MemberReference> m_references;
QList<MemberReference> m_referencedBy;
QString m_defFile;
int m_defLine;
};
......
......@@ -13,6 +13,7 @@
*
*/
#include "mainhandler.h"
#include "compoundhandler.h"
#include "sectionhandler.h"
......@@ -46,4 +47,15 @@ void SectionHandler::startMember(const QXmlAttributes& attrib)
m_members.append(memHandler);
}
void SectionHandler::initialize(MainHandler *m)
{
QListIterator<IMember> mli(m_members);
MemberHandler *mh;
for (;(mh=(MemberHandler *)mli.current());++mli)
{
m->insertMemberById(mh->name(),mh);
m->insertMemberByName(mh->name(),mh);
}
}
......@@ -24,6 +24,8 @@
#include "memberhandler.h"
#include "doxmlintf.h"
class MainHandler;
class SectionHandler : public ISection, public BaseHandler<SectionHandler>
{
public:
......@@ -38,6 +40,8 @@ class SectionHandler : public ISection, public BaseHandler<SectionHandler>
virtual QString kind() const { return m_kind; }
virtual QListIterator<IMember> getMemberIterator() const { return m_members; }
void initialize(MainHandler *m);
private:
IBaseHandler *m_parent;
QString m_kind;
......
Name: doxygen
Version: 1.2.11_20011111
Version: 1.2.12
Summary: documentation system for C, C++ and IDL
Release: 4
Source: doxygen-%{version}.src.tar.gz
......
......@@ -1591,6 +1591,7 @@ bool ClassDef::isVisibleInHierarchy()
// documented or shown anyway or documentation is external
(hasDocumentation() ||
!Config_getBool("HIDE_UNDOC_CLASSES") ||
(m_templateMaster && m_templateMaster->hasDocumentation()) ||
isReference()
) &&
// is not part of an unnamed namespace or shown anyway
......
......@@ -330,12 +330,12 @@ static void startCodeLine()
//if (g_currentFontClass) { g_code->endFontClass(); }
if (g_sourceFileDef)
{
QCString lineNumber,lineAnchor;
lineNumber.sprintf("%05d",g_yyLineNr);
lineAnchor.sprintf("l%05d",g_yyLineNr);
//QCString lineNumber,lineAnchor;
//lineNumber.sprintf("%05d",g_yyLineNr);
//lineAnchor.sprintf("l%05d",g_yyLineNr);
Definition *d = g_sourceFileDef->getSourceDefinition(g_yyLineNr);
g_code->startLineNumber();
//g_code->startLineNumber();
if (!g_includeCodeFragment && d && d->isLinkableInProject())
{
g_currentDefinition = d;
......@@ -347,16 +347,19 @@ static void startCodeLine()
//printf("Real scope: `%s'\n",g_realScope.data());
g_bodyCurlyCount = 0;
if (g_currentMemberDef) anchor=g_currentMemberDef->getBodyAnchor();
g_code->startCodeAnchor(lineAnchor);
g_code->writeCodeLink(d->getReference(),d->getOutputFileBase(),
anchor,lineNumber);
g_code->endCodeAnchor();
//g_code->startCodeAnchor(lineAnchor);
//g_code->writeCodeLink(d->getReference(),d->getOutputFileBase(),
// anchor,lineNumber);
//g_code->endCodeAnchor();
g_code->writeLineNumber(d->getReference(),d->getOutputFileBase(),
anchor,g_yyLineNr);
}
else
{
g_code->codify(lineNumber);
//g_code->codify(lineNumber);
g_code->writeLineNumber(0,0,0,g_yyLineNr);
}
g_code->endLineNumber();
//g_code->endLineNumber();
}
g_code->startCodeLine();
if (g_currentFontClass)
......@@ -556,13 +559,33 @@ static MemberDef *setCallContextForVar(const QCString &name)
if ((mn=Doxygen::functionNameSDict[name]))
{
//printf("global var `%s'\n",name.data());
if (mn->count()>=1)
// TODO: if count>1 link to static members in the same file only
if (mn->count()==1) // global defined only once
{
MemberDef *md=mn->getFirst();
if (!md->isStatic() || md->getBodyDef()==g_sourceFileDef)
{
g_theCallContext.setClass(stripClassName(md->typeString()));
return md;
}
return 0;
}
else if (mn->count()>1) // global defined more than once
{
MemberDef *md=mn->first();
while (md)
{
//printf("mn=%p md=%p md->getBodyDef()=%p g_sourceFileDef=%p\n",
// mn,md,
// md->getBodyDef(),g_sourceFileDef);
if (md->getBodyDef()==g_sourceFileDef)
{
g_theCallContext.setClass(stripClassName(md->typeString()));
return md;
}
md=mn->next();
}
return 0;
}
}
return 0;
}
......
......@@ -994,8 +994,10 @@ void Config::check()
QStrList &inputSources=Config_getList("INPUT");
if (inputSources.count()==0)
{
config_err("Error: tag INPUT: no input files specified after the INPUT tag.\n");
exit(1);
//config_err("Error: tag INPUT: no input files specified after the INPUT tag.\n");
//exit(1);
inputSources.append(QDir::currentDirPath());
//config_warn("Warning: no files after the INPUT tag, defaulting to the current dir\n");
}
else
{
......@@ -1016,7 +1018,23 @@ void Config::check()
QStrList &filePatternList = Config_getList("FILE_PATTERNS");
if (filePatternList.isEmpty())
{
filePatternList.append("*");
filePatternList.append("*.c");
filePatternList.append("*.cc");
filePatternList.append("*.cxx");
filePatternList.append("*.cpp");
filePatternList.append("*.c++");
filePatternList.append("*.java");
filePatternList.append("*.ii");
filePatternList.append("*.ixx");
filePatternList.append("*.ipp");
filePatternList.append("*.i++");
filePatternList.append("*.inl");
filePatternList.append("*.h");
filePatternList.append("*.hh");
filePatternList.append("*.hxx");
filePatternList.append("*.hpp");
filePatternList.append("*.h++");
filePatternList.append("*.idl");
}
// add default pattern if needed
......@@ -1509,7 +1527,9 @@ void Config::create()
"If the value of the INPUT tag contains directories, you can use the \n"
"FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp \n"
"and *.h) to filter out the source-files in the directories. If left \n"
"blank all files are included. \n"
"blank file matching one of the following patterns are included: \n"
"*.c *.cc *.cxx *.c++ *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh *.hxx *.hpp \n"
"*.h++ *.idl \n"
);
cb = addBool(
"RECURSIVE",
......
......@@ -334,6 +334,7 @@ void Definition::writeInlineCode(OutputList &ol,const char *scopeName)
initParseCodeContext();
//printf("Read:\n`%s'\n\n",codeFragment.data());
if (definitionType()==TypeMember) setParameterList((MemberDef *)this);
ol.newParagraph();
ol.startCodeFragment();
parseCode(ol,scopeName,codeFragment,FALSE,0,
m_bodyDef,actualStart,actualEnd,TRUE);
......@@ -418,7 +419,6 @@ void Definition::writeSourceRefList(OutputList &ol,const char *scopeName,
}
parseText(ol,ldefLine.right(ldefLine.length()-index));
ol.writeString(".");
ol.newParagraph();
}
ol.popGeneratorState();
}
......
......@@ -123,6 +123,9 @@ class Definition
virtual void addInnerCompound(Definition *d);
virtual void setOuterScope(Definition *d) { m_outerScope = d; }
MemberSDict *getReferencesMembers() const { return m_sourceRefsDict; }
MemberSDict *getReferencedByMembers() const { return m_sourceRefByDict; }
protected:
int m_startBodyLine; // line number of the start of the definition
int m_endBodyLine; // line number of the end of the definition
......@@ -147,9 +150,6 @@ class Definition
QCString m_doc; // detailed description
QCString m_ref; // reference to external documentation
SectionDict *m_sectionDict; // dictionary of all sections
//MemberList *m_sourceRefList; // list of entities that refer to this
// // entity in their definition
//MemberDict *m_sourceRefDict;
MemberSDict *m_sourceRefByDict;
MemberSDict *m_sourceRefsDict;
int m_testId; // id for test list item
......
......@@ -406,7 +406,7 @@ static void skipLine(OutputDocInterface &od,const char *key)
found=TRUE;
od.writeString(" ");
parseCode(od,className,s,exampleDoc,exampleName);
od.writeString("\n");
//od.writeString("\n");
}
else if (includeFileOffset==includeFileLength) found=TRUE;
}
......@@ -451,7 +451,7 @@ static void showLine(OutputDocInterface &od,const char *key)
{
od.writeString(" ");
parseCode(od,className,s,exampleDoc,exampleName);
od.writeString("\n");
//od.writeString("\n");
}
}
......@@ -469,7 +469,7 @@ static void showUntil(OutputDocInterface &od,const char *key)
{
od.writeString(" ");
parseCode(od,className,s,exampleDoc,exampleName);
od.writeString("\n");
//od.writeString("\n");
if (s.find(key)!=-1) found=TRUE;
}
if (includeFileOffset==includeFileLength) found=TRUE;
......
......@@ -837,6 +837,8 @@ int DotClassGraph::m_curNodeNumber;
void DotClassGraph::addClass(ClassDef *cd,DotNode *n,int prot,
const char *label,int distance,const char *usedName,const char *templSpec,bool base)
{
if (Config_getBool("HIDE_UNDOC_CLASSES") && !cd->isLinkable()) return;
int edgeStyle = (label || prot==EdgeInfo::Orange) ? EdgeInfo::Dashed : EdgeInfo::Solid;
QCString className;
if (usedName) // name is a typedef
......
......@@ -1385,7 +1385,6 @@ static MemberDef *addVariableToFile(
}
}
//printf("Adding member=%s\n",md->name().data());
// add member definition to the list of globals
if (mn)
{
......@@ -1395,8 +1394,6 @@ static MemberDef *addVariableToFile(
{
mn = new MemberName(name);
mn->append(md);
//Doxygen::functionNameDict.insert(name,mn);
//Doxygen::functionNameList.append(mn);
Doxygen::functionNameSDict.append(name,mn);
}
root->section = Entry::EMPTY_SEC;
......@@ -5805,7 +5802,7 @@ static bool openOutputFile(const char *outFile,QFile &f)
dir.rename(fi.fileName(),fi.fileName()+".bak");
}
f.setName(outFile);
fileOpened = f.open(IO_WriteOnly);
fileOpened = f.open(IO_WriteOnly|IO_Translate);
}
return fileOpened;
}
......
......@@ -1113,3 +1113,23 @@ void HtmlGenerator::writeNonBreakableSpace(int n)
t << "&nbsp;";
}
}
void HtmlGenerator::writeLineNumber(const char *ref,const char *file,
const char *anchor,int l)
{
QCString lineNumber,lineAnchor;
lineNumber.sprintf("%05d",l);
lineAnchor.sprintf("l%05d",l);
if (file)
{
startCodeAnchor(lineAnchor);
writeCodeLink(ref,file,anchor,lineNumber);
endCodeAnchor();
}
else
{
codify(lineNumber);
}
codify(" ");
}
......@@ -124,8 +124,7 @@ class HtmlGenerator : public OutputGenerator
void endCodeFragment() { t << "</pre></div>"; }
void startPreFragment() { t << "<pre>"; }
void endPreFragment() { t << "</pre>"; }
void startLineNumber() {}
void endLineNumber() { t << " "; }
void writeLineNumber(const char *,const char *,const char *,int);
void startCodeLine() { col=0; }
void endCodeLine() { codify("\n"); }
//void writeBoldString(const char *text)
......
......@@ -122,8 +122,7 @@ class LatexGenerator : public OutputGenerator
void endPreFragment() { t << "\\end{alltt}\\normalsize " << endl;
insidePre=FALSE;
}
void startLineNumber() {}
void endLineNumber() { t << " "; }
void writeLineNumber(const char *,const char *,const char *,int l) { t << l << " "; }
void startCodeLine() { col=0; }
void endCodeLine() { codify("\n"); }
//void writeBoldString(const char *text)
......
......@@ -114,8 +114,7 @@ class ManGenerator : public OutputGenerator
void endCodeFragment();
void startPreFragment() { startCodeFragment(); }
void endPreFragment() { endCodeFragment(); }
void startLineNumber() {}
void endLineNumber() { t << " "; }
void writeLineNumber(const char *,const char *,const char *,int l) { t << l << " "; }
void startCodeLine() {}
void endCodeLine() { codify("\n"); col=0; }
//void writeBoldString(const char *text)
......
......@@ -248,8 +248,8 @@ class BaseOutputDocInterface
virtual void endPageRef(const char *,const char *) = 0;
virtual void startLineNumber() = 0;
virtual void endLineNumber() = 0;
virtual void writeLineNumber(const char *ref,const char *file,
const char *anchor,int lineNumber) = 0;
virtual void startCodeLine() = 0;
virtual void endCodeLine() = 0;
virtual void startCodeAnchor(const char *label) = 0;
......
......@@ -278,6 +278,7 @@ FORALL3(const char *a1,const char *a2,bool a3,a1,a2,a3)
FORALL3(uchar a1,uchar a2,uchar a3,a1,a2,a3)
FORALL4(const char *a1,const char *a2,const char *a3,const char *a4,a1,a2,a3,a4)
FORALL4(const char *a1,const char *a2,const char *a3,bool a4,a1,a2,a3,a4)
FORALL4(const char *a1,const char *a2,const char *a3,int a4,a1,a2,a3,a4)
//--------------------------------------------------------------------------
......@@ -214,10 +214,13 @@ class OutputList : public OutputDocInterface
{ forall(&OutputGenerator::startCodeLine); }
void endCodeLine()
{ forall(&OutputGenerator::endCodeLine); }
void startLineNumber()
{ forall(&OutputGenerator::startLineNumber); }
void endLineNumber()
{ forall(&OutputGenerator::endLineNumber); }
//void startLineNumber()
//{ forall(&OutputGenerator::startLineNumber); }
//void endLineNumber()
//{ forall(&OutputGenerator::endLineNumber); }
void writeLineNumber(const char *ref,const char *file,const char *anchor,
int lineNumber)
{ forall(&OutputGenerator::writeLineNumber,ref,file,anchor,lineNumber); }
void startEmphasis()
{ forall(&OutputGenerator::startEmphasis); }
void endEmphasis()
......@@ -485,6 +488,7 @@ class OutputList : public OutputDocInterface
FORALLPROTO3(ClassDiagram &,const char *,const char *);
FORALLPROTO4(const char *,const char *,const char *,const char *);
FORALLPROTO4(const char *,const char *,const char *,bool);
FORALLPROTO4(const char *,const char *,const char *,int);
OutputList(const OutputList &ol);
QList<OutputGenerator> *outputs;
......
......@@ -114,8 +114,7 @@ class RTFGenerator : public OutputGenerator
void endCodeFragment();
void startPreFragment() { startCodeFragment(); }
void endPreFragment() { endCodeFragment(); }
void startLineNumber() {}
void endLineNumber() { t << " "; }
void writeLineNumber(const char *,const char *,const char *,int l) { t << l << " "; }
void startCodeLine() { col=0; }
void endCodeLine() { lineBreak(); }
//void writeBoldString(const char *text)
......
......@@ -1699,6 +1699,26 @@ CHARLIT (("'"\\[0-7]{1,3}"'")|("'"\\."'")|("'"[^'\\\n]{1,4}"'"))
}
}
}
<ReadBody>"}"{BN}+"typedef"{BN}+ { //err("ReadBody count=%d\n",curlyCount);
if ( curlyCount>0 )
{
current->program += yytext ;
--curlyCount ;
}
else
{
lineCount();
isTypedef = TRUE;
current->endBodyLine = yyLineNr;
QCString &cn = current->name;
QCString rn = current_root->name.copy();
if (!cn.isEmpty() && !rn.isEmpty())
{
prependScope();
}
BEGIN( TypedefName );
}
}
<TypedefName>{ID} {
if (current->section == Entry::ENUM_SEC)
{
......
......@@ -39,10 +39,16 @@
// - Removed obsolete method trVerbatimHeadert()
// - Method latexBabelPackage() removed, ude latexLanguageSupportCommand
//
// 2001/11/13
// - inherits from Translator
// - Added strings for 1.2.11
// - better output for C documentation (trCompoundMembersDescription(), trClassDocumentation())
//
#ifndef TRANSLATOR_HR_H
#define TRANSLATOR_HR_H
class TranslatorCroatian : public TranslatorAdapter_1_2_11
class TranslatorCroatian : public Translator
{
private:
/*! to avoid macro redefinition from translator_cz.h */
......@@ -156,19 +162,37 @@ class TranslatorCroatian : public TranslatorAdapter_1_2_11
QCString trCompoundMembersDescription(bool extractAll)
{
QCString result="Popis svih ";
if (!extractAll) result+="dokumentiranih ";
if (!extractAll)
result+="dokumentiranih ";
if (Config_getBool("OPTIMIZE_OUTPUT_FOR_C"))
result+="lanova klasa s linkovima na ";
if (extractAll) result+="dokumentaciju svakog lana:";
else result+="dokumentaciju klase :";
else
result+="lanova struktura s linkovima na ";
if (extractAll)
{
result+="dokumentaciju svakog lana:";
}
else
{
if (Config_getBool("OPTIMIZE_OUTPUT_FOR_C"))
result+="dokumentaciju klase :";
else
result +="dokumentaciju strukture";
}
return decode(result);
}
QCString trFileMembersDescription(bool extractAll)
{
QCString result="Popis svih ";
if (!extractAll) result+="dokumentiranih ";
if (!extractAll)
result+="dokumentiranih ";
result+="lanova s linkovima na ";
if (extractAll) result+="dokumentaciju datoteke u kojima se nalaze:";
else result+="datoteke u kojima se nalaze:";
if (extractAll)
result+="dokumentaciju datoteke u kojima se nalaze:";
else
result+="datoteke u kojima se nalaze:";
return decode(result);
}
QCString trHeaderFilesDescription()
......@@ -189,13 +213,31 @@ class TranslatorCroatian : public TranslatorAdapter_1_2_11
QCString trHierarchicalIndex()
{ return "Hijerarhijsko kazalo"; }
QCString trCompoundIndex()
{ return "Skupno kazalo "; }
{
if (Config_getBool("OPTIMIZE_OUTPUT_FOR_C"))
{
return "Kazalo struktura podataka";
}
else
{
return "Skupno kazalo ";
}
}
QCString trFileIndex()
{ return "Kazalo datoteka"; }
QCString trModuleDocumentation()
{ return "Dokumentacija modula"; }
QCString trClassDocumentation()
{ return "Dokumentacija klasa"; }
{
if (Config_getBool("OPTIMIZE_OUTPUT_FOR_C"))
{
return "Dokumentacija struktura podataka";
}
else
{
return "Dokumentacija klasa";
}
}
QCString trFileDocumentation()
{ return "Dokumentacija datoteka"; }
QCString trExampleDocumentation()
......@@ -967,6 +1009,16 @@ class TranslatorCroatian : public TranslatorAdapter_1_2_11
return result;
}
//////////////////////////////////////////////////////////////////////////
// new since 1.2.11
//////////////////////////////////////////////////////////////////////////
/*! This text is put before the list of members referenced by a member
*/
virtual QCString trReferences()
{
return "Reference";
}
};
#endif
......@@ -35,6 +35,8 @@
#include <qfile.h>
#include <qtextstream.h>
#define XML_DB(x)
QCString sectionTypeToString(BaseOutputDocInterface::SectionTypes t)
{
switch (t)
......@@ -147,6 +149,10 @@ template<class T> class ValStack
{
return m_sp==0;
}
uint count() const
{
return m_sp;
}
private:
QArray<T> m_values;
......@@ -170,11 +176,13 @@ class XMLGenerator : public OutputDocInterface
{
m_inParStack.top() = TRUE;
m_t << "<para>" << endl;
XML_DB(("start par at level=%d\n",m_inParStack.count());)
}
else if (m_inParStack.isEmpty())
{
m_inParStack.push(TRUE);
m_t << "<para>" << endl;
XML_DB(("start par at level=%d\n",m_inParStack.count());)
}
}
void endParMode()
......@@ -183,18 +191,25 @@ class XMLGenerator : public OutputDocInterface
{
m_inParStack.top() = FALSE;
m_t << "</para>" << endl;
XML_DB(("end par at level=%d\n",m_inParStack.count());)
}
}
void startNestedPar()
{
m_inParStack.push(FALSE);
XML_DB(("enter par level=%d\n",m_inParStack.count());)
}
void endNestedPar()
{
XML_DB(("leave par level=%d\n",m_inParStack.count());)
if (m_inParStack.pop())
{
m_t << "</para>" << endl;
}
else
{
XML_DB(("ILLEGAL par level!\n");)
}
}
// Standard generator functions to be implemented by all generators
......@@ -503,27 +518,47 @@ class XMLGenerator : public OutputDocInterface
}
void startTable(int cols)
{
XML_DB(("startTable\n");)
startParMode();
m_t << "<table><tgroup cols=\"" << cols << "\"><tbody>\n";
m_t << "<table cols=\"" << cols << "\">\n";
}
void endTable()
{
m_t << "</row>\n</tbody></tgroup></table>";
XML_DB(("endTable\n");)
m_t << "</row>\n</table>";
}
void nextTableRow()
{
XML_DB(("nextTableRow\n");)
m_t << "<row><entry>";
// we need manually add a para here because cells are
// parsed before the table is generated, and thus
// are already parsed as if they are inside a paragraph.
m_t << "<para>";
}
void endTableRow()
{
XML_DB(("endTableRow\n");)
m_t << "</row>" << endl;
}
void nextTableColumn()
{
XML_DB(("nextTableColumn\n");)
m_t << "<entry>";
// we need manually add a para here because cells are
// parsed before the table is generated, and thus
// are already parsed as if they are inside a paragraph.
m_t << "<para>";
}
void endTableColumn()
{
XML_DB(("endTableColumn\n");)
// we need manually add a para here because cells are
// parsed before the table is generated, and thus
// are already parsed as if they are inside a paragraph.
m_t << "</para>";
m_t << "</entry>";
}
......@@ -614,13 +649,16 @@ class XMLGenerator : public OutputDocInterface
void endPageRef(const char *,const char *)
{
}
void startLineNumber()
void writeLineNumber(const char *,const char *file, // TODO: support external references
const char *anchor,int l)
{
m_t << "<linenumber>";
}
void endLineNumber()
m_t << "<linenumber";
m_t << " line=\"" << l << "\"";
if (file)
{
m_t << "</linenumber>";
m_t << " refid=\"" << file << "_1" << anchor << "\"";
}
m_t << "/>";
}
void startCodeLine()
{
......@@ -665,15 +703,7 @@ class XMLGenerator : public OutputDocInterface
{
const XMLGenerator *xg = (const XMLGenerator *)g;
//if (m_inPar && !mifgen->m_inParStart)
//{
// endParMode();
//}
//else if (!m_inPar && mifgen->m_inParStart)
//{
// startParMode();
//}
//printf("Appending \n>>>>\n`%s'\n<<<<\n and \n>>>>\n`%s'\n<<<<\n",getContents().data(),mifgen->getContents().data());
//printf("Appending \n>>>>\n`%s'\n<<<<\n and \n>>>>\n`%s'\n<<<<\n",getContents().data(),xg->getContents().data());
m_t << xg->getContents();
m_inParStack = xg->m_inParStack;
m_inListStack = xg->m_inListStack;
......@@ -697,6 +727,9 @@ class XMLGenerator : public OutputDocInterface
m_t.setDevice(&m_b);
m_t.setEncoding(QTextStream::Latin1);
//printf("Cloning >>%s<< m_parStack.count()=%d\n",
// xg->getContents().data(),xg->m_inParStack.count());
// copy state variables
m_inParStack = xg->m_inParStack;
m_inListStack = xg->m_inListStack;
......@@ -779,6 +812,18 @@ void writeXMLCodeBlock(QTextStream &t,FileDef *fd)
void generateXMLForMember(MemberDef *md,QTextStream &t,Definition *def)
{
// + declaration
// - reimplements
// - reimplementedBy
// - exceptions
// - const/volatile specifiers
// - examples
// + source definition
// - source references
// - source referenced by
// - include code
if (md->memberType()==MemberDef::EnumValue) return;
QCString scopeName;
......@@ -942,9 +987,67 @@ void generateXMLForMember(MemberDef *md,QTextStream &t,Definition *def)
t << " <detaileddescription>" << endl;
writeXMLDocBlock(t,md->getDefFileName(),md->getDefLine(),scopeName,md->name(),md->documentation());
t << " </detaileddescription>" << endl;
if (md->getDefLine()!=-1)
{
t << " <location file=\""
<< md->getDefFileName() << "\" line=\""
<< md->getDefLine() << "\"/>" << endl;
}
printf("md->getReferencesMembers()=%p\n",md->getReferencesMembers());
if (md->getReferencesMembers())
{
MemberSDict::Iterator mdi(*md->getReferencesMembers());
MemberDef *rmd;
for (mdi.toFirst();(rmd=mdi.current());++mdi)
{
if (rmd->getStartBodyLine()!=-1 && rmd->getBodyDef())
{
t << " <references id=\"";
t << rmd->getBodyDef()->getOutputFileBase()
<< "_1" // encoded `:' character (see util.cpp:convertNameToFile)
<< rmd->anchor()
<< "\" line=\""
<< rmd->getStartBodyLine()
<< "\">";
QCString scope = rmd->getScopeString();
QCString name = rmd->name();
if (!scope.isEmpty() && scope!=def->name())
{
name.prepend(scope+"::");
}
writeXMLString(t,name);
t << "</references>" << endl;
}
}
}
if (md->getReferencedByMembers())
{
MemberSDict::Iterator mdi(*md->getReferencedByMembers());
MemberDef *rmd;
for (mdi.toFirst();(rmd=mdi.current());++mdi)
{
if (rmd->getStartBodyLine()!=-1 && rmd->getBodyDef())
{
t << " <referencedby id=\"";
t << rmd->getBodyDef()->getOutputFileBase()
<< "_1" // encoded `:' character (see util.cpp:convertNameToFile)
<< rmd->anchor()
<< "\" line=\""
<< rmd->getStartBodyLine()
<< "\">";
QCString scope = rmd->getScopeString();
QCString name = rmd->name();
if (!scope.isEmpty() && scope!=def->name())
{
name.prepend(scope+"::");
}
writeXMLString(t,name);
t << "</referencedby>" << endl;
}
}
}
t << " </memberdef>" << endl;
}
......@@ -980,6 +1083,7 @@ void generateXMLForClass(ClassDef *cd,QTextStream &t)
// + user defined member sections
// + standard member sections
// + detailed member documentation
// - examples
if (cd->isReference()) return; // skip external references.
if (cd->name().find('@')!=-1) return; // skip anonymous compounds.
......
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