diff options
Diffstat (limited to 'tools/qdoc3')
42 files changed, 2944 insertions, 3124 deletions
diff --git a/tools/qdoc3/atom.cpp b/tools/qdoc3/atom.cpp index a82a783..da32735 100644 --- a/tools/qdoc3/atom.cpp +++ b/tools/qdoc3/atom.cpp @@ -93,6 +93,7 @@ QString Atom::UPPERROMAN_ ("upperroman"); \value AbstractLeft \value AbstractRight + \value AnnotatedList \value AutoLink \value BaseName \value BriefLeft @@ -163,6 +164,7 @@ static const struct { } atms[] = { { "AbstractLeft", Atom::AbstractLeft }, { "AbstractRight", Atom::AbstractRight }, + { "AnnotatedList", Atom::AnnotatedList }, { "AutoLink", Atom::AutoLink }, { "BaseName", Atom::BaseName }, { "BriefLeft", Atom::BriefLeft }, diff --git a/tools/qdoc3/atom.h b/tools/qdoc3/atom.h index 6d5af0a..941ac70 100644 --- a/tools/qdoc3/atom.h +++ b/tools/qdoc3/atom.h @@ -58,6 +58,7 @@ class Atom enum Type { AbstractLeft, AbstractRight, + AnnotatedList, AutoLink, BaseName, BriefLeft, diff --git a/tools/qdoc3/codemarker.cpp b/tools/qdoc3/codemarker.cpp index 728f9fa..4c018d1 100644 --- a/tools/qdoc3/codemarker.cpp +++ b/tools/qdoc3/codemarker.cpp @@ -168,7 +168,8 @@ const Node *CodeMarker::nodeForString(const QString& string) { if (sizeof(const Node *) == sizeof(uint)) { return reinterpret_cast<const Node *>(string.toUInt()); - } else { + } + else { return reinterpret_cast<const Node *>(string.toULongLong()); } } @@ -177,7 +178,8 @@ QString CodeMarker::stringForNode(const Node *node) { if (sizeof(const Node *) == sizeof(ulong)) { return QString::number(reinterpret_cast<ulong>(node)); - } else { + } + else { return QString::number(reinterpret_cast<qulonglong>(node)); } } @@ -220,7 +222,8 @@ QString CodeMarker::typified(const QString &string) || ch.digitValue() >= 0 || ch == QLatin1Char('_') || ch == QLatin1Char(':')) { pendingWord += ch; - } else { + } + else { if (!pendingWord.isEmpty()) { bool isProbablyType = (pendingWord != QLatin1String("const")); if (isProbablyType) @@ -251,7 +254,7 @@ QString CodeMarker::typified(const QString &string) return result; } -QString CodeMarker::taggedNode(const Node *node) +QString CodeMarker::taggedNode(const Node* node) { QString tag; @@ -276,11 +279,35 @@ QString CodeMarker::taggedNode(const Node *node) break; default: tag = QLatin1String("@unknown"); + break; } return QLatin1Char('<') + tag + QLatin1Char('>') + protect(node->name()) + QLatin1String("</") + tag + QLatin1Char('>'); } +#ifdef QDOC_QML +QString CodeMarker::taggedQmlNode(const Node* node) +{ + QString tag; + switch (node->type()) { + case Node::QmlProperty: + tag = QLatin1String("@property"); + break; + case Node::QmlSignal: + tag = QLatin1String("@signal"); + break; + case Node::QmlMethod: + tag = QLatin1String("@method"); + break; + default: + tag = QLatin1String("@unknown"); + break; + } + return QLatin1Char('<') + tag + QLatin1Char('>') + protect(node->name()) + + QLatin1String("</") + tag + QLatin1Char('>'); +} +#endif + QString CodeMarker::linkTag(const Node *node, const QString& body) { return QLatin1String("<@link node=\"") + stringForNode(node) @@ -308,9 +335,11 @@ QString CodeMarker::sortName(const Node *node) QString sortNo; if (func->metaness() == FunctionNode::Ctor) { sortNo = QLatin1String("C"); - } else if (func->metaness() == FunctionNode::Dtor) { + } + else if (func->metaness() == FunctionNode::Dtor) { sortNo = QLatin1String("D"); - } else { + } + else { if (nodeName.startsWith(QLatin1String("operator")) && nodeName.length() > 8 && !nodeName[8].isLetterOrNumber()) @@ -331,20 +360,30 @@ QString CodeMarker::sortName(const Node *node) return QLatin1Char('B') + nodeName; } -void CodeMarker::insert(FastSection &fastSection, Node *node, SynopsisStyle style, Status status) +void CodeMarker::insert(FastSection &fastSection, + Node *node, + SynopsisStyle style, + Status status) { - bool inheritedMember = (!node->relates() && - (node->parent() != (const InnerNode *)fastSection.innerNode)); bool irrelevant = false; + bool inheritedMember = false; + if (!node->relates()) { + if (node->parent() != (const InnerNode*)fastSection.innerNode) { + if (node->type() != Node::QmlProperty) + inheritedMember = true; + } + } if (node->access() == Node::Private) { irrelevant = true; - } else if (node->type() == Node::Function) { + } + else if (node->type() == Node::Function) { FunctionNode *func = (FunctionNode *) node; irrelevant = (inheritedMember && (func->metaness() == FunctionNode::Ctor || func->metaness() == FunctionNode::Dtor)); - } else if (node->type() == Node::Class || node->type() == Node::Enum + } + else if (node->type() == Node::Class || node->type() == Node::Enum || node->type() == Node::Typedef) { irrelevant = (inheritedMember && style != SeparateList); if (!irrelevant && style == Detailed && node->type() == Node::Typedef) { @@ -357,9 +396,11 @@ void CodeMarker::insert(FastSection &fastSection, Node *node, SynopsisStyle styl if (!irrelevant) { if (status == Compat) { irrelevant = (node->status() != Node::Compat); - } else if (status == Obsolete) { + } + else if (status == Obsolete) { irrelevant = (node->status() != Node::Obsolete); - } else { + } + else { irrelevant = (node->status() == Node::Compat || node->status() == Node::Obsolete); } @@ -370,7 +411,8 @@ void CodeMarker::insert(FastSection &fastSection, Node *node, SynopsisStyle styl QString key = sortName(node); if (!fastSection.memberMap.contains(key)) fastSection.memberMap.insert(key, node); - } else { + } + else { if (node->parent()->type() == Node::Class) { if (fastSection.inherited.isEmpty() || fastSection.inherited.last().first != node->parent()) { @@ -383,16 +425,42 @@ void CodeMarker::insert(FastSection &fastSection, Node *node, SynopsisStyle styl } } -void CodeMarker::append(QList<Section>& sectionList, - const FastSection& fastSection) +/*! + Returns true if \a node represents a reimplemented member function. + If it is, then it is inserted in the reimplemented member map in the + section \a fs. And, the test is only performed if \a status is \e OK. + Otherwise, false is returned. + */ +bool CodeMarker::insertReimpFunc(FastSection& fs, Node* node, Status status) +{ + if (node->access() == Node::Private) + return false; + + const FunctionNode* fn = static_cast<const FunctionNode*>(node); + if ((fn->reimplementedFrom() != 0) && (status == Okay)) { + bool inherited = (!fn->relates() && (fn->parent() != (const InnerNode*)fs.innerNode)); + if (!inherited) { + QString key = sortName(fn); + if (!fs.reimpMemberMap.contains(key)) { + fs.reimpMemberMap.insert(key,node); + return true; + } + } + } + return false; + } + +/*! + If \a fs is not empty, convert it to a Section and append + the new Section to \a sectionList. + */ +void CodeMarker::append(QList<Section>& sectionList, const FastSection& fs) { - if (!fastSection.memberMap.isEmpty() || - !fastSection.inherited.isEmpty()) { - Section section(fastSection.name, - fastSection.singularMember, - fastSection.pluralMember); - section.members = fastSection.memberMap.values(); - section.inherited = fastSection.inherited; + if (!fs.isEmpty()) { + Section section(fs.name,fs.singularMember,fs.pluralMember); + section.members = fs.memberMap.values(); + section.reimpMembers = fs.reimpMemberMap.values(); + section.inherited = fs.inherited; sectionList.append(section); } } @@ -428,7 +496,8 @@ QStringList CodeMarker::macRefsForNode(const Node *node) #if 0 if (!classe->templateStuff().isEmpty()) { result += QLatin1String("tmplt/"); - } else + } + else #endif { result += QLatin1String("cl/"); @@ -465,14 +534,18 @@ QStringList CodeMarker::macRefsForNode(const Node *node) result += QLatin1String("macro/"); isMacro = true; #if 0 - } else if (!func->templateStuff().isEmpty()) { + } + else if (!func->templateStuff().isEmpty()) { result += QLatin1String("ftmplt/"); #endif - } else if (func->isStatic()) { + } + else if (func->isStatic()) { result += QLatin1String("clm/"); - } else if (!func->parent()->name().isEmpty()) { + } + else if (!func->parent()->name().isEmpty()) { result += QLatin1String("instm/"); - } else { + } + else { result += QLatin1String("func/"); } @@ -486,7 +559,8 @@ QStringList CodeMarker::macRefsForNode(const Node *node) result += "/" + QLatin1String(QMetaObject::normalizedSignature(func->returnType().toLatin1().constData())) + "/("; const QList<Parameter> ¶ms = func->parameters(); for (int i = 0; i < params.count(); ++i) { - QString type = params.at(i).leftType() + params.at(i).rightType(); + QString type = params.at(i).leftType() + + params.at(i).rightType(); type = QLatin1String(QMetaObject::normalizedSignature(type.toLatin1().constData())); if (i != 0) result += ","; @@ -529,10 +603,21 @@ QString CodeMarker::macName(const Node *node, const QString &name) if (node->name().isEmpty()) { return QLatin1Char('/') + myName; - } else { + } + else { return plainFullName(node) + QLatin1Char('/') + myName; } } +#ifdef QDOC_QML +/*! + Get the list of documentation sections for the children of + the specified QmlClassNode. + */ +QList<Section> CodeMarker::qmlSections(const QmlClassNode* , SynopsisStyle ) +{ + return QList<Section>(); +} +#endif QT_END_NAMESPACE diff --git a/tools/qdoc3/codemarker.h b/tools/qdoc3/codemarker.h index 483dc4d..91dc8b0 100644 --- a/tools/qdoc3/codemarker.h +++ b/tools/qdoc3/codemarker.h @@ -61,6 +61,7 @@ struct Section QString singularMember; QString pluralMember; NodeList members; + NodeList reimpMembers; QList<QPair<ClassNode *, int> > inherited; Section() { } @@ -79,6 +80,7 @@ struct FastSection QString singularMember; QString pluralMember; QMap<QString, Node *> memberMap; + QMap<QString, Node *> reimpMemberMap; QList<QPair<ClassNode *, int> > inherited; FastSection(const InnerNode *innerNode0, @@ -89,6 +91,11 @@ struct FastSection name(name0), singularMember(singularMember0), pluralMember(pluralMember0) { } + bool isEmpty() const { + return (memberMap.isEmpty() && inherited.isEmpty() && + reimpMemberMap.isEmpty()); + } + }; class CodeMarker @@ -114,6 +121,9 @@ class CodeMarker virtual QString markedUpSynopsis(const Node *node, const Node *relative, SynopsisStyle style) = 0; +#ifdef QDOC_QML + virtual QString markedUpQmlItem(const Node* , bool) { return QString(); } +#endif virtual QString markedUpName(const Node *node) = 0; virtual QString markedUpFullName(const Node *node, const Node *relative = 0) = 0; @@ -125,6 +135,10 @@ class CodeMarker virtual QList<Section> sections(const InnerNode *inner, SynopsisStyle style, Status status) = 0; +#ifdef QDOC_QML + virtual QList<Section> qmlSections(const QmlClassNode* qmlClassNode, + SynopsisStyle style); +#endif virtual const Node *resolveTarget(const QString& target, const Tree *tree, const Node *relative) = 0; @@ -144,12 +158,16 @@ class CodeMarker virtual QString sortName(const Node *node); QString protect(const QString &string); QString typified(const QString &string); - QString taggedNode(const Node *node); + QString taggedNode(const Node* node); +#ifdef QDOC_QML + QString taggedQmlNode(const Node* node); +#endif QString linkTag(const Node *node, const QString& body); void insert(FastSection &fastSection, Node *node, SynopsisStyle style, Status status); + bool insertReimpFunc(FastSection& fs, Node* node, Status status); void append(QList<Section>& sectionList, const FastSection& fastSection); private: diff --git a/tools/qdoc3/codeparser.cpp b/tools/qdoc3/codeparser.cpp index 2fedd67..92243fa 100644 --- a/tools/qdoc3/codeparser.cpp +++ b/tools/qdoc3/codeparser.cpp @@ -47,6 +47,7 @@ #include "codeparser.h" #include "node.h" #include "tree.h" +#include "config.h" QT_BEGIN_NAMESPACE @@ -67,6 +68,7 @@ QT_BEGIN_NAMESPACE #define COMMAND_TITLE Doc::alias(QLatin1String("title")) QList<CodeParser *> CodeParser::parsers; +bool CodeParser::showInternal = false; /*! The constructor adds this code parser to the static @@ -87,11 +89,11 @@ CodeParser::~CodeParser() } /*! - Initializing a code parser is trivial. + Initialize the code parser base class. */ -void CodeParser::initializeParser(const Config & /* config */) +void CodeParser::initializeParser(const Config& config) { - // nothing. + showInternal = config.getBool(QLatin1String(CONFIG_SHOWINTERNAL)); } /*! @@ -217,8 +219,10 @@ void CodeParser::processCommonMetaCommand(const Location &location, node->setStatus(Node::Preliminary); } else if (command == COMMAND_INTERNAL) { - node->setAccess(Node::Private); - node->setStatus(Node::Internal); + if (!showInternal) { + node->setAccess(Node::Private); + node->setStatus(Node::Internal); + } } else if (command == COMMAND_REENTRANT) { node->setThreadSafeness(Node::Reentrant); @@ -241,19 +245,6 @@ void CodeParser::processCommonMetaCommand(const Location &location, if (node->type() == Node::Fake) { FakeNode *fake = static_cast<FakeNode *>(node); fake->setTitle(arg); -#ifdef QDOC2DOX - /* qdoc -> doxygen. - I think this must be done here, because there can be multiple - "\externalpage" and "\title" metacommands in a single qdoc - comment, which means, among other things, that the "\title" - commands are not inserted into the metacommand map used by - the Doc class. I'm sure there4 is a better way to do this in - the DoxWriter class using the information in the FakeNode, - but I don't have time to figure it out right now. - */ - if (DoxWriter::isDoxPass(1)) - DoxWriter::insertTitle(fake,arg); -#endif } else location.warning(tr("Ignored '\\%1'").arg(COMMAND_TITLE)); diff --git a/tools/qdoc3/codeparser.h b/tools/qdoc3/codeparser.h index 8f5bd87..06603a9 100644 --- a/tools/qdoc3/codeparser.h +++ b/tools/qdoc3/codeparser.h @@ -87,6 +87,7 @@ class CodeParser private: static QList<CodeParser *> parsers; + static bool showInternal; }; QT_END_NAMESPACE diff --git a/tools/qdoc3/command.cpp b/tools/qdoc3/command.cpp index e51e235..bce262b 100644 --- a/tools/qdoc3/command.cpp +++ b/tools/qdoc3/command.cpp @@ -49,44 +49,46 @@ QT_BEGIN_NAMESPACE -void executeCommand( const Location& location, const QString& format, - const QStringList& args ) +void executeCommand(const Location& location, + const QString& format, + const QStringList& args) { QString actualCommand; - for ( int i = 0; i < (int) format.length(); i++ ) { + for (int i = 0; i < (int) format.length(); i++) { int ch = format[i].unicode(); - if ( ch > 0 && ch < 8 ) { + if (ch > 0 && ch < 8) { actualCommand += args[ch - 1]; - } else { + } + else { actualCommand += format[i]; } } QString toolName = actualCommand; - int space = toolName.indexOf( QLatin1Char(' ') ); - if ( space != -1 ) - toolName.truncate( space ); + int space = toolName.indexOf(QLatin1Char(' ')); + if (space != -1) + toolName.truncate(space); QProcess process; process.start(QLatin1String("sh"), - QStringList() << QLatin1String("-c") << actualCommand ); + QStringList() << QLatin1String("-c") << actualCommand); process.waitForFinished(); if (process.exitCode() == 127) - location.fatal( tr("Couldn't launch the '%1' tool") - .arg(toolName), - tr("Make sure the tool is installed and in the" - " path.") ); + location.fatal(tr("Couldn't launch the '%1' tool") + .arg(toolName), + tr("Make sure the tool is installed and in the" + " path.")); QString errors = QString::fromLocal8Bit(process.readAllStandardError()); - while ( errors.endsWith(QLatin1Char('\n')) ) - errors.truncate( errors.length() - 1 ); - if ( !errors.isEmpty() ) - location.fatal( tr("The '%1' tool encountered some problems") - .arg(toolName), - tr("The tool was invoked like this:\n%1\n" - "It emitted these errors:\n%2") - .arg(actualCommand).arg(errors) ); + while (errors.endsWith(QLatin1Char('\n'))) + errors.truncate(errors.length() - 1); + if (!errors.isEmpty()) + location.fatal(tr("The '%1' tool encountered some problems") + .arg(toolName), + tr("The tool was invoked like this:\n%1\n" + "It emitted these errors:\n%2") + .arg(actualCommand).arg(errors)); } QT_END_NAMESPACE diff --git a/tools/qdoc3/config.cpp b/tools/qdoc3/config.cpp index 20b0aa7..ad993d9 100644 --- a/tools/qdoc3/config.cpp +++ b/tools/qdoc3/config.cpp @@ -751,7 +751,7 @@ void Config::load(Location location, const QString& fileName) word += QChar(c.digitValue()); SKIP_CHAR(); } - else if ((metaCharPos = QString(QLatin1String("abfnrtv")).indexOf(c)) != -1) { + else if ((metaCharPos = QString::fromLatin1("abfnrtv").indexOf(c)) != -1) { word += "\a\b\f\n\r\t\v"[metaCharPos]; SKIP_CHAR(); } diff --git a/tools/qdoc3/config.h b/tools/qdoc3/config.h index 8f25340..22cb671 100644 --- a/tools/qdoc3/config.h +++ b/tools/qdoc3/config.h @@ -140,6 +140,7 @@ class Config #define CONFIG_INDEXES "indexes" #define CONFIG_LANGUAGE "language" #define CONFIG_MACRO "macro" +#define CONFIG_OBSOLETELINKS "obsoletelinks" #define CONFIG_OUTPUTDIR "outputdir" #define CONFIG_OUTPUTLANGUAGE "outputlanguage" #define CONFIG_OUTPUTFORMATS "outputformats" @@ -147,6 +148,7 @@ class Config #define CONFIG_QHP "qhp" #define CONFIG_QUOTINGINFORMATION "quotinginformation" #define CONFIG_SLOW "slow" +#define CONFIG_SHOWINTERNAL "showinternal" #define CONFIG_SOURCEDIRS "sourcedirs" #define CONFIG_SOURCES "sources" #define CONFIG_SPURIOUS "spurious" diff --git a/tools/qdoc3/cppcodemarker.cpp b/tools/qdoc3/cppcodemarker.cpp index 6760c65..0f8d1b7 100644 --- a/tools/qdoc3/cppcodemarker.cpp +++ b/tools/qdoc3/cppcodemarker.cpp @@ -43,6 +43,7 @@ cppcodemarker.cpp */ +#include <qdebug.h> #include "atom.h" #include "cppcodemarker.h" #include "node.h" @@ -283,7 +284,7 @@ QString CppCodeMarker::markedUpSynopsis(const Node *node, } else { for (int i = 0; i < documentedItems.size(); ++i) { - if (i < MaxEnumValues - 2 || i == documentedItems.size() - 1) { + if (i < MaxEnumValues-2 || i == documentedItems.size()-1) { if (i != 0) synopsis += ", "; synopsis += documentedItems.at(i); @@ -344,6 +345,43 @@ QString CppCodeMarker::markedUpSynopsis(const Node *node, return synopsis + extra; } +#ifdef QDOC_QML +/*! + */ +QString CppCodeMarker::markedUpQmlItem(const Node* node, bool summary) +{ + QString name = taggedQmlNode(node); + if (summary) { + name = linkTag(node,name); + } + name = "<@name>" + name + "</@name>"; + QString synopsis = name; + if (node->type() == Node::QmlProperty) { + const QmlPropertyNode* pn = static_cast<const QmlPropertyNode*>(node); + synopsis += " : " + typified(pn->dataType()); + } + + QString extra; + if (summary) { + if (node->status() == Node::Preliminary) { + extra += " (preliminary)"; + } + else if (node->status() == Node::Deprecated) { + extra += " (deprecated)"; + } + else if (node->status() == Node::Obsolete) { + extra += " (obsolete)"; + } + } + + if (!extra.isEmpty()) { + extra.prepend("<@extra>"); + extra.append("</@extra>"); + } + return synopsis + extra; +} +#endif + QString CppCodeMarker::markedUpName(const Node *node) { QString name = linkTag(node, taggedNode(node)); @@ -411,6 +449,21 @@ QString CppCodeMarker::functionEndRegExp(const QString& /* funcName */) return "^\\}$"; } +#if 0 + FastSection privateReimpFuncs(classe, + "Private Reimplemented Functions", + "private reimplemented function", + "private reimplemented functions"); + FastSection protectedReimpFuncs(classe, + "Protected Reimplemented Functions", + "protected reimplemented function", + "protected reimplemented functions"); + FastSection publicReimpFuncs(classe, + "Public Reimplemented Functions", + "public reimplemented function", + "public reimplemented functions"); +#endif + QList<Section> CppCodeMarker::sections(const InnerNode *inner, SynopsisStyle style, Status status) @@ -421,29 +474,55 @@ QList<Section> CppCodeMarker::sections(const InnerNode *inner, const ClassNode *classe = static_cast<const ClassNode *>(inner); if (style == Summary) { - FastSection privateFunctions(classe, "Private Functions", "private function", + FastSection privateFunctions(classe, + "Private Functions", + "private function", "private functions"); FastSection privateSlots(classe, "Private Slots", "private slot", "private slots"); FastSection privateTypes(classe, "Private Types", "private type", "private types"); - FastSection protectedFunctions(classe, "Protected Functions", "protected function", + FastSection protectedFunctions(classe, + "Protected Functions", + "protected function", "protected functions"); - FastSection protectedSlots(classe, "Protected Slots", "protected slot", "protected slots"); - FastSection protectedTypes(classe, "Protected Types", "protected type", "protected types"); - FastSection protectedVariables(classe, "Protected Variables", "protected type", "protected variables"); - FastSection publicFunctions(classe, "Public Functions", "public function", - "public functions"); + FastSection protectedSlots(classe, + "Protected Slots", + "protected slot", + "protected slots"); + FastSection protectedTypes(classe, + "Protected Types", + "protected type", + "protected types"); + FastSection protectedVariables(classe, + "Protected Variables", + "protected type", + "protected variables"); + FastSection publicFunctions(classe, + "Public Functions", + "public function", + "public functions"); FastSection publicSignals(classe, "Signals", "signal", "signals"); FastSection publicSlots(classe, "Public Slots", "public slot", "public slots"); FastSection publicTypes(classe, "Public Types", "public type", "public types"); - FastSection publicVariables(classe, "Public Variables", "public type", "public variables"); + FastSection publicVariables(classe, + "Public Variables", + "public type", + "public variables"); FastSection properties(classe, "Properties", "property", "properties"); - FastSection relatedNonMembers(classe, "Related Non-Members", "related non-member", + FastSection relatedNonMembers(classe, + "Related Non-Members", + "related non-member", "related non-members"); - FastSection staticPrivateMembers(classe, "Static Private Members", "static private member", + FastSection staticPrivateMembers(classe, + "Static Private Members", + "static private member", "static private members"); - FastSection staticProtectedMembers(classe, "Static Protected Members", - "static protected member", "static protected members"); - FastSection staticPublicMembers(classe, "Static Public Members", "static public member", + FastSection staticProtectedMembers(classe, + "Static Protected Members", + "static protected member", + "static protected members"); + FastSection staticPublicMembers(classe, + "Static Public Members", + "static public member", "static public members"); FastSection macros(inner, "Macros", "macro", "macros"); @@ -495,7 +574,7 @@ QList<Section> CppCodeMarker::sections(const InnerNode *inner, else if (isStatic) { if ((*c)->type() != Node::Variable || !(*c)->doc().isEmpty()) - insert(staticPublicMembers, *c, style, status); + insert(staticPublicMembers,*c,style,status); } else if ((*c)->type() == Node::Property) { insert(properties, *c, style, status); @@ -505,7 +584,8 @@ QList<Section> CppCodeMarker::sections(const InnerNode *inner, insert(publicVariables, *c, style, status); } else if ((*c)->type() == Node::Function) { - insert(publicFunctions, *c, style, status); + if (!insertReimpFunc(publicFunctions,*c,status)) + insert(publicFunctions, *c, style, status); } else { insert(publicTypes, *c, style, status); @@ -518,14 +598,15 @@ QList<Section> CppCodeMarker::sections(const InnerNode *inner, else if (isStatic) { if ((*c)->type() != Node::Variable || !(*c)->doc().isEmpty()) - insert(staticProtectedMembers, *c, style, status); + insert(staticProtectedMembers,*c,style,status); } else if ((*c)->type() == Node::Variable) { if (!(*c)->doc().isEmpty()) - insert(protectedVariables, *c, style, status); + insert(protectedVariables,*c,style,status); } else if ((*c)->type() == Node::Function) { - insert(protectedFunctions, *c, style, status); + if (!insertReimpFunc(protectedFunctions,*c,status)) + insert(protectedFunctions, *c, style, status); } else { insert(protectedTypes, *c, style, status); @@ -538,13 +619,14 @@ QList<Section> CppCodeMarker::sections(const InnerNode *inner, else if (isStatic) { if ((*c)->type() != Node::Variable || !(*c)->doc().isEmpty()) - insert(staticPrivateMembers, *c, style, status); + insert(staticPrivateMembers,*c,style,status); } else if ((*c)->type() == Node::Function) { - insert(privateFunctions, *c, style, status); + if (!insertReimpFunc(privateFunctions,*c,status)) + insert(privateFunctions, *c, style, status); } else { - insert(privateTypes, *c, style, status); + insert(privateTypes,*c,style,status); } } ++c; @@ -661,17 +743,23 @@ QList<Section> CppCodeMarker::sections(const InnerNode *inner, "Namespaces", "namespace", "namespaces"); - FastSection classes(inner, "Classes", "class", "classes"); + FastSection classes(inner, + "Classes", + "class", + "classes"); FastSection types(inner, - style == Summary ? "Types" : "Type Documentation", + style == Summary ? + "Types" : "Type Documentation", "type", "types"); FastSection functions(inner, - style == Summary ? "Functions" : "Function Documentation", + style == Summary ? + "Functions" : "Function Documentation", "function", "functions"); FastSection macros(inner, - style == Summary ? "Macros" : "Macro Documentation", + style == Summary ? + "Macros" : "Macro Documentation", "macro", "macros"); @@ -1006,4 +1094,82 @@ QString CppCodeMarker::addMarkUp(const QString& protectedCode, return result; } +#ifdef QDOC_QML +/*! + This function is for documenting QML properties. It returns + the list of documentation sections for the children of the + \a qmlClassNode. + + Currently, it only handles QML property groups. + */ +QList<Section> CppCodeMarker::qmlSections(const QmlClassNode* qmlClassNode, + SynopsisStyle style) +{ + QList<Section> sections; + if (qmlClassNode) { + if (style == Summary) { + FastSection qmlproperties(qmlClassNode, + "QML Properties", + "property", + "properties"); + FastSection qmlsignals(qmlClassNode, + "QML Signals", + "signal", + "signals"); + FastSection qmlmethods(qmlClassNode, + "QML Methods", + "method", + "methods"); + + NodeList::ConstIterator c = qmlClassNode->childNodes().begin(); + while (c != qmlClassNode->childNodes().end()) { + if ((*c)->subType() == Node::QmlPropertyGroup) { + const QmlPropGroupNode* qpgn = static_cast<const QmlPropGroupNode*>(*c); + NodeList::ConstIterator p = qpgn->childNodes().begin(); + while (p != qpgn->childNodes().end()) { + if ((*p)->type() == Node::QmlProperty) { + insert(qmlproperties,*p,style,Okay); + } + ++p; + } + } + else if ((*c)->type() == Node::QmlSignal) { + insert(qmlsignals,*c,style,Okay); + } + else if ((*c)->type() == Node::QmlMethod) { + insert(qmlmethods,*c,style,Okay); + } + ++c; + } + append(sections,qmlproperties); + append(sections,qmlsignals); + append(sections,qmlmethods); + } + else if (style == Detailed) { + FastSection qmlproperties(qmlClassNode,"QML Property Documentation"); + FastSection qmlsignals(qmlClassNode,"QML Signal Documentation"); + FastSection qmlmethods(qmlClassNode,"QML Method Documentation"); + NodeList::ConstIterator c = qmlClassNode->childNodes().begin(); + while (c != qmlClassNode->childNodes().end()) { + if ((*c)->subType() == Node::QmlPropertyGroup) { + insert(qmlproperties,*c,style,Okay); + } + else if ((*c)->type() == Node::QmlSignal) { + insert(qmlsignals,*c,style,Okay); + } + else if ((*c)->type() == Node::QmlMethod) { + insert(qmlmethods,*c,style,Okay); + } + ++c; + } + append(sections,qmlproperties); + append(sections,qmlsignals); + append(sections,qmlmethods); + } + } + + return sections; +} +#endif + QT_END_NAMESPACE diff --git a/tools/qdoc3/cppcodemarker.h b/tools/qdoc3/cppcodemarker.h index 2967dfe..fa3cb78 100644 --- a/tools/qdoc3/cppcodemarker.h +++ b/tools/qdoc3/cppcodemarker.h @@ -67,6 +67,9 @@ class CppCodeMarker : public CodeMarker QString markedUpSynopsis(const Node *node, const Node *relative, SynopsisStyle style); +#ifdef QDOC_QML + QString markedUpQmlItem(const Node *node, bool summary); +#endif QString markedUpName(const Node *node); QString markedUpFullName(const Node *node, const Node *relative); QString markedUpEnumValue(const QString &enumValue, const Node *relative); @@ -76,6 +79,8 @@ class CppCodeMarker : public CodeMarker QList<Section> sections(const InnerNode *innerNode, SynopsisStyle style, Status status); + QList<Section> qmlSections(const QmlClassNode* qmlClassNode, + SynopsisStyle style); const Node *resolveTarget(const QString& target, const Tree *tree, const Node *relative); diff --git a/tools/qdoc3/cppcodeparser.cpp b/tools/qdoc3/cppcodeparser.cpp index 204c6e5..562684b 100644 --- a/tools/qdoc3/cppcodeparser.cpp +++ b/tools/qdoc3/cppcodeparser.cpp @@ -87,6 +87,10 @@ QT_BEGIN_NAMESPACE #ifdef QDOC_QML #define COMMAND_QMLCLASS Doc::alias("qmlclass") #define COMMAND_QMLPROPERTY Doc::alias("qmlproperty") +#define COMMAND_QMLINHERITS Doc::alias("inherits") +#define COMMAND_QMLSIGNAL Doc::alias("qmlsignal") +#define COMMAND_QMLMETHOD Doc::alias("qmlmethod") +#define COMMAND_QMLDEFAULT Doc::alias("default") #endif QStringList CppCodeParser::exampleFiles; @@ -109,7 +113,8 @@ static void extractPageLinkAndDesc(const QString &arg, if (arg.contains(".html") && spaceAt != -1) { *link = arg.left(spaceAt).trimmed(); *desc = arg.mid(spaceAt).trimmed(); - } else { + } + else { *link = arg; *desc = arg; } @@ -202,11 +207,6 @@ void CppCodeParser::initializeParser(const Config &config) nodeTypeMap.insert(COMMAND_PROPERTY, Node::Property); nodeTypeMap.insert(COMMAND_VARIABLE, Node::Variable); -#ifdef QDOC_QML - // nodeTypeMap.insert(COMMAND_QMLCLASS, Node::Class); - nodeTypeMap.insert(COMMAND_QMLPROPERTY, Node::Property); -#endif - exampleFiles = config.getStringList(CONFIG_EXAMPLES); exampleDirs = config.getStringList(CONFIG_EXAMPLEDIRS); QStringList exampleFilePatterns = config.getStringList( @@ -477,13 +477,15 @@ QSet<QString> CppCodeParser::topicCommands() << COMMAND_PROPERTY << COMMAND_SERVICE << COMMAND_TYPEDEF -#ifdef QDOC_QML +#ifdef QDOC_QML << COMMAND_VARIABLE << COMMAND_QMLCLASS - << COMMAND_QMLPROPERTY; -#else + << COMMAND_QMLPROPERTY + << COMMAND_QMLSIGNAL + << COMMAND_QMLMETHOD; +#else << COMMAND_VARIABLE; -#endif +#endif } /*! @@ -587,24 +589,8 @@ Node *CppCodeParser::processTopicCommand(const Doc& doc, The command was neither "fn" nor "macro" . */ // ### split(" ") hack is there to support header file syntax - QStringList paths = arg.split(" "); + QStringList paths = arg.split(" "); QStringList path = paths[0].split("::"); - -#if QDOC2DOX - // qdoc -> doxygen. - if (Doc::isDoxPass(1)) { - if (command == COMMAND_PROPERTY) { - Doc::insertProperty(path); - } - else if (command == COMMAND_VARIABLE) { - Doc::insertVariable(path); - } - else if (command == COMMAND_ENUM) { - // zzz - } - } -#endif - Node *node = 0; if (!usedNamespaces.isEmpty()) { foreach (const QString &usedNamespace, usedNamespaces) { @@ -643,49 +629,169 @@ Node *CppCodeParser::processTopicCommand(const Doc& doc, } } + if (command == COMMAND_CLASS) { + if (paths.size() > 1) { + if (!paths[1].endsWith(".h")) { + ClassNode*cnode = static_cast<ClassNode*>(node); + cnode->setQmlElement(paths[1]); + } + } + } return node; } else if (command == COMMAND_EXAMPLE) { - FakeNode *fake = new FakeNode(tre->root(), arg, FakeNode::Example); + FakeNode *fake = new FakeNode(tre->root(), arg, Node::Example); createExampleFileNodes(fake); return fake; } else if (command == COMMAND_EXTERNALPAGE) { - return new FakeNode(tre->root(), arg, FakeNode::ExternalPage); + return new FakeNode(tre->root(), arg, Node::ExternalPage); } else if (command == COMMAND_FILE) { - return new FakeNode(tre->root(), arg, FakeNode::File); + return new FakeNode(tre->root(), arg, Node::File); } else if (command == COMMAND_GROUP) { - return new FakeNode(tre->root(), arg, FakeNode::Group); + return new FakeNode(tre->root(), arg, Node::Group); } else if (command == COMMAND_HEADERFILE) { - return new FakeNode(tre->root(), arg, FakeNode::HeaderFile); + return new FakeNode(tre->root(), arg, Node::HeaderFile); } else if (command == COMMAND_MODULE) { - return new FakeNode(tre->root(), arg, FakeNode::Module); + return new FakeNode(tre->root(), arg, Node::Module); } else if (command == COMMAND_PAGE) { - return new FakeNode(tre->root(), arg, FakeNode::Page); + return new FakeNode(tre->root(), arg, Node::Page); } -#ifdef QDOC_QML +#ifdef QDOC_QML else if (command == COMMAND_QMLCLASS) { const ClassNode* classNode = 0; - QStringList names = arg.split(" "); - //qDebug() << "QMLCLASS" << names; + QStringList names = arg.split(" "); if (names.size() > 1) { Node* n = tre->findNode(names[1].split("::"),Node::Class); - if (n) { + if (n) classNode = static_cast<const ClassNode*>(n); - //qDebug() << "FOUND IT!" << classNode->name(); + } + return new QmlClassNode(tre->root(), names[0], classNode); + } + else if ((command == COMMAND_QMLSIGNAL) || + (command == COMMAND_QMLMETHOD)) { + QString element; + QString name; + QmlClassNode* qmlClass = 0; + if (splitQmlArg(doc,arg,element,name)) { + Node* n = tre->findNode(QStringList(element),Node::Fake); + if (n && n->subType() == Node::QmlClass) { + qmlClass = static_cast<QmlClassNode*>(n); + if (command == COMMAND_QMLSIGNAL) + return new QmlSignalNode(qmlClass,name); + else + return new QmlMethodNode(qmlClass,name); } } - return new QmlNode(tre->root(), names[0], classNode); } -#endif +#endif return 0; } +#ifdef QDOC_QML + +/*! + A QML property argument has the form... + + <type> <element>::<name> + + This function splits the argument into those three + parts, sets \a type, \a element, and \a property, + and returns true. If any of the parts isn't found, + a debug message is output and false is returned. + */ +bool CppCodeParser::splitQmlPropertyArg(const Doc& doc, + const QString& arg, + QString& type, + QString& element, + QString& property) +{ + QStringList blankSplit = arg.split(" "); + if (blankSplit.size() > 1) { + type = blankSplit[0]; + QStringList colonSplit(blankSplit[1].split("::")); + if (colonSplit.size() > 1) { + element = colonSplit[0]; + property = colonSplit[1]; + return true; + } + else + doc.location().warning(tr("Missing QML element name or property name")); + } + else + doc.location().warning(tr("Missing QML property type or property path")); + return false; +} + +/*! + A QML signal or method argument has the form... + + <element>::<name> + + This function splits the argument into those two + parts, sets \a element, and \a name, and returns + true. If either of the parts isn't found, a debug + message is output and false is returned. + */ +bool CppCodeParser::splitQmlArg(const Doc& doc, + const QString& arg, + QString& element, + QString& name) +{ + QStringList colonSplit(arg.split("::")); + if (colonSplit.size() > 1) { + element = colonSplit[0]; + name = colonSplit[1]; + return true; + } + else + doc.location().warning(tr("Missing QML element name or signal/method name")); + return false; +} + +/*! + Process the topic \a command group with arguments \a args. + + Currently, this function is called only for \e{qmlproperty}. + */ +Node *CppCodeParser::processTopicCommandGroup(const Doc& doc, + const QString& command, + const QStringList& args) +{ + QmlPropGroupNode* qmlPropGroup = 0; + if (command == COMMAND_QMLPROPERTY) { + QString type; + QString element; + QString property; + QStringList::ConstIterator arg = args.begin(); + if (splitQmlPropertyArg(doc,(*arg),type,element,property)) { + Node* n = tre->findNode(QStringList(element),Node::Fake); + if (n && n->subType() == Node::QmlClass) { + QmlClassNode* qmlClass = static_cast<QmlClassNode*>(n); + if (qmlClass) + qmlPropGroup = new QmlPropGroupNode(qmlClass,property); + } + } + if (qmlPropGroup) { + new QmlPropertyNode(qmlPropGroup,property,type); + ++arg; + while (arg != args.end()) { + if (splitQmlPropertyArg(doc,(*arg),type,element,property)) { + new QmlPropertyNode(qmlPropGroup,property,type); + } + ++arg; + } + } + } + return qmlPropGroup; +} +#endif + /*! Returns the set of strings representing the common metacommands plus some other metacommands. @@ -700,7 +806,13 @@ QSet<QString> CppCodeParser::otherMetaCommands() << COMMAND_NEXTPAGE << COMMAND_PREVIOUSPAGE << COMMAND_INDEXPAGE +#ifdef QDOC_QML + << COMMAND_STARTPAGE + << COMMAND_QMLINHERITS + << COMMAND_QMLDEFAULT; +#else << COMMAND_STARTPAGE; +#endif } /*! @@ -742,21 +854,29 @@ void CppCodeParser::processOtherMetaCommand(const Doc& doc, tr("The function either doesn't exist in any base class " "with the same signature or it exists but isn't virtual.")); } -#if 0 // Ideally, we would enable this check to warn whenever \reimp is used - // incorrectly, and only make the node internal if the function is a - // reimplementation of another function in a base class. + /* + Ideally, we would enable this check to warn whenever + \reimp is used incorrectly, and only make the node + internal if the function is a reimplementation of + another function in a base class. + */ else if (from->access() == Node::Private || from->parent()->access() == Node::Private) { - doc.location().warning( - tr("Base function for '\\%1' in %2() is private or internal") + doc.location().warning(tr("'\\%1' in %2() should be '\\internal' because its base function is private or internal") .arg(COMMAND_REIMP).arg(node->name())); } -#endif - // Note: Setting the access to Private hides the documentation, - // but setting the status to Internal makes the node available - // in the XML output when the WebXMLGenerator is used. + +#if 0 + // Reimplemented functions now reported in separate sections. + /* + Note: Setting the access to Private hides the documentation, + but setting the status to Internal makes the node available + in the XML output when the WebXMLGenerator is used. + */ func->setAccess(Node::Private); func->setStatus(Node::Internal); +#endif + func->setReimp(true); } else { doc.location().warning(tr("Ignored '\\%1' in %2") @@ -767,14 +887,19 @@ void CppCodeParser::processOtherMetaCommand(const Doc& doc, else if (command == COMMAND_RELATES) { InnerNode *pseudoParent; if (arg.startsWith("<") || arg.startsWith("\"")) { - pseudoParent = static_cast<InnerNode *>(tre->findNode(QStringList(arg), Node::Fake)); + pseudoParent = + static_cast<InnerNode *>(tre->findNode(QStringList(arg), + Node::Fake)); } else { QStringList newPath = arg.split("::"); - pseudoParent = static_cast<InnerNode *>(tre->findNode(QStringList(newPath), Node::Class)); + pseudoParent = + static_cast<InnerNode*>(tre->findNode(QStringList(newPath), + Node::Class)); if (!pseudoParent) - pseudoParent = static_cast<InnerNode *>(tre->findNode(QStringList(newPath), - Node::Namespace)); + pseudoParent = + static_cast<InnerNode*>(tre->findNode(QStringList(newPath), + Node::Namespace)); } if (!pseudoParent) { doc.location().warning(tr("Cannot find '%1' in '\\%2'") @@ -799,6 +924,15 @@ void CppCodeParser::processOtherMetaCommand(const Doc& doc, else if (command == COMMAND_STARTPAGE) { setLink(node, Node::StartLink, arg); } +#ifdef QDOC_QML + else if (command == COMMAND_QMLINHERITS) { + setLink(node, Node::InheritsLink, arg); + } + else if (command == COMMAND_QMLDEFAULT) { + QmlPropGroupNode* qpgn = static_cast<QmlPropGroupNode*>(node); + qpgn->setDefault(); + } +#endif else { processCommonMetaCommand(doc.location(),command,arg,node,tre); } @@ -878,9 +1012,8 @@ bool CppCodeParser::match(int target) readToken(); return true; } - else { + else return false; - } } /*! @@ -915,11 +1048,14 @@ bool CppCodeParser::matchTemplateAngles(CodeChunk *dataType) do { if (tok == Tok_LeftAngle) { leftAngleDepth++; - } else if (tok == Tok_RightAngle) { + } + else if (tok == Tok_RightAngle) { leftAngleDepth--; - } else if (tok == Tok_LeftParen || tok == Tok_LeftBrace) { + } + else if (tok == Tok_LeftParen || tok == Tok_LeftBrace) { ++parenAndBraceDepth; - } else if (tok == Tok_RightParen || tok == Tok_RightBrace) { + } + else if (tok == Tok_RightParen || tok == Tok_RightBrace) { if (--parenAndBraceDepth < 0) return false; } @@ -982,7 +1118,8 @@ bool CppCodeParser::matchDataType(CodeChunk *dataType, QString *var) dataType->append(previousLexeme()); else return false; - } else if (match(Tok_int) || match(Tok_char) || match(Tok_double)) { + } + else if (match(Tok_int) || match(Tok_char) || match(Tok_double)) { dataType->append(previousLexeme()); } @@ -1082,8 +1219,10 @@ bool CppCodeParser::matchParameter(FunctionNode *func) readToken(); } } - func->addParameter(Parameter(dataType.toString(), "", name, - defaultValue.toString())); // ### + func->addParameter(Parameter(dataType.toString(), + "", + name, + defaultValue.toString())); // ### return true; } @@ -1131,7 +1270,8 @@ bool CppCodeParser::matchFunctionDecl(InnerNode *parent, compat = true; if (tok == Tok_operator && - (returnType.toString().isEmpty() || returnType.toString().endsWith("::"))) { + (returnType.toString().isEmpty() || + returnType.toString().endsWith("::"))) { // 'QString::operator const char *()' parentPath = returnType.toString().split(sep); parentPath.removeAll(QString()); @@ -1167,11 +1307,10 @@ bool CppCodeParser::matchFunctionDecl(InnerNode *parent, name = previousLexeme(); matchTemplateAngles(); - if (match(Tok_Gulbrandsen)) { + if (match(Tok_Gulbrandsen)) parentPath.append(name); - } else { + else break; - } } if (tok == Tok_operator) { @@ -1184,7 +1323,9 @@ bool CppCodeParser::matchFunctionDecl(InnerNode *parent, break; } } - if (parent && (tok == Tok_Semicolon || tok == Tok_LeftBracket || tok == Tok_Colon) + if (parent && (tok == Tok_Semicolon || + tok == Tok_LeftBracket || + tok == Tok_Colon) && access != Node::Private) { if (tok == Tok_LeftBracket) { returnType.appendHotspot(); @@ -1198,7 +1339,8 @@ bool CppCodeParser::matchFunctionDecl(InnerNode *parent, } if (tok != Tok_Semicolon) return false; - } else if (tok == Tok_Colon) { + } + else if (tok == Tok_Colon) { returnType.appendHotspot(); while (tok != Tok_Semicolon && tok != Tok_Eoi) { @@ -1390,7 +1532,7 @@ bool CppCodeParser::matchNamespaceDecl(InnerNode *parent) QString namespaceName = previousLexeme(); NamespaceNode *namespasse = 0; if (parent) - namespasse = static_cast<NamespaceNode *>(parent->findNode(namespaceName, Node::Namespace)); + namespasse = static_cast<NamespaceNode*>(parent->findNode(namespaceName, Node::Namespace)); if (!namespasse) { namespasse = new NamespaceNode(parent, namespaceName); namespasse->setAccess(access); @@ -1456,7 +1598,8 @@ bool CppCodeParser::matchEnumItem(InnerNode *parent, EnumNode *enume) if (strVal.isEmpty()) { if (enume->items().isEmpty()) { strVal = "0"; - } else { + } + else { QString last = enume->items().last().value(); bool ok; int n = last.toInt(&ok); @@ -1466,15 +1609,16 @@ bool CppCodeParser::matchEnumItem(InnerNode *parent, EnumNode *enume) strVal = last.left(2) + QString::number(n + 1, 16); else strVal = "0" + QString::number(n + 1, 8); - } else { - strVal = QString::number(n + 1); } + else + strVal = QString::number(n + 1); } } } enume->addItem(EnumItem(name, strVal)); - } else { + } + else { VariableNode *var = new VariableNode(parent, name); var->setAccess(access); var->setLocation(location()); @@ -1562,7 +1706,8 @@ bool CppCodeParser::matchProperty(InnerNode *parent) if (match(Tok_Ident)) { value = previousLexeme(); - } else if (match(Tok_LeftParen)) { + } + else if (match(Tok_LeftParen)) { int depth = 1; while (tok != Tok_Eoi) { if (tok == Tok_LeftParen) { @@ -1579,6 +1724,9 @@ bool CppCodeParser::matchProperty(InnerNode *parent) value = "?"; } + /* + Task 259071 requires work here. See gui/widgets/qdatetime.h, for example. + */ if (key == "READ") tre->addPropertyFunction(property, value, PropertyNode::Getter); else if (key == "WRITE") @@ -1753,12 +1901,6 @@ bool CppCodeParser::matchDocsAndStuff() readToken(); Doc::trimCStyleComment(start_loc,comment); - /* - qdoc --> doxygen - We must also remember the location of the end - of the comment, so we can construct a diff for - it. - */ Location end_loc(location()); /* @@ -1821,6 +1963,28 @@ bool CppCodeParser::matchDocsAndStuff() /* There is a topic command. Process it. */ +#ifdef QDOC_QML + if (topic == COMMAND_QMLPROPERTY) { + Doc nodeDoc = doc; + Node *node = processTopicCommandGroup(nodeDoc,topic,args); + if (node != 0) { + nodes.append(node); + docs.append(nodeDoc); + } + } + else { + QStringList::ConstIterator a = args.begin(); + while (a != args.end()) { + Doc nodeDoc = doc; + Node *node = processTopicCommand(nodeDoc,topic,*a); + if (node != 0) { + nodes.append(node); + docs.append(nodeDoc); + } + ++a; + } + } +#else QStringList::ConstIterator a = args.begin(); while (a != args.end()) { Doc nodeDoc = doc; @@ -1831,6 +1995,7 @@ bool CppCodeParser::matchDocsAndStuff() } ++a; } +#endif } NodeList::Iterator n = nodes.begin(); @@ -1838,7 +2003,8 @@ bool CppCodeParser::matchDocsAndStuff() while (n != nodes.end()) { processOtherMetaCommands(*d, *n); (*n)->setDoc(*d); - if ((*n)->isInnerNode() && ((InnerNode *)*n)->includes().isEmpty()) { + if ((*n)->isInnerNode() && + ((InnerNode *)*n)->includes().isEmpty()) { InnerNode *m = static_cast<InnerNode *>(*n); while (m->parent() != tre->root()) m = m->parent(); @@ -1926,7 +2092,8 @@ void CppCodeParser::parseQiteratorDotH(const Location &location, mutableSequentialIteratorDefinition = lines[1]; associativeIteratorDefinition = lines[2]; mutableAssociativeIteratorDefinition = lines[3]; - } else { + } + else { location.warning(tr("The qiterator.h hack failed")); } } @@ -2008,7 +2175,7 @@ void CppCodeParser::createExampleFileNodes(FakeNode *fake) foreach (const QString &exampleFile, exampleFiles) (void) new FakeNode(fake, exampleFile.mid(sizeOfBoringPartOfName), - FakeNode::File); + Node::File); } QT_END_NAMESPACE diff --git a/tools/qdoc3/cppcodeparser.h b/tools/qdoc3/cppcodeparser.h index 1f41318..cbb0149 100644 --- a/tools/qdoc3/cppcodeparser.h +++ b/tools/qdoc3/cppcodeparser.h @@ -90,6 +90,21 @@ class CppCodeParser : public CodeParser virtual Node *processTopicCommand(const Doc& doc, const QString& command, const QString& arg); +#ifdef QDOC_QML + // might need to implement this in QsCodeParser as well. + virtual Node *processTopicCommandGroup(const Doc& doc, + const QString& command, + const QStringList& args); + bool splitQmlPropertyArg(const Doc& doc, + const QString& arg, + QString& type, + QString& element, + QString& property); + bool splitQmlArg(const Doc& doc, + const QString& arg, + QString& element, + QString& name); +#endif virtual QSet<QString> otherMetaCommands(); virtual void processOtherMetaCommand(const Doc& doc, const QString& command, diff --git a/tools/qdoc3/doc.cpp b/tools/qdoc3/doc.cpp index f7007a0..e2f3525 100644 --- a/tools/qdoc3/doc.cpp +++ b/tools/qdoc3/doc.cpp @@ -73,20 +73,20 @@ struct Macro }; enum { - CMD_A, CMD_ABSTRACT, CMD_BADCODE, CMD_BASENAME, CMD_BOLD, - CMD_BRIEF, CMD_C, CMD_CAPTION, CMD_CHAPTER, CMD_CODE, - CMD_CODELINE, CMD_DOTS, CMD_ELSE, CMD_ENDABSTRACT, - CMD_ENDCHAPTER, CMD_ENDCODE, CMD_ENDFOOTNOTE, CMD_ENDIF, - CMD_ENDLEGALESE, CMD_ENDLINK, CMD_ENDLIST, CMD_ENDOMIT, - CMD_ENDPART, CMD_ENDQUOTATION, CMD_ENDRAW, CMD_ENDSECTION1, - CMD_ENDSECTION2, CMD_ENDSECTION3, CMD_ENDSECTION4, - CMD_ENDSIDEBAR, CMD_ENDTABLE, CMD_EXPIRE, CMD_FOOTNOTE, - CMD_GENERATELIST, CMD_GRANULARITY, CMD_HEADER, CMD_I, - CMD_IF, CMD_IMAGE, CMD_INCLUDE, CMD_INLINEIMAGE, CMD_INDEX, - CMD_KEYWORD, CMD_L, CMD_LEGALESE, CMD_LINK, CMD_LIST, - CMD_META, CMD_NEWCODE, CMD_O, CMD_OLDCODE, CMD_OMIT, - CMD_OMITVALUE, CMD_OVERLOAD, - CMD_PART, CMD_PRINTLINE, CMD_PRINTTO, + CMD_A, CMD_ABSTRACT, CMD_ANNOTATEDLIST, CMD_BADCODE, + CMD_BASENAME, CMD_BOLD, CMD_BRIEF, CMD_C, CMD_CAPTION, + CMD_CHAPTER, CMD_CODE, CMD_CODELINE, CMD_DOTS, CMD_ELSE, + CMD_ENDABSTRACT, CMD_ENDCHAPTER, CMD_ENDCODE, + CMD_ENDFOOTNOTE, CMD_ENDIF, CMD_ENDLEGALESE, CMD_ENDLINK, + CMD_ENDLIST, CMD_ENDOMIT, CMD_ENDPART, CMD_ENDQUOTATION, + CMD_ENDRAW, CMD_ENDSECTION1, CMD_ENDSECTION2, + CMD_ENDSECTION3, CMD_ENDSECTION4, CMD_ENDSIDEBAR, + CMD_ENDTABLE, CMD_EXPIRE, CMD_FOOTNOTE, CMD_GENERATELIST, + CMD_GRANULARITY, CMD_HEADER, CMD_I, CMD_IF, CMD_IMAGE, + CMD_INCLUDE, CMD_INLINEIMAGE, CMD_INDEX, CMD_KEYWORD, + CMD_L, CMD_LEGALESE, CMD_LINK, CMD_LIST, CMD_META, + CMD_NEWCODE, CMD_O, CMD_OLDCODE, CMD_OMIT, CMD_OMITVALUE, + CMD_OVERLOAD, CMD_PART, CMD_PRINTLINE, CMD_PRINTTO, CMD_PRINTUNTIL, CMD_QUOTATION, CMD_QUOTEFILE, CMD_QUOTEFROMFILE, CMD_QUOTEFUNCTION, CMD_RAW, CMD_ROW, CMD_SA, CMD_SECTION1, CMD_SECTION2, CMD_SECTION3, @@ -108,6 +108,7 @@ static struct { } cmds[] = { { "a", CMD_A, 0 }, { "abstract", CMD_ABSTRACT, 0 }, + { "annotatedlist", CMD_ANNOTATEDLIST, 0 }, { "badcode", CMD_BADCODE, 0 }, { "basename", CMD_BASENAME, 0 }, // ### don't document for now { "bold", CMD_BOLD, 0 }, @@ -515,14 +516,7 @@ void DocParser::parse(const QString& source, break; case CMD_BADCODE: leavePara(); -#ifdef QDOC2DOX - if (DoxWriter::isDoxPass()) - append(Atom::CodeBad,getUnmarkedCode(CMD_BADCODE)); - else - append(Atom::CodeBad,getCode(CMD_BADCODE, marker)); -#else append(Atom::CodeBad,getCode(CMD_BADCODE, marker)); -#endif break; case CMD_BASENAME: leavePara(); @@ -538,17 +532,8 @@ void DocParser::parse(const QString& source, case CMD_C: enterPara(); x = untabifyEtc(getArgument(true)); -#ifdef QDOC2DOX - if (DoxWriter::isDoxPass()) - append(Atom::C, x); - else { - marker = CodeMarker::markerForCode(x); - append(Atom::C, marker->markedUpCode(x, 0, "")); - } -#else marker = CodeMarker::markerForCode(x); append(Atom::C, marker->markedUpCode(x, 0, "")); -#endif break; case CMD_CAPTION: leavePara(); @@ -559,14 +544,7 @@ void DocParser::parse(const QString& source, break; case CMD_CODE: leavePara(); -#ifdef QDOC2DOX - if (DoxWriter::isDoxPass()) - append(Atom::Code, getUnmarkedCode(CMD_CODE)); - else - append(Atom::Code, getCode(CMD_CODE, marker)); -#else append(Atom::Code, getCode(CMD_CODE, marker)); -#endif break; #ifdef QDOC_QML case CMD_QML: @@ -579,17 +557,6 @@ void DocParser::parse(const QString& source, #endif case CMD_CODELINE: { -#ifdef QDOC2DOX - if (!quoting && !DoxWriter::isDoxPass()) { - if (priv->text.lastAtom()->type() == Atom::Code - && priv->text.lastAtom()->string().endsWith("\n\n")) - priv->text.lastAtom()->chopString(); - appendToCode("\n"); - } lse { - append(Atom::CodeQuoteCommand, cmdStr); - append(Atom::CodeQuoteArgument, " "); - } -#else if (!quoting) { if (priv->text.lastAtom()->type() == Atom::Code && priv->text.lastAtom()->string().endsWith("\n\n")) @@ -600,37 +567,10 @@ void DocParser::parse(const QString& source, append(Atom::CodeQuoteCommand, cmdStr); append(Atom::CodeQuoteArgument, " "); } -#endif } break; case CMD_DOTS: { -#ifdef QDOC2DOX - if (DoxWriter::isDoxPass()) { - append(Atom::CodeQuoteCommand, cmdStr); - append(Atom::CodeQuoteArgument, " ..."); - } - else if (!quoting) { - if (priv->text.lastAtom()->type() == Atom::Code - && priv->text.lastAtom()->string().endsWith("\n\n")) - priv->text.lastAtom()->chopString(); - - QString arg = getOptionalArgument(); - int indent = 4; - if (!arg.isEmpty()) - indent = arg.toInt(); - for (int i = 0; i < indent; ++i) - appendToCode(" "); - appendToCode("...\n"); - } - else { - append(Atom::CodeQuoteCommand, cmdStr); - QString arg = getOptionalArgument(); - if (arg.isEmpty()) - arg = "4"; - append(Atom::CodeQuoteArgument, arg); - } -#else if (!quoting) { if (priv->text.lastAtom()->type() == Atom::Code && priv->text.lastAtom()->string().endsWith("\n\n")) @@ -651,7 +591,6 @@ void DocParser::parse(const QString& source, arg = "4"; append(Atom::CodeQuoteArgument, arg); } -#endif } break; case CMD_ELSE: @@ -785,6 +724,9 @@ void DocParser::parse(const QString& source, paraState = OutsidePara; // ### } break; + case CMD_ANNOTATEDLIST: + append(Atom::AnnotatedList, getArgument()); + break; case CMD_GENERATELIST: append(Atom::GeneratedList, getArgument()); break; @@ -953,19 +895,8 @@ void DocParser::parse(const QString& source, break; case CMD_OLDCODE: leavePara(); -#ifdef QDOC2DOX - if (DoxWriter::isDoxPass()) { - append(Atom::CodeOld, getUnmarkedCode(CMD_OLDCODE)); - append(Atom::CodeNew, getUnmarkedCode(CMD_NEWCODE)); - } - else { - append(Atom::CodeOld, getCode(CMD_OLDCODE, marker)); - append(Atom::CodeNew, getCode(CMD_NEWCODE, marker)); - } -#else append(Atom::CodeOld, getCode(CMD_OLDCODE, marker)); append(Atom::CodeNew, getCode(CMD_NEWCODE, marker)); -#endif break; case CMD_OMIT: getUntilEnd(cmd); @@ -1147,18 +1078,6 @@ void DocParser::parse(const QString& source, { QString snippet = getArgument(); QString identifier = getRestOfLine(); -#ifdef QDOC2DOX - if (quoting || DoxWriter::isDoxPass()) { - append(Atom::SnippetCommand, cmdStr); - append(Atom::SnippetLocation, snippet); - append(Atom::SnippetIdentifier, identifier); - } - else { - Doc::quoteFromFile(location(),quoter,snippet); - appendToCode(quoter.quoteSnippet(location(), - identifier)); - } -#else if (quoting) { append(Atom::SnippetCommand, cmdStr); append(Atom::SnippetLocation, snippet); @@ -1169,7 +1088,6 @@ void DocParser::parse(const QString& source, appendToCode(quoter.quoteSnippet(location(), identifier)); } -#endif } break; case CMD_SUB: @@ -1251,7 +1169,7 @@ void DocParser::parse(const QString& source, append(Atom::FormattingRight, ATOM_FORMATTING_BOLD); append(Atom::String, " "); break; - case CMD_OVERLOAD: // qdoc --> doxygen + case CMD_OVERLOAD: priv->metacommandsUsed.insert(cmdStr); x.clear(); if (!isBlankLine()) @@ -1763,10 +1681,13 @@ void DocParser::startSection(Doc::SectioningUnit unit, int cmd) leavePara(); if (currentSectioningUnit == Doc::Book) { +#if 0 + // mws didn't think this was necessary. if (unit > Doc::Section1) location().warning(tr("Unexpected '\\%1' without '\\%2'") .arg(cmdName(cmd)) .arg(cmdName(CMD_SECTION1))); +#endif currentSectioningUnit = (Doc::SectioningUnit) (unit - 1); priv->constructExtra(); priv->extra->sectioningUnit = currentSectioningUnit; @@ -2343,7 +2264,7 @@ QString DocParser::getCode(int cmd, CodeMarker *marker) } /*! - Used only for generating doxygen output. + Was used only for generating doxygen output. */ QString DocParser::getUnmarkedCode(int cmd) { @@ -2579,36 +2500,6 @@ QString DocParser::slashed(const QString& str) #define COMMAND_QMLBRIEF Doc::alias("qmlbrief") #endif -#ifdef QDOC2DOX -#define DOXYGEN_INDENT 2 -#define DOXYGEN_TAB_SIZE 4 -#define DOXYGEN_INDENT_STRING " " -#define DOXYGEN_TAB_STRING " " - -static QRegExp ws_rx("\\s"); -static QRegExp not_ws_rx("\\S"); - -int DoxWriter::doxPass = 0; -QString DoxWriter::currentClass; -QSet<QString> DoxWriter::anchors; -QStringMap DoxWriter::exampleTitles; -QStringMap DoxWriter::headerFileTitles; -QStringMap DoxWriter::fileTitles; -QStringMap DoxWriter::groupTitles; -QStringMap DoxWriter::moduleTitles; -QStringMap DoxWriter::pageTitles; -QStringMap DoxWriter::externalPageTitles; -QStringMap DoxWriter::exampleTitlesInverse; -QStringMap DoxWriter::headerFileTitlesInverse; -QStringMap DoxWriter::fileTitlesInverse; -QStringMap DoxWriter::groupTitlesInverse; -QStringMap DoxWriter::moduleTitlesInverse; -QStringMap DoxWriter::pageTitlesInverse; -QStringMap DoxWriter::externalPageTitlesInverse; -QStringMultiMap DoxWriter::variables; -QStringMultiMap DoxWriter::properties; -QStringMultiMap DoxWriter::enums; -#endif Doc::Doc(const Location& start_loc, const Location& end_loc, @@ -2618,15 +2509,6 @@ Doc::Doc(const Location& start_loc, priv = new DocPrivate(start_loc,end_loc,source); DocParser parser; parser.parse(source,priv,metaCommandSet); -#ifdef QDOC2DOX - if (DoxWriter::isDoxPass()) { - DoxWriter doxWriter(source,priv); - if (DoxWriter::isDoxPass(1)) - doxWriter.pass1(); - else - doxWriter.pass2(); - } -#endif } Doc::Doc(const Doc& doc) @@ -3180,1855 +3062,4 @@ void Doc::detach() priv = newPriv; } -#ifdef QDOC2DOX -/*! - Sets the doxygen writer pass to \a pass. You can use - isDoxPass(), with or without a parameter, to test if - you are in a doxygen writer run or in a specific pass - of a doxygen writer run. - - This function is only called from main() if either the - \e doxygen1 or \e doxygen2 flag is passed to qdoc3 on - the command line. - */ -void DoxWriter::setDoxPass(int pass) -{ - qDebug() << "SETTING doxygen pass to " << pass - << " in DoxWriter::setDoxPass()"; - doxPass = pass; -} - -/*! - Returns true if the doxygen pass is set to \a pass, - which means we are in the specified \a pass of a doxygen - writer run of qdoc3. - */ -bool DoxWriter::isDoxPass(int pass) { return (doxPass == pass); } - -/*! - Returns true if the doxygen pass is 1 or 2, which - means this is a doxygen writer run to transform qdoc - comments into doxygen comments. - */ -bool DoxWriter::isDoxPass() { return (doxPass > 0); } - -bool DoxWriter::conversionRequired() const -{ - /* - Loop through all the topic commands searching for - one that must be transformed to doxygen format. If - one is found, return true. - */ - QCommandMap::const_iterator i; - i = priv->metaCommandMap.constBegin(); - while (i != priv->metaCommandMap.constEnd()) { - QString s = i.key(); - if (s == "enum") - return true; - else if (s == "example") - return true; - else if (s == "externalpage") - return true; - else if (s == "group") - return true; - else if (s == "headerfile") - return true; - else if (s == "module") - return true; - else if (s == "page") - return true; - else if (s == "property") - return true; - else if (s == "typedef") - return true; - else if (s == "variable") - return true; - else if (s == "overload") - return true; - else if (s == "reimp") - return true; - else if (s == "relates") - return true; - else if (s == "macro") - return true; - else { -#if 0 - if (s == "class") - else if (s == "namespace") - else if (s == "service") - else if (s == "inheaderfile") - else if (s == "file") - else if (s == "fn") - else if (s == "contentspage") - else if (s == "nextpage") - else if (s == "previous") - else if (s == "indexpage") - else if (s == "startpage") -#endif - } - ++i; - } - - /* - Loop through all the qdoc atoms searching for one - that must be transformed to doxygen format. If one - is found, return true. - */ - const Atom* next = priv->text.firstAtom(); - while (next != 0) { - Atom::Type atomType = next->type(); - switch (atomType) { - case Atom::C: - case Atom::CaptionLeft: - case Atom::Code: - case Atom::CodeBad: - case Atom::CodeNew: - case Atom::CodeOld: - case Atom::CodeQuoteArgument: - case Atom::CodeQuoteCommand: - case Atom::FootnoteLeft: - case Atom::FormatElse: - case Atom::FormatEndif: - case Atom::FormatIf: - case Atom::GeneratedList: - case Atom::Image: - case Atom::ImageText: - case Atom::InlineImage: - case Atom::LegaleseLeft: - case Atom::LineBreak: - case Atom::Link: - case Atom::LinkNode: - case Atom::ListLeft: - case Atom::ListItemNumber: - case Atom::ListTagLeft: - case Atom::ListItemLeft: - case Atom::QuotationLeft: - case Atom::RawString: - case Atom::SectionLeft: - case Atom::SectionHeadingLeft: - case Atom::SidebarLeft: - case Atom::SnippetCommand: - case Atom::SnippetIdentifier: - case Atom::SnippetLocation: - case Atom::TableLeft: - case Atom::TableHeaderLeft: - case Atom::TableRowLeft: - case Atom::TableItemLeft: - case Atom::TableOfContents: - case Atom::Target: - return true; - case Atom::AbstractLeft: - case Atom::AbstractRight: - case Atom::AutoLink: - case Atom::BaseName: - case Atom::BriefLeft: - case Atom::BriefRight: - case Atom::CaptionRight: - case Atom::FormattingLeft: - case Atom::FormattingRight: - case Atom::Nop: - case Atom::ParaLeft: - case Atom::ParaRight: - case Atom::FootnoteRight: - case Atom::LegaleseRight: - case Atom::ListTagRight: - case Atom::ListItemRight: - case Atom::ListRight: - case Atom::QuotationRight: - case Atom::SectionRight: - case Atom::SectionHeadingRight: - case Atom::SidebarRight: - case Atom::String: - case Atom::TableRight: - case Atom::TableHeaderRight: - case Atom::TableRowRight: - case Atom::TableItemRight: - default: - break; - } - next = next->next(); - } - return false; -} - -/*! - A convenience function to write a qdoc metacommand as a - doxygen command, without conversion. i.e., some of the - qdoc metacommands don't require conversion for doxygen. - */ -void DoxWriter::writeCommand(QCommandMap::const_iterator cmd) -{ - concatenate("\\" + cmd.key() + " " + cmd.value()[0]); - newLine(); -} - -/*! - Convert the qdoc commands in the metacommand map to - doxygen format. This function is called only in pass2(). - The metacommand map contains all the metacommands that - were found in the qdoc comment that is being converted. - The metacommands are the ones that begin with the '\'. - These are not considered part of the text of the comment. - The text is converted by convertText(). - */ -void DoxWriter::convertMetaCommands() -{ - QCommandMap& metaCmdMap = priv->metaCommandMap; - QCommandMap::iterator cmd; - int c; - - currentPage.clear(); - currentFn.clear(); - currentTitle.clear(); - currentEnum.clear(); - currentProperty.clear(); - currentVariable.clear(); - currentClass.clear(); - currentExample.clear(); - currentGroup.clear(); - currentModule.clear(); - currentMacro.clear(); - currentService.clear(); - currentTypedef.clear(); - currentHeaderFile.clear(); - commentType = OtherComment; - - if ((cmd = metaCmdMap.find("class")) != metaCmdMap.end()) { - currentClass = cmd.value()[0]; - if ((c = currentClass.indexOf(' ')) > 0) - currentClass = currentClass.left(c); - writeCommand(cmd); - metaCmdMap.erase(cmd); - commentType = ClassComment; - } - else if ((cmd = metaCmdMap.find("fn")) != metaCmdMap.end()) { - currentFn = cmd.value()[0]; - writeCommand(cmd); - metaCmdMap.erase(cmd); - commentType = FnComment; - } - else if ((cmd = metaCmdMap.find("enum")) != metaCmdMap.end()) { - currentEnum = cmd.value()[0]; - if ((c = currentEnum.lastIndexOf("::")) > 0) { - currentClass = currentEnum.left(c); - currentEnum = currentEnum.right(currentEnum.size()-c-2); - qDebug() << "currentEnum =" << currentEnum; - qDebug() << "currentClass =" << currentClass; - } - writeCommand(cmd); - metaCmdMap.erase(cmd); - commentType = EnumComment; - } - else if ((cmd = metaCmdMap.find("property")) != metaCmdMap.end()) { - currentClass = cmd.value()[0]; - if ((c = currentClass.lastIndexOf("::")) > 0) { - currentProperty = currentClass.right(currentClass.size()-c-2); - currentClass = currentClass.left(c); - qDebug() << "currentProperty =" << currentProperty; - qDebug() << "currentClass =" << currentClass; - } - writeCommand(cmd); - metaCmdMap.erase(cmd); - commentType = PropertyComment; - } - else if ((cmd = metaCmdMap.find("variable")) != metaCmdMap.end()) { - currentClass = cmd.value()[0]; - if ((c = currentClass.lastIndexOf("::")) > 0) { - currentVariable = currentClass.right(currentClass.size()-c-2); - currentClass = currentClass.left(c); - qDebug() << "currentVariable =" << currentVariable; - qDebug() << "currentClass =" << currentClass; - } - concatenate("\\var " + cmd.value()[0]); - newLine(); - metaCmdMap.erase(cmd); - commentType = VariableComment; - } - - if ((cmd = metaCmdMap.find("page")) != metaCmdMap.end()) { - currentPage = cmd.value()[0]; - QString htmlFile = currentPage; - const QString* title = getPageTitle(htmlFile); - QStringList parts = htmlFile.split('.'); - metaCmdMap.erase(cmd); - if (title) { - concatenate("\\page " + parts[0] + " " + *title); - newLine(); - } - commentType = PageComment; - qDebug() << "currentPage =" << currentPage; - } - - if ((cmd = metaCmdMap.find("example")) != metaCmdMap.end()) { - currentExample = cmd.value()[0]; - metaCmdMap.erase(cmd); - commentType = ExampleComment; - qDebug() << "currentExample =" << currentExample; - } - - if ((cmd = metaCmdMap.find("macro")) != metaCmdMap.end()) { - currentMacro = cmd.value()[0]; - metaCmdMap.erase(cmd); - commentType = MacroComment; - qDebug() << "currentMacro =" << currentMacro; - } - - if ((cmd = metaCmdMap.find("group")) != metaCmdMap.end()) { - currentGroup = cmd.value()[0]; - metaCmdMap.erase(cmd); - commentType = GroupComment; - qDebug() << "currentGroup =" << currentGroup; - } - - if ((cmd = metaCmdMap.find("module")) != metaCmdMap.end()) { - currentModule = cmd.value()[0]; - metaCmdMap.erase(cmd); - commentType = ModuleComment; - qDebug() << "currentModule =" << currentModule; - } - - if ((cmd = metaCmdMap.find("headerfile")) != metaCmdMap.end()) { - currentHeaderFile = cmd.value()[0]; - metaCmdMap.erase(cmd); - commentType = HeaderFileComment; - qDebug() << "currentHeaderFile =" << currentHeaderFile; - } - - if ((cmd = metaCmdMap.find("typedef")) != metaCmdMap.end()) { - currentClass = cmd.value()[0]; - if ((c = currentClass.lastIndexOf("::")) > 0) { - currentTypedef = currentClass.right(currentClass.size()-c-2); - currentClass = currentClass.left(c); - } - metaCmdMap.erase(cmd); - commentType = TypedefComment; - qDebug() << "currentTypedef =" << currentTypedef; - qDebug() << "currentClass =" << currentClass; - } - - cmd = priv->metaCommandMap.begin(); - while (cmd != priv->metaCommandMap.end()) { - for (int i=0; i<cmd.value().size(); i++) { - concatenate("\\" + cmd.key() + " " + cmd.value()[i]); - newLine(); - } - //qDebug() << " " << cmd.key() << ": " << cmd.value(); - ++cmd; - } -} - -/*! - Convert the qdoc text to doxygen format. The metacommands - are converted by convertMetaCommands(). This function is - called in pass2(). - */ -void DoxWriter::convertText() -{ - const Atom* prev = 0; - const Atom* next = priv->text.firstAtom(); - while (next != 0) { - next->dump(); - Atom::Type atomType = next->type(); - switch (atomType) { - case Atom::AbstractLeft: - break; - case Atom::AbstractRight: - break; - case Atom::AutoLink: - concatenate(next->string()); - break; - case Atom::BaseName: - break; - case Atom::BriefLeft: - concatenate("\\brief "); - break; - case Atom::BriefRight: - newLine(); - break; - case Atom::C: - tt(next); - break; - case Atom::CaptionLeft: - unhandled(next); - break; - case Atom::CaptionRight: - unhandled(next); - break; - case Atom::Code: - code(next); - break; - case Atom::CodeBad: - code(next); - break; - case Atom::CodeNew: - newLine(); - concatenate("you can rewrite it as"); - code(next); - break; - case Atom::CodeOld: - newLine(); - concatenate("For example, if you have code like"); - code(next); - break; - case Atom::CodeQuoteArgument: - unhandled(next); - break; - case Atom::CodeQuoteCommand: - next = codeQuoteCommand(next); - break; - case Atom::FootnoteLeft: - break; - case Atom::FootnoteRight: - break; - case Atom::FormatElse: - formatElse(); - break; - case Atom::FormatEndif: - formatEndif(); - break; - case Atom::FormatIf: - formatIf(next); - break; - case Atom::FormattingLeft: - formattingLeft(next,next->next()); - break; - case Atom::FormattingRight: - formattingRight(next,prev); - break; - case Atom::GeneratedList: - break; - case Atom::Image: - break; - case Atom::ImageText: - break; - case Atom::InlineImage: - break; - case Atom::LegaleseLeft: - break; - case Atom::LegaleseRight: - break; - case Atom::LineBreak: - break; - case Atom::Link: - next = link(next); - break; - case Atom::LinkNode: - break; - case Atom::ListLeft: - { - bool nested = false; - if (structs.isEmpty()) { - const Atom* i = next->next(); - while (i->type() != Atom::ListRight) { - if ((i->type() == Atom::ListLeft) || - (i->type() == Atom::TableLeft)) { - nested = true; - break; - } - i = i->next(); - } - } - else - nested = true; - StructDesc d(BulletList,nested); - if (next->string() == "numeric") - d.structType = NumericList; - else if (next->string() == "value") { - d.structType = ValueList; - } - else if (next->string() != "bullet") - qDebug() << "UNKNOWN LIST TYPE" << next->string(); - structs.push(d); - if (nested || (d.structType != BulletList)) { - if (d.structType == BulletList) - concatenate("<ul>"); - else if (d.structType == NumericList) - concatenate("<ol>"); - else if (d.structType == ValueList) - concatenate("<dl>"); - newLine(); - } - } - break; - case Atom::ListItemNumber: - structs.top().count = next->string().toInt(); - break; - case Atom::ListTagLeft: - { - structs.top().count++; - concatenate("<dt>"); - const Atom* n = next->next(); - if (n->type() == Atom::String) { - qDebug() << "ENUM VALUE" << n->string(); - } - else - qDebug() << "NOT EN ENUM"; - } - break; - case Atom::ListTagRight: - concatenate("</dt>"); - break; - case Atom::ListItemLeft: - { - newLine(); - const StructDesc& d = structs.top(); - if (d.structType == BulletList) { - if (!d.nested) - concatenate("\\arg "); - else - concatenate("<li>"); - } - else if (d.structType == NumericList) - concatenate("<li>"); - else if (d.structType == ValueList) - concatenate("<dd>"); - } - break; - case Atom::ListItemRight: - { - const StructDesc& d = structs.top(); - if (d.structType == BulletList) { - if (d.nested) { - concatenate("</li>"); - newLine(); - } - } - else if (d.structType == NumericList) { - concatenate("</li>"); - newLine(); - } - else if (d.structType == ValueList) { - concatenate("</dd>"); - newLine(); - } - } - break; - case Atom::ListRight: - { - if (!structs.isEmpty()) { - const StructDesc& d = structs.top(); - if (d.nested || (d.structType != BulletList)) { - if (d.structType == BulletList) - concatenate("</ul>"); - else if (d.structType == NumericList) - concatenate("</ol>"); - else if (d.structType == ValueList) - concatenate("</dl>"); - newLine(); - } - structs.pop(); - } - } - break; - case Atom::Nop: - // nothing. - break; - case Atom::ParaLeft: - if (structs.isEmpty()) - newLine(); - break; - case Atom::ParaRight: - { - if (structs.isEmpty()) - newLine(); - else { - const StructDesc& d = structs.top(); - if (d.nested || (d.structType != BulletList)) { - Atom::Type t = next->next()->type(); - if ((t != Atom::ListItemRight) && - (t != Atom::TableItemRight)) - newLine(); - } - else - newLine(); - } - } - break; - case Atom::QuotationLeft: - break; - case Atom::QuotationRight: - break; - case Atom::RawString: - concatenate(next->string()); - break; - case Atom::SectionLeft: - // nothing. - break; - case Atom::SectionRight: - // nothing. - break; - case Atom::SectionHeadingLeft: - next = sectionHeading(next); - break; - case Atom::SectionHeadingRight: - newLine(); - break; - case Atom::SidebarLeft: - break; - case Atom::SidebarRight: - break; - case Atom::SnippetCommand: - newLine(); - concatenate("\\snippet "); - break; - case Atom::SnippetIdentifier: - newText += next->string(); - lineLength += next->string().size(); - newLine(); - break; - case Atom::SnippetLocation: - newText += next->string() + " "; - lineLength += next->string().size() + 1; - break; - case Atom::String: - wrap(next->string()); - break; - case Atom::TableLeft: - { - bool nested = false; - if (structs.isEmpty()) { - const Atom* i = next->next(); - while (i->type() != Atom::TableRight) { - if ((i->type() == Atom::ListLeft) || - (i->type() == Atom::TableLeft)) { - nested = true; - break; - } - i = i->next(); - } - } - else - nested = true; - StructDesc d(Table,nested); - structs.push(d); - if (next->string().isEmpty()) - concatenate("<table>"); - else { - QString attrs = "width=\"" + next->string() + "\""; - attrs += " align=\"center\""; - concatenate("<table " + attrs + ">"); - } - newLine(); - } - break; - case Atom::TableRight: - concatenate("</table>"); - if (!structs.isEmpty()) - structs.pop(); - newLine(); - break; - case Atom::TableHeaderLeft: - concatenate("<tr>"); - if (!structs.isEmpty()) - structs.top().inTableHeader = true; - newLine(); - break; - case Atom::TableHeaderRight: - concatenate("</tr>"); - if (!structs.isEmpty()) - structs.top().inTableHeader = false; - newLine(); - break; - case Atom::TableRowLeft: - if (!structs.isEmpty()) { - structs.top().inTableRow = true; - concatenate("<tr valign=\"top\" class=\""); - if (structs.top().odd) - concatenate("odd\">"); - else - concatenate("even\">"); - structs.top().odd = !structs.top().odd; - } - newLine(); - break; - case Atom::TableRowRight: - concatenate("</tr>"); - if (!structs.isEmpty()) - structs.top().inTableRow = false; - newLine(); - break; - case Atom::TableItemLeft: - if (!structs.isEmpty()) { - structs.top().inTableItem = true; - concatenate("<td>"); - if (structs.top().inTableHeader) - concatenate("<b> "); - } - break; - case Atom::TableItemRight: - if (!structs.isEmpty()) { - structs.top().inTableItem = false; - if (structs.top().inTableHeader) - concatenate(" </b>"); - concatenate("</td>"); - } - newLine(); - break; - case Atom::TableOfContents: - break; - case Atom::Target: - { - QString text = next->string(); - text.remove(ws_rx); - newLine(); - concatenate("\\anchor "); - newText += text; - lineLength += text.size(); - newLine(); - } - break; - case Atom::UnhandledFormat: - unhandled(next); - break; - case Atom::UnknownCommand: - unhandled(next); - break; - default: - //next->dump(); - break; - } - prev = next; - next = next->next(); - } -} - -/*! - - Pass one looks for topic commands and target and section - commands, and maybe other stuff. These are serialized to - text files, which are read back in by pass2(). - */ -void DoxWriter::pass1() -{ - QCommandMap& metaCmdMap = priv->metaCommandMap; - if (!metaCmdMap.isEmpty()) { - int c; - QCommandMap::iterator cmd; - if ((cmd = metaCmdMap.find("enum")) != metaCmdMap.end()) { - commentType = EnumComment; - currentEnum = cmd.value()[0]; - if ((c = currentEnum.lastIndexOf("::")) > 0) { - currentClass = currentEnum.left(c); - currentEnum = currentEnum.right(currentEnum.size()-c-2); - qDebug() << "currentEnum =" << currentEnum; - qDebug() << "currentClass =" << currentClass; - if (enums.contains(currentEnum,currentClass)) { - qWarning() << "DoxWriter::pass1():" - << "Duplicate enum:" - << currentClass << currentEnum; - } - else - enums.insert(currentEnum,currentClass); - } - } - else if ((cmd = metaCmdMap.find("property")) != metaCmdMap.end()) { - commentType = PropertyComment; - currentClass = cmd.value()[0]; - if ((c = currentClass.lastIndexOf("::")) > 0) { - currentProperty = currentClass.right(currentClass.size()-c-2); - currentClass = currentClass.left(c); - qDebug() << "currentProperty =" << currentProperty; - qDebug() << "currentClass =" << currentClass; - if (properties.contains(currentProperty,currentClass)) { - qWarning() << "DoxWriter::pass1():" - << "Duplicate property:" - << currentClass << currentProperty; - } - else - properties.insert(currentProperty,currentClass); - } - } - else if ((cmd = metaCmdMap.find("variable")) != metaCmdMap.end()) { - commentType = VariableComment; - currentClass = cmd.value()[0]; - if ((c = currentClass.lastIndexOf("::")) > 0) { - currentVariable = currentClass.right(currentClass.size()-c-2); - currentClass = currentClass.left(c); - qDebug() << "currentVariable =" << currentVariable; - qDebug() << "currentClass =" << currentClass; - if (variables.contains(currentVariable,currentClass)) { - qWarning() << "DoxWriter::pass1():" - << "Duplicate variable:" - << currentClass << currentVariable; - } - else - variables.insert(currentVariable,currentClass); - } - } - } - - /* - */ - const Atom* next = priv->text.firstAtom(); - while (next != 0) { - switch (next->type()) { - case Atom::SectionHeadingLeft: - { - QString text; - next = next->next(); - while (next) { - if (next->type() == Atom::SectionHeadingRight) - break; - else - text += next->string(); - next = next->next(); - } - //text.remove(ws_rx); - insertAnchor(text); - } - break; - case Atom::Target: - { - QString text = next->string(); - //text.remove(ws_rx); - insertAnchor(text); - } - default: - break; - } - next = next->next(); - } -} - -/*! - Output a parsed, tokenized qdoc comment as a doxygen - comment in diff format for input to the patch command. - */ -void DoxWriter::pass2() -{ - if (!conversionRequired()) { - qDebug() << "NO CONVERSION - FILE:" << priv->start_loc.fileName() - << "START:" << priv->start_loc.lineNo() - << "END:" << priv->end_loc.lineNo() - 1; - return; - } - - /* - Transformation to doxygen required... - */ - newText = "\n/*! \n"; - convertMetaCommands(); - convertText(); - if (newText[newText.size()-1] == ' ') - newText.remove(newText.size()-1,1); - newText += " */\n"; - qDebug() << "CONVERTED COMMENT - FILE:" << priv->start_loc.fileName() - << "START:" << priv->start_loc.lineNo() - << "END:" << priv->end_loc.lineNo() - 1; - qDebug() << newText; -} - -/*! - Unparse the second parameter of a "\l" command. - */ -const Atom* DoxWriter::link(const Atom* atom) -{ - QString first_text = atom->string(); - QString second_text; - const QString* value = 0; - - const Atom* next = atom->next(Atom::FormattingLeft,Atom::LINK_); - if (next) { - next->dump(); - while (1) { - next = next->next(); - next->dump(); - if (next->type() == Atom::FormattingRight) { - if (next->string() == Atom::LINK_) - break; - else { - // ignore it. - } - } - else - second_text += next->string(); - } - int i = first_text.indexOf('#'); - if (i >= 0) - first_text = first_text.right(first_text.size() - i - 1); - //newLine(); - if ((value = getExternalPage(first_text))) { - //qDebug() << "USED AN EXTERNAL PAGE TITLE" << first_text; - QString href = "<a href=\""+*value+"\">"+first_text+"</a>"; - concatenate(href); - } - else if (first_text.startsWith("http:",Qt::CaseInsensitive)) { - if (first_text == second_text) { - concatenate(first_text); - } - else { - QString href = "<a href=\""+first_text+"\">"+second_text+"</a>"; - concatenate(href); - } - } - else if ((value = getPageFile(first_text))) { - //qDebug() << "USED A PAGE TITLE" << first_text; - QStringList parts = (*value).split('.'); - QString ref = "\\ref " + parts[0] + " \"" + second_text + "\""; - concatenate(ref); - } - else if ((value = getGroup(first_text))) { - //qDebug() << "USED A GROUP TITLE" << first_text; - concatenate("\\ref " + *value + " \"" + second_text + "\""); - } - else if ((value = getModule(first_text))) { - //qDebug() << "USED A MODULE TITLE" << first_text; - concatenate("\\ref " + *value + " \"" + second_text + "\""); - } - else if ((value = getExamplePath(first_text))) { - //qDebug() << "USED AN EXAMPLE TITLE" << first_text; - first_text.remove(ws_rx); - QString ref = "\\ref " + first_text + " \"" + second_text + "\""; - concatenate(ref); - } - else if ((value = getFile(first_text))) { - //qDebug() << "USED A FILE TITLE" << first_text; - // I think this command is no longer available. - first_text.remove(ws_rx); - QString ref = "\\ref " + first_text + " \"" + second_text + "\""; - concatenate(ref); - } - else if ((value = getHeaderFile(first_text))) { - //qDebug() << "USED A HEADER FILE TITLE" << first_text; - first_text.remove(ws_rx); - QString ref = "\\ref " + first_text + " \"" + second_text + "\""; - concatenate(ref); - } - else if (isAnchor(first_text)) { - //qDebug() << "USED AN ANCHOR" << first_text; - first_text.remove(ws_rx); - QString ref = "\\ref " + first_text + " \"" + second_text + "\""; - concatenate(ref); - } - else if ((value = getPageTitle(first_text))) { - //qDebug() << "USED AN INVERSE PAGE TITLE" << first_text; - QStringList parts = first_text.split('.'); - QString ref = "\\ref " + parts[0] + " \"" + second_text + "\""; - concatenate(ref); - } - else if ((value = getExampleTitle(first_text))) { - //qDebug() << "USED AN INVERSE EXAMPLE TITLE" << first_text; - QString title = *value; - title.remove(ws_rx); - QString ref = "\\ref " + title + " \"" + second_text + "\""; - concatenate(ref); - } - else if ((value = getGroupTitle(first_text))) { - //qDebug() << "USED AN INVERSE GROUP TITLE" << first_text; - concatenate("\\ref " + first_text + " \"" + second_text + "\""); - } - else if ((value = getModuleTitle(first_text))) { - //qDebug() << "USED AN INVERSE MODULE TITLE" << first_text; - concatenate("\\ref " + first_text + " \"" + second_text + "\""); - } - else if ((value = getFileTitle(first_text))) { - qDebug() << "USED AN INVERSE FILE TITLE" << first_text; - } - else if ((value = getHeaderFileTitle(first_text))) { - qDebug() << "USED AN INVERSE HEADER FILE TITLE" << first_text; - } - else if ((first_text.indexOf("::") >= 0) || - (first_text.indexOf("()") >= 0) || - (first_text[0] == 'Q')) { - //qDebug() << "AUTO-LINKABLE" << first_text; - if (first_text == second_text) - concatenate(first_text); - else { - QString link = first_text + " " + second_text; - concatenate("\\link " + link + "\\endlink"); - } - } - else { - QString link; - QStringList propertyClasses; - QStringList variableClasses; - QStringList enumClasses; - bool p = isProperty(first_text,propertyClasses); - bool v = isVariable(first_text,variableClasses); - bool e = isEnum(first_text,enumClasses); - if (e) { - if (enumClasses.size() == 1) - link = enumClasses[0]; - else if (enumClasses.contains(currentClass)) - link = currentClass; - else { - QString msg = "Unqualified enum name: " + first_text; - QString details = "Classes: " + enumClasses.join(", "); - priv->start_loc.error(msg,details); - } - if (!link.isEmpty()) - qDebug() << "FOUND ENUM" << link << first_text; - } - else if (p && v) { - if (propertyClasses.size() == 1) { - if (variableClasses.size() == 1) { - if (propertyClasses[0] == variableClasses[0]) - link = propertyClasses[0]; - } - } - if (link.isEmpty()) { - if (propertyClasses.contains(currentClass) || - variableClasses.contains(currentClass)) - link = currentClass; - else { - propertyClasses += variableClasses; - QString msg = "Unqualified property or variable name: " - + first_text; - QString details = "Classes: " + - propertyClasses.join(", "); - priv->start_loc.error(msg,details); - } - } - } - else if (p) { - if (propertyClasses.size() == 1) - link = propertyClasses[0]; - else if (propertyClasses.contains(currentClass)) - link = currentClass; - else { - QString msg = "Unqualified property name: " + first_text; - QString details = "Classes: " + propertyClasses.join(", "); - priv->start_loc.error(msg,details); - } - } - else if (v) { - if (variableClasses.size() == 1) - link = variableClasses[0]; - else if (variableClasses.contains(currentClass)) - link = currentClass; - else { - QString msg = "Unqualified variable name: " + first_text; - QString details = "Classes: " + variableClasses.join(", "); - priv->start_loc.error(msg,details); - } - } - else { - qDebug() << "NOT AUTO-LINKABLE" << first_text; - QString s = first_text + " " + second_text; - concatenate("\\link " + s + "\\endlink"); - } - if (!link.isEmpty()) { - link += "::" + first_text + " " + second_text; - concatenate("\\link " + link + "\\endlink"); - } - } - } - else - qDebug() << "LINK with no second parameter!!!!"; - return next? next : atom; -} - -/*! - If the current line length is 0, the current line is - indented according to the context. - */ -void DoxWriter::indentLine() -{ - if (lineLength == 0) { - newText += DOXYGEN_INDENT_STRING; - lineLength = DOXYGEN_INDENT; - if (!structs.isEmpty()) { - for (int i=1; i<structs.size(); ++i) { - newText += DOXYGEN_TAB_STRING; - lineLength += DOXYGEN_TAB_SIZE; - } - } - } -} - -/*! - Concatenates a newline to the doxygen text, increments the - line count, and resets the line length to 0. - */ -void DoxWriter::newLine() -{ - newText += "\n"; - ++lineCount; - lineLength = 0; -} - -static const int maxLineLength = 70; - -/*! - Concatenate the \a text to the doxygen comment currently - under construction and increment the current line length - by the size of the \a text. - - If incrementing the current line length by the \a text size - would make the current line length longer than the maximum - line length, then call newLine() and indentLine() \e before - concatenating the \a text. - */ -void DoxWriter::concatenate(QString text) -{ - if ((lineLength + text.size()) > maxLineLength) - newLine(); - indentLine(); - newText += text; - lineLength += text.size(); -} - -static bool punctuation(QChar c) -{ - switch (c.toAscii()) { - case '.': - case ',': - case ':': - case ';': - case '/': - case '+': - case '-': - case '?': - case '!': - case '\"': - return true; - default: - break; - } - return false; -} - -/*! - Concatenate the \a text string to the doxygen text, doing - line wrapping where necessary. - */ -void DoxWriter::wrap(QString text) -{ - int from = 0; - int to = -1; - - if ((lineLength == 0) || (lineLength >= maxLineLength)) { - if (!text.isEmpty() && (text[0] == ' ')) - text = text.right(text.size() - 1); - } - - indentLine(); - while (text.size()) { - int avail = maxLineLength - lineLength; - from = text.indexOf(' ',from); - if (from >= 0) { - if (from < avail) - to = from++; - else if (from == 1 && punctuation(text[0])) - to = from++; - else { - if (to >= 0) { - newText += text.left(to+1); - lineLength += to + 1; - text = text.right(text.size() - to - 1); - } - else { - newLine(); - indentLine(); - newText += text.left(from+1); - lineLength += from + 1; - text = text.right(text.size() - from - 1); - } - from = 0; - to = -1; - if (text.size() && (lineLength > maxLineLength)) { - newLine(); - indentLine(); - } - } - } - else - break; - } - if (text.size()) { - if (lineLength >= maxLineLength) { - newLine(); - indentLine(); - } - newText += text; - lineLength += text.size(); - } -} - -/*! - This will output something, but it depends on what the - \a atom string and the \a next atom string are. - */ -void DoxWriter::formattingLeft(const Atom* atom, const Atom* next) -{ - if (atom->string() == "parameter") { - concatenate("\\a "); - return; - } - else if (atom->string() == "underline") { - concatenate("<u>"); - return; - } - else if (atom->string() == "superscript") { - concatenate("<sup>"); - return; - } - else if (atom->string() == "subscript") { - concatenate("<sub>"); - return; - } - int ws = -1; - if (next) - ws = next->string().indexOf(ws_rx); - if (atom->string() == "bold") { - if (ws < 0) - concatenate("\\b "); - else - concatenate("<b>"); - } - else if (atom->string() == "italic") { - if (ws < 0) - concatenate("\\e "); - else - concatenate("<i>"); - } - else if (atom->string() == "teletype") { - if (ws < 0) - concatenate("\\c "); - else - concatenate("<tt>"); - } - else - qDebug() << "UNHANDLED FormattingLeft: " << atom->string(); -} - -/*! - This will output something, but it depends on what the - \a atom string and the \a prev atom string are. - */ -void DoxWriter::formattingRight(const Atom* atom, const Atom* prev) -{ - if (atom->string() == "parameter") - return; - else if (atom->string() == "underline") { - concatenate("</u>"); - return; - } - else if (atom->string() == "superscript") { - concatenate("</sup>"); - return; - } - else if (atom->string() == "subscript") { - concatenate("</sub>"); - return; - } - int ws = -1; - if (prev) - ws = prev->string().indexOf(ws_rx); - if (ws < 0) - return; - if (atom->string() == "bold") - concatenate("</b>"); - else if (atom->string() == "italic") - concatenate("</i>"); - else if (atom->string() == "teletype") - concatenate("</tt>"); - else - qDebug() << "UNHANDLED FormattingRight: " << atom->string(); -} - -/*! - Output a \c or a <tt>...</tt>. - */ -void DoxWriter::tt(const Atom* atom) -{ - if (atom->string().indexOf(ws_rx) < 0) { - concatenate("\\c "); - concatenate(atom->string()); - } - else { - concatenate("<tt>"); - concatenate(atom->string()); - concatenate("</tt>"); - } -} - -/*! - */ -void DoxWriter::formatIf(const Atom* atom) -{ - if (atom->string() == "HTML") { - newLine(); - concatenate("\\htmlonly"); - newLine(); - } -} - -/*! - */ -void DoxWriter::formatEndif() -{ - newLine(); - concatenate("\\endhtmlonly"); - newLine(); -} - -/*! - */ -void DoxWriter::formatElse() -{ - // nothing. -} - -/*! - Pass 1: Construct a section identifier and insert it into - the anchor set. - - Pass 2: Convert section1, section2, and section3 commands - to section, subsection, and subsubsection respectively. - Warn if a section command higher than 3 is seen. - */ -const Atom* DoxWriter::sectionHeading(const Atom* atom) -{ - QString heading_level = atom->string(); - QString heading_text; - const Atom* next = atom->next(); - while (next) { - next->dump(); - if (next->type() == Atom::SectionHeadingRight) { - if (next->string() == heading_level) - break; - else { - qDebug() << "WRONG SectionHeading number!!!!"; - } - } - else - heading_text += next->string(); - next = next->next(); - } - - QString heading_identifier = heading_text; - heading_identifier.remove(ws_rx); - - newLine(); - if (heading_level == "1") - heading_level = "\\section "; - else if (heading_level == "2") - heading_level = "\\subsection "; - else if (heading_level == "3") - heading_level = "\\subsubsection "; - else if (heading_level == "4") { - heading_level = "\\subsubsection "; - qDebug() << "WARNING section4 converted to \\subsubsection"; - } - else { - heading_level = "\\subsubsection "; - qDebug() << "WARNING section5 converted to \\subsubsection"; - } - concatenate(heading_level); - newText += heading_identifier + " "; - lineLength += heading_identifier.size() + 1; - newText += heading_text; - lineLength += heading_text.size(); - newLine(); - return next? next : atom; -} - -/*! - Report an unhandled atom. - */ -void DoxWriter::unhandled(const Atom* atom) -{ - qDebug() << "UNHANDLED ATOM"; - atom->dump(); -} - -/*! - Output a code/endcode block. - */ -void DoxWriter::code(const Atom* atom) -{ - newLine(); - concatenate("\\code"); - writeCode(atom->string()); - concatenate("\\endcode"); - newLine(); -} - -/*! - Output a code/endcode block depending on the - CodeQuote Command and CodeQuoteArgument parameters. - */ -const Atom* DoxWriter::codeQuoteCommand(const Atom* atom) -{ - QString command = atom->string(); - atom = atom->next(); - concatenate("\\code"); - if (command == "codeline") { - newLine(); - concatenate(atom->string()); - newLine(); - } - else if (command == "dots") { - newLine(); - concatenate(atom->string()); - newLine(); - } - else { - writeCode(atom->string()); - } - concatenate("\\endcode"); - return atom; -} - -/*! - Appends a block of code to the comment. - */ -void DoxWriter::writeCode(QString text) -{ - int cr_count = text.count('\n') - 1; - if (cr_count >= 0) { - int last_cr = text.lastIndexOf('\n'); - newText += text.left(last_cr); - lineCount += cr_count; - } - else - newText += text; - newLine(); -} - -/*! - Inserts \a text into the anchor set. This function is called - during doxygen pass 1. - */ -void DoxWriter::insertAnchor(const QString& text) -{ - anchors.insert(text); -} - -/*! - Returns true if \a text identifies an anchor, section, - subsection, subsubsection, or page. - */ -bool DoxWriter::isAnchor(const QString& text) -{ - return anchors.contains(text); -} - -/*! - Write the set of anchors to a file, one per line. - */ -void DoxWriter::writeAnchors() -{ - QFile file("anchors.txt"); - if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) { - qWarning("Unable to open anchors.txt for writing."); - return; - } - - QTextStream out(&file); - QSet<QString>::const_iterator i = anchors.constBegin(); - while (i != anchors.constEnd()) { - out << *i << "\n"; - ++i; - } - file.close(); -} - -/*! - Read the set of anchors from the anchors file, one per line, - and insert each one into the anchor set. - */ -void DoxWriter::readAnchors() -{ - QFile file("anchors.txt"); - if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) { - qWarning("Unable to open anchors.txt for reading."); - return; - } - - QTextStream in(&file); - while (!in.atEnd()) { - QString line = in.readLine(); - anchors.insert(line); - } - file.close(); -#if 0 - QSet<QString>::const_iterator i = anchors.constBegin(); - while (i != anchors.constEnd()) { - qDebug() << *i; - ++i; - } -#endif -} - -/*! - Inserts \a title into one of the title maps. \a title is - mapped to the \a node name. This function is called during - doxygen pass 1. - */ -void DoxWriter::insertTitle(FakeNode* node, const QString& title) -{ - switch (node->subType()) { - case FakeNode::Example: - if (exampleTitles.contains(title)) { - qWarning() << "DoxWriter::insertTitle():" - << "Duplicate example title:" - << title; - } - else { - exampleTitles[title] = node->name(); - exampleTitlesInverse[node->name()] = title; - } - break; - case FakeNode::HeaderFile: - if (headerFileTitles.contains(title)) { - qWarning() << "DoxWriter::insertTitle():" - << "Duplicate header file title:" - << title; - } - else { - headerFileTitles[title] = node->name(); - headerFileTitlesInverse[node->name()] = title; - } - break; - case FakeNode::File: - if (fileTitles.contains(title)) { - qWarning() << "DoxWriter::insertTitle():" - << "Duplicate file title:" - << title; - } - else { - fileTitles[title] = node->name(); - fileTitlesInverse[node->name()] = title; - } - break; - case FakeNode::Group: - if (groupTitles.contains(title)) { - qWarning() << "DoxWriter::insertTitle():" - << "Duplicate group title:" - << title; - } - else { - groupTitles[title] = node->name(); - groupTitlesInverse[node->name()] = title; - } - break; - case FakeNode::Module: - if (moduleTitles.contains(title)) { - qWarning() << "DoxWriter::insertTitle():" - << "Duplicate module title:" - << title; - } - else { - moduleTitles[title] = node->name(); - moduleTitlesInverse[node->name()] = title; - } - break; - case FakeNode::Page: - if (pageTitles.contains(title)) { - qWarning() << "DoxWriter::insertTitle():" - << "Duplicate page title:" - << title; - } - else { - pageTitles[title] = node->name(); - pageTitlesInverse[node->name()] = title; - } - break; - case FakeNode::ExternalPage: - if (externalPageTitles.contains(title)) { - qWarning() << "DoxWriter::insertTitle():" - << "Duplicate external page title:" - << title; - } - else { - externalPageTitles[title] = node->name(); - externalPageTitlesInverse[node->name()] = title; - } - break; - default: - break; - } -} - -/*! - */ -const QString* DoxWriter::getPageFile(const QString& title) -{ - QStringMapEntry entry = pageTitles.find(title); - return (entry == pageTitles.end()) ? 0 : &entry.value(); -} - -/*! - */ -const QString* DoxWriter::getExamplePath(const QString& title) -{ - QStringMapEntry entry = exampleTitles.find(title); - return (entry == exampleTitles.end()) ? 0 : &entry.value(); -} - -/*! - */ -const QString* DoxWriter::getFile(const QString& title) -{ - QStringMapEntry entry = fileTitles.find(title); - return (entry == fileTitles.end()) ? 0 : &entry.value(); -} - -/*! - */ -const QString* DoxWriter::getHeaderFile(const QString& title) -{ - QStringMapEntry entry = headerFileTitles.find(title); - return (entry == headerFileTitles.end()) ? 0 : &entry.value(); -} - -/*! - */ -const QString* DoxWriter::getGroup(const QString& title) -{ - QStringMapEntry entry = groupTitles.find(title); - return (entry == groupTitles.end()) ? 0 : &entry.value(); -} - -/*! - */ -const QString* DoxWriter::getModule(const QString& title) -{ - QStringMapEntry entry = moduleTitles.find(title); - return (entry == moduleTitles.end()) ? 0 : &entry.value(); -} - -/*! - */ -const QString* DoxWriter::getExternalPage(const QString& title) -{ - QStringMapEntry entry = externalPageTitles.find(title); - return (entry == externalPageTitles.end()) ? 0 : &entry.value(); -} - -/*! - */ -const QString* DoxWriter::getPageTitle(const QString& text) -{ - QStringMapEntry entry = pageTitlesInverse.find(text); - return (entry == pageTitlesInverse.end()) ? 0 : &entry.value(); -} - -/*! - */ -const QString* DoxWriter::getExampleTitle(const QString& text) -{ - QStringMapEntry entry = exampleTitlesInverse.find(text); - return (entry == exampleTitlesInverse.end()) ? 0 : &entry.value(); -} - -/*! - */ -const QString* DoxWriter::getFileTitle(const QString& text) -{ - QStringMapEntry entry = fileTitlesInverse.find(text); - return (entry == fileTitlesInverse.end()) ? 0 : &entry.value(); -} - -/*! - */ -const QString* DoxWriter::getHeaderFileTitle(const QString& text) -{ - QStringMapEntry entry = headerFileTitlesInverse.find(text); - return (entry == headerFileTitlesInverse.end()) ? 0 : &entry.value(); -} - -/*! - */ -const QString* DoxWriter::getGroupTitle(const QString& text) -{ - QStringMapEntry entry = groupTitlesInverse.find(text); - return (entry == groupTitlesInverse.end()) ? 0 : &entry.value(); -} - -/*! - */ -const QString* DoxWriter::getModuleTitle(const QString& text) -{ - QStringMapEntry entry = moduleTitlesInverse.find(text); - return (entry == moduleTitlesInverse.end()) ? 0 : &entry.value(); -} - -/*! - */ -const QString* DoxWriter::getExternalPageTitle(const QString& text) -{ - QStringMapEntry entry = externalPageTitlesInverse.find(text); - return (entry == externalPageTitlesInverse.end()) ? 0 : &entry.value(); -} - -/*! - Serialize \a map to file \a name. - */ -void DoxWriter::writeMap(const QStringMap& map, const QString& name) -{ - - QFile file(name); - if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) { - qWarning() << "Unable to open" << name << "for writing."; - return; - } - - QTextStream out(&file); - QStringMap::const_iterator i = map.constBegin(); - while (i != map.constEnd()) { - out << i.key() << "\n"; - out << i.value() << "\n"; - ++i; - } - file.close(); -} - -/*! - Read file \a name into the \a map. - */ -void DoxWriter::readMap(QStringMap& map, QStringMap& inverseMap, const QString& name) -{ - QFile file(name); - if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) { - qWarning() << "Unable to open" << name << "for reading."; - return; - } - - QTextStream in(&file); - while (!in.atEnd()) { - QString title = in.readLine(); - QString value = in.readLine(); - map[title] = value; - inverseMap[value] = title; - } - file.close(); -} - -/*! - Write the sets of titles to text files, one per line. - */ -void DoxWriter::writeTitles() -{ - if (!pageTitles.isEmpty()) - writeMap(pageTitles,"pagetitles.txt"); - if (!fileTitles.isEmpty()) - writeMap(fileTitles,"filetitles.txt"); - if (!headerFileTitles.isEmpty()) - writeMap(headerFileTitles,"headerfiletitles.txt"); - if (!exampleTitles.isEmpty()) - writeMap(exampleTitles,"exampletitles.txt"); - if (!moduleTitles.isEmpty()) - writeMap(moduleTitles,"moduletitles.txt"); - if (!groupTitles.isEmpty()) - writeMap(groupTitles,"grouptitles.txt"); - if (!externalPageTitles.isEmpty()) - writeMap(externalPageTitles,"externalpagetitles.txt"); -} - -/*! - Read the sets of titles from the titles files, one per line, - and insert each one into the appropriate title set. - */ -void DoxWriter::readTitles() -{ - readMap(pageTitles,pageTitlesInverse,"pagetitles.txt"); - readMap(fileTitles,fileTitlesInverse,"filetitles.txt"); - readMap(headerFileTitles,headerFileTitlesInverse,"headerfiletitles.txt"); - readMap(exampleTitles,exampleTitlesInverse,"exampletitles.txt"); - readMap(moduleTitles,moduleTitlesInverse,"moduletitles.txt"); - readMap(groupTitles,groupTitlesInverse,"grouptitles.txt"); - readMap(externalPageTitles, - externalPageTitlesInverse, - "externalpagetitles.txt"); -} - -/*! - Serialize \a map to file \a name. - */ -void DoxWriter::writeMultiMap(const QStringMultiMap& map, const QString& name) -{ - - QFile file(name); - if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) { - qWarning() << "Unable to open" << name << "for writing."; - return; - } - - QTextStream out(&file); - QStringMultiMap::const_iterator i = map.constBegin(); - while (i != map.constEnd()) { - out << i.key() << "\n"; - out << i.value() << "\n"; - ++i; - } - file.close(); -} - -/*! - Write the4 property names and variable names to text files. - */ -void DoxWriter::writeMembers() -{ - if (!variables.isEmpty()) - writeMultiMap(variables,"variables.txt"); - if (!properties.isEmpty()) - writeMultiMap(properties,"properties.txt"); - if (!enums.isEmpty()) - writeMultiMap(enums,"enums.txt"); -} - -/*! - Read file \a name into the \a map. - */ -void DoxWriter::readMultiMap(QStringMultiMap& map, const QString& name) -{ - QFile file(name); - if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) { - qWarning() << "Unable to open" << name << "for reading."; - return; - } - - QTextStream in(&file); - while (!in.atEnd()) { - QString member = in.readLine(); - QString className = in.readLine(); - map.insert(member,className); - } - file.close(); -} - -/*! - Read the property names and variable names from the test files. - */ -void DoxWriter::readMembers() -{ - readMultiMap(variables,"variables.txt"); - readMultiMap(properties,"properties.txt"); - readMultiMap(enums,"enums.txt"); -} - -/*! - Return true if \a name is a property. Loads \a classes with - the names of all the classes in which \a name is a property. - */ -bool DoxWriter::isProperty(const QString& name, QStringList& classes) -{ - classes = properties.values(name); - return !classes.isEmpty(); -} - -/*! - Return true if \a name is a variable. Loads \a classes with - the names of all the classes in which \a name is a variable. - */ -bool DoxWriter::isVariable(const QString& name, QStringList& classes) -{ - classes = variables.values(name); - return !classes.isEmpty(); -} - -/*! - Return true if \a name is an enum type. Loads \a classes with - the names of all the classes in which \a name is an enum type. - */ -bool DoxWriter::isEnum(const QString& name, QStringList& classes) -{ - classes = enums.values(name); - return !classes.isEmpty(); -} -#endif - QT_END_NAMESPACE diff --git a/tools/qdoc3/doc.h b/tools/qdoc3/doc.h index dbba6e4..d58167f 100644 --- a/tools/qdoc3/doc.h +++ b/tools/qdoc3/doc.h @@ -133,183 +133,6 @@ class Doc DocPrivate *priv; }; -#ifdef QDOC2DOX - -class DoxWriter -{ - public: - DoxWriter(const QString& source, DocPrivate* docPrivate) - : commentType(OtherComment), - lineLength(0), - lineCount(0), - priv(docPrivate), - oldText(source) {} - ~DoxWriter() {} - - void pass1(); - void pass2(); - - static void setDoxPass(int pass); - static bool isDoxPass(int pass); - static bool isDoxPass(); - static void insertTitle(FakeNode* node, const QString& title); - static void writeTitles(); - static void readTitles(); - static void writeMembers(); - static void readMembers(); - static void writeAnchors(); - static void readAnchors(); - - private: - void indentLine(); - void newLine(); - void concatenate(QString text); - void wrap(QString text); - bool conversionRequired() const; - void convertMetaCommands(); - void convertText(); - const Atom* link(const Atom* atom); - void formattingLeft(const Atom* atom, const Atom* next); - void formattingRight(const Atom* atom, const Atom* prev); - void tt(const Atom* atom); - void formatIf(const Atom* atom); - void formatEndif(); - void formatElse(); - const Atom* sectionHeading(const Atom* atom); - void unhandled(const Atom* atom); - void code(const Atom* atom); - const Atom* codeQuoteCommand(const Atom* atom); - void writeCode(QString text); - void writeCommand(QCommandMap::const_iterator cmd); - - static void insertAnchor(const QString& text); - static bool isAnchor(const QString& text); - - static const QString* getPageFile(const QString& title); - static const QString* getFile(const QString& title); - static const QString* getExamplePath(const QString& title); - static const QString* getHeaderFile(const QString& title); - static const QString* getGroup(const QString& title); - static const QString* getModule(const QString& title); - static const QString* getExternalPage(const QString& title); - static const QString* getPageTitle(const QString& text); - static const QString* getFileTitle(const QString& text); - static const QString* getExampleTitle(const QString& text); - static const QString* getHeaderFileTitle(const QString& text); - static const QString* getGroupTitle(const QString& text); - static const QString* getModuleTitle(const QString& text); - static const QString* getExternalPageTitle(const QString& text); - - static bool isProperty(const QString& title, QStringList& classes); - static bool isVariable(const QString& title, QStringList& classes); - static bool isEnum(const QString& title, QStringList& classes); - - private: - static void writeMap(const QStringMap& map, const QString& name); - static void readMap(QStringMap& map, - QStringMap& inverseMap, - const QString& name); - static void writeMultiMap(const QStringMultiMap& map, const QString& name); - static void readMultiMap(QStringMultiMap& map, const QString& name); - - public: // VS 6, SunCC need this to be public - enum StructType { BulletList, NumericList, ValueList, Table }; - private: - struct StructDesc { - StructType structType; - int count; - bool nested; - bool inTableHeader; - bool inTableRow; - bool inTableItem; - bool odd; - - StructDesc() - : structType(BulletList), - count(0), - nested(false), - inTableHeader(false), - inTableRow(false), - inTableItem(false), - odd(true) { } - - StructDesc(StructType t, bool n) - : structType(t), - count(0), - nested(n), - inTableHeader(false), - inTableRow(false), - inTableItem(false), - odd(true) { } - }; - - typedef QStack<StructDesc> StructStack; - - enum CommentType { - ClassComment, - EnumComment, - ExampleComment, - FnComment, - GroupComment, - HeaderFileComment, - MacroComment, - ModuleComment, - PageComment, - PropertyComment, - ServiceComment, - TypedefComment, - VariableComment, - OtherComment - }; - - private: - CommentType commentType; - int lineLength; - int lineCount; - DocPrivate* priv; - QString oldText; - QString newText; - StructStack structs; - - QString currentPage; - QString currentFn; - QString currentTitle; - QString currentEnum; - QString currentProperty; - QString currentVariable; - QString currentExample; - QString currentGroup; - QString currentModule; - QString currentMacro; - QString currentService; - QString currentTypedef; - QString currentHeaderFile; - static QString currentClass; - - static int doxPass; - static QSet<QString> anchors; - static QStringMap exampleTitles; - static QStringMap headerFileTitles; - static QStringMap fileTitles; - static QStringMap groupTitles; - static QStringMap moduleTitles; - static QStringMap pageTitles; - static QStringMap externalPageTitles; - static QStringMap exampleTitlesInverse; - static QStringMap headerFileTitlesInverse; - static QStringMap fileTitlesInverse; - static QStringMap groupTitlesInverse; - static QStringMap moduleTitlesInverse; - static QStringMap pageTitlesInverse; - static QStringMap externalPageTitlesInverse; - - static QStringMultiMap variables; - static QStringMultiMap properties; - static QStringMultiMap enums; -}; - -#endif - QT_END_NAMESPACE #endif diff --git a/tools/qdoc3/generator.cpp b/tools/qdoc3/generator.cpp index 3652071..e92f53b 100644 --- a/tools/qdoc3/generator.cpp +++ b/tools/qdoc3/generator.cpp @@ -42,9 +42,9 @@ /* generator.cpp */ - +#include <QtCore> #include <qdir.h> - +#include <qdebug.h> #include "codemarker.h" #include "config.h" #include "doc.h" @@ -68,14 +68,20 @@ QStringList Generator::imageDirs; QString Generator::outDir; QString Generator::project; -static Text stockLink(const QString &target) +static void singularPlural(Text& text, const NodeList& nodes) { - return Text() << Atom(Atom::Link, target) << Atom(Atom::FormattingLeft, ATOM_FORMATTING_LINK) - << target << Atom(Atom::FormattingRight, ATOM_FORMATTING_LINK); + if (nodes.count() == 1) + text << " is"; + else + text << " are"; } Generator::Generator() - : amp("&"), lt("<"), gt(">"), quot("""), tag("</?@[^>]*>") + : amp("&"), + lt("<"), + gt(">"), + quot("""), + tag("</?@[^>]*>") { generators.prepend(this); } @@ -123,7 +129,8 @@ void Generator::initialize(const Config &config) QSet<QString> formats = config.subVars(imagesDotFileExtensions); QSet<QString>::ConstIterator f = formats.begin(); while (f != formats.end()) { - imgFileExts[*f] = config.getStringList(imagesDotFileExtensions + Config::dot + *f); + imgFileExts[*f] = config.getStringList(imagesDotFileExtensions + + Config::dot + *f); ++f; } @@ -131,16 +138,22 @@ void Generator::initialize(const Config &config) while (g != generators.end()) { if (outputFormats.contains((*g)->format())) { (*g)->initializeGenerator(config); - QStringList extraImages = config.getStringList(CONFIG_EXTRAIMAGES + Config::dot - + (*g)->format()); + QStringList extraImages = config.getStringList(CONFIG_EXTRAIMAGES + + Config::dot + + (*g)->format()); QStringList::ConstIterator e = extraImages.begin(); while (e != extraImages.end()) { QString userFriendlyFilePath; - QString filePath = Config::findFile(config.lastLocation(), imageFiles, imageDirs, *e, - imgFileExts[(*g)->format()], userFriendlyFilePath); + QString filePath = Config::findFile(config.lastLocation(), + imageFiles, imageDirs, *e, + imgFileExts[(*g)->format()], + userFriendlyFilePath); if (!filePath.isEmpty()) - Config::copyFile(config.lastLocation(), filePath, userFriendlyFilePath, - (*g)->outputDir() + "/images"); + Config::copyFile(config.lastLocation(), + filePath, + userFriendlyFilePath, + (*g)->outputDir() + + "/images"); ++e; } } @@ -156,20 +169,23 @@ void Generator::initialize(const Config &config) QSet<QString> formats = config.subVars(formattingDotName); QSet<QString>::ConstIterator f = formats.begin(); while (f != formats.end()) { - QString def = config.getString(formattingDotName + Config::dot + - *f); + QString def = config.getString(formattingDotName + + Config::dot + *f); if (!def.isEmpty()) { int numParams = Config::numParams(def); int numOccs = def.count("\1"); if (numParams != 1) { - config.lastLocation().warning(tr("Formatting '%1' must have exactly one" - " parameter (found %2)") - .arg(*n).arg(numParams)); + config.lastLocation().warning(tr("Formatting '%1' must " + "have exactly one " + "parameter (found %2)") + .arg(*n).arg(numParams)); } else if (numOccs > 1) { - config.lastLocation().fatal(tr("Formatting '%1' must contain exactly one" - " occurrence of '\\1' (found %2)") + config.lastLocation().fatal(tr("Formatting '%1' must " + "contain exactly one " + "occurrence of '\\1' " + "(found %2)") .arg(*n).arg(numOccs)); } else { @@ -241,7 +257,7 @@ void Generator::generateFakeNode(const FakeNode * /* fake */, { } -void Generator::generateText(const Text& text, +bool Generator::generateText(const Text& text, const Node *relative, CodeMarker *marker) { @@ -254,31 +270,40 @@ void Generator::generateText(const Text& text, true, numAtoms); endText(relative, marker); + return true; } + return false; } #ifdef QDOC_QML -void Generator::generateQmlText(const Text& text, +/*! + Extract sections of markup text surrounded by \e qmltext + and \e endqmltext and output them. + */ +bool Generator::generateQmlText(const Text& text, const Node *relative, - CodeMarker *marker) + CodeMarker *marker, + const QString& qmlName) { - if (text.firstAtom() != 0) { - startText(relative, marker); - const Atom *atom = text.firstAtom(); - while (atom) { - if (atom->type() != Atom::QmlText) - atom = atom->next(); - else { - atom = atom->next(); - while (atom && (atom->type() != Atom::EndQmlText)) { - int n = 1 + generateAtom(atom, relative, marker); - while (n-- > 0) - atom = atom->next(); - } + const Atom* atom = text.firstAtom(); + if (atom == 0) + return false; + + startText(relative, marker); + while (atom) { + if (atom->type() != Atom::QmlText) + atom = atom->next(); + else { + atom = atom->next(); + while (atom && (atom->type() != Atom::EndQmlText)) { + int n = 1 + generateAtom(atom, relative, marker); + while (n-- > 0) + atom = atom->next(); } } - endText(relative, marker); } + endText(relative, marker); + return true; } #endif @@ -295,19 +320,27 @@ void Generator::generateBody(const Node *node, CodeMarker *marker) } else if (node->type() == Node::Fake) { const FakeNode *fake = static_cast<const FakeNode *>(node); - if (fake->subType() == FakeNode::Example) + if (fake->subType() == Node::Example) generateExampleFiles(fake, marker); - else if (fake->subType() == FakeNode::File) + else if (fake->subType() == Node::File) quiet = true; } if (node->doc().isEmpty()) { - if (!quiet) // ### might be unnecessary + if (!quiet && !node->isReimp()) // ### might be unnecessary node->location().warning(tr("No documentation for '%1'") .arg(marker->plainFullName(node))); } else { - generateText(node->doc().body(), node, marker); + if (node->type() == Node::Function) { + const FunctionNode *func = static_cast<const FunctionNode *>(node); + if (func->reimplementedFrom() != 0) + generateReimplementedFrom(func, marker); + } + + if (!generateText(node->doc().body(), node, marker)) + if (node->isReimp()) + return; if (node->type() == Node::Enum) { const EnumNode *enume = (const EnumNode *) node; @@ -345,7 +378,6 @@ void Generator::generateBody(const Node *node, CodeMarker *marker) } else if (node->type() == Node::Function) { const FunctionNode *func = static_cast<const FunctionNode *>(node); - QSet<QString> definedParams; QList<Parameter>::ConstIterator p = func->parameters().begin(); while (p != func->parameters().end()) { @@ -382,7 +414,8 @@ void Generator::generateBody(const Node *node, CodeMarker *marker) FunctionNode *primaryFunc = func->parent()->findFunctionNode(func->name()); if (primaryFunc) { - foreach (const Parameter ¶m, primaryFunc->parameters()) { + foreach (const Parameter ¶m, + primaryFunc->parameters()) { if (param.name() == *a) { needWarning = false; break; @@ -390,9 +423,10 @@ void Generator::generateBody(const Node *node, CodeMarker *marker) } } } - if (needWarning) + if (needWarning && !func->isReimp()) node->doc().location().warning( - tr("Undocumented parameter '%1' in %2").arg(*a).arg(marker->plainFullName(node))); + tr("Undocumented parameter '%1' in %2") + .arg(*a).arg(marker->plainFullName(node))); } ++a; } @@ -404,15 +438,17 @@ void Generator::generateBody(const Node *node, CodeMarker *marker) if (!body.contains("return", Qt::CaseInsensitive)) node->doc().location().warning(tr("Undocumented return value")); } - +#if 0 + // Now we put this at the top, before the other text. if (func->reimplementedFrom() != 0) generateReimplementedFrom(func, marker); +#endif } } if (node->type() == Node::Fake) { const FakeNode *fake = static_cast<const FakeNode *>(node); - if (fake->subType() == FakeNode::File) { + if (fake->subType() == Node::File) { Text text; Quoter quoter; Doc::quoteFromFile(fake->doc().location(), quoter, fake->name()); @@ -459,7 +495,8 @@ void Generator::generateInherits(const ClassNode *classe, CodeMarker *marker) if ((*r).access == Node::Protected) { text << " (protected)"; - } else if ((*r).access == Node::Private) { + } + else if ((*r).access == Node::Private) { text << " (private)"; } text << separator(index++, classe->baseClasses().count()); @@ -470,6 +507,15 @@ void Generator::generateInherits(const ClassNode *classe, CodeMarker *marker) } } +#ifdef QDOC_QML +/*! + */ +void Generator::generateQmlInherits(const QmlClassNode* , CodeMarker* ) +{ + // stub. +} +#endif + void Generator::generateInheritedBy(const ClassNode *classe, CodeMarker *marker) { @@ -497,18 +543,21 @@ void Generator::generateExampleFiles(const FakeNode *fake, CodeMarker *marker) QString exampleFile = child->name(); openedList.next(); text << Atom(Atom::ListItemNumber, openedList.numberString()) - << Atom(Atom::ListItemLeft, openedList.styleString()) << Atom::ParaLeft + << Atom(Atom::ListItemLeft, openedList.styleString()) + << Atom::ParaLeft << Atom(Atom::Link, exampleFile) << Atom(Atom::FormattingLeft, ATOM_FORMATTING_LINK) << exampleFile << Atom(Atom::FormattingRight, ATOM_FORMATTING_LINK) - << Atom::ParaRight << Atom(Atom::ListItemRight, openedList.styleString()); + << Atom::ParaRight + << Atom(Atom::ListItemRight, openedList.styleString()); } text << Atom(Atom::ListRight, openedList.styleString()); generateText(text, fake, marker); } -void Generator::generateModuleWarning(const ClassNode *classe, CodeMarker *marker) +void Generator::generateModuleWarning(const ClassNode *classe, + CodeMarker *marker) { QString module = classe->moduleName(); if (!module.isEmpty()) { @@ -529,8 +578,10 @@ void Generator::generateModuleWarning(const ClassNode *classe, CodeMarker *marke << Atom(Atom::FormattingRight, ATOM_FORMATTING_BOLD) << Atom::ParaRight; } - else if (module == "Qt3Support" && Tokenizer::isTrue("defined(opensourceedition)")) { - text << Atom::ParaLeft << Atom(Atom::FormattingLeft, ATOM_FORMATTING_BOLD) + else if (module == "Qt3Support" && + Tokenizer::isTrue("defined(opensourceedition)")) { + text << Atom::ParaLeft + << Atom(Atom::FormattingLeft, ATOM_FORMATTING_BOLD) << "Note to Qt Desktop Light Edition users:" << Atom(Atom::FormattingRight, ATOM_FORMATTING_BOLD) << " This class is only available in the " @@ -558,10 +609,12 @@ QString Generator::indent(int level, const QString& markedCode) if (markedCode.at(i - 1) == QLatin1Char('>')) break; } - } else { + } + else { if (markedCode.at(i) == QLatin1Char('\n')) { column = 0; - } else { + } + else { if (column == 0) { for (int j = 0; j < level; j++) t += QLatin1Char(' '); @@ -630,7 +683,7 @@ void Generator::setImageFileExtensions(const QStringList& extensions) void Generator::unknownAtom(const Atom *atom) { Location::internalError(tr("unknown atom type '%1' in %2 generator") - .arg(atom->typeString()).arg(format())); + .arg(atom->typeString()).arg(format())); } bool Generator::matchAhead(const Atom *atom, Atom::Type expectedAtomType) @@ -659,7 +712,8 @@ void Generator::supplementAlsoList(const Node *node, QList<Text> &alsoList) alternateFunc = func->parent()->findFunctionNode(alternateName); } } - } else if (!func->name().isEmpty()) { + } + else if (!func->name().isEmpty()) { alternateName = "set"; alternateName += func->name()[0].toUpper(); alternateName += func->name().mid(1); @@ -715,9 +769,13 @@ void Generator::generateStatus(const Node *node, CodeMarker *marker) case Node::Main: break; case Node::Preliminary: - text << Atom::ParaLeft << Atom(Atom::FormattingLeft, ATOM_FORMATTING_BOLD) << "This " - << typeString(node) << " is under development and is subject to change." - << Atom(Atom::FormattingRight, ATOM_FORMATTING_BOLD) << Atom::ParaRight; + text << Atom::ParaLeft + << Atom(Atom::FormattingLeft, ATOM_FORMATTING_BOLD) + << "This " + << typeString(node) + << " is under development and is subject to change." + << Atom(Atom::FormattingRight, ATOM_FORMATTING_BOLD) + << Atom::ParaRight; break; case Node::Deprecated: text << Atom::ParaLeft; @@ -735,16 +793,21 @@ void Generator::generateStatus(const Node *node, CodeMarker *marker) text << "This " << typeString(node) << " is obsolete."; if (node->isInnerNode()) text << Atom(Atom::FormattingRight, ATOM_FORMATTING_BOLD); - text << " It is provided to keep old source code working. We strongly advise against " + text << " It is provided to keep old source code working. " + << "We strongly advise against " << "using it in new code." << Atom::ParaRight; break; case Node::Compat: // reimplemented in HtmlGenerator subclass if (node->isInnerNode()) { - text << Atom::ParaLeft << Atom(Atom::FormattingLeft, ATOM_FORMATTING_BOLD) << "This " - << typeString(node) << " is part of the Qt 3 compatibility layer." + text << Atom::ParaLeft + << Atom(Atom::FormattingLeft, ATOM_FORMATTING_BOLD) + << "This " + << typeString(node) + << " is part of the Qt 3 compatibility layer." << Atom(Atom::FormattingRight, ATOM_FORMATTING_BOLD) - << " It is provided to keep old source code working. We strongly advise against " + << " It is provided to keep old source code working. " + << "We strongly advise against " << "using it in new code. See " << Atom(Atom::AutoLink, "Porting to Qt 4") << " for more information." @@ -762,71 +825,147 @@ void Generator::generateThreadSafeness(const Node *node, CodeMarker *marker) { Text text; Text theStockLink; - Node::ThreadSafeness parent = node->parent()->inheritedThreadSafeness(); + Node::ThreadSafeness threadSafeness = node->threadSafeness(); - switch (node->threadSafeness()) { + Text rlink; + rlink << Atom(Atom::Link,"reentrant") + << Atom(Atom::FormattingLeft, ATOM_FORMATTING_LINK) + << "reentrant" + << Atom(Atom::FormattingRight, ATOM_FORMATTING_LINK); + + Text tlink; + tlink << Atom(Atom::Link,"thread-safe") + << Atom(Atom::FormattingLeft, ATOM_FORMATTING_LINK) + << "thread-safe" + << Atom(Atom::FormattingRight, ATOM_FORMATTING_LINK); + + switch (threadSafeness) { case Node::UnspecifiedSafeness: break; case Node::NonReentrant: - text << Atom::ParaLeft << Atom(Atom::FormattingLeft, ATOM_FORMATTING_BOLD) << "Warning:" - << Atom(Atom::FormattingRight, ATOM_FORMATTING_BOLD) << " This " - << typeString(node) << " is not " << stockLink("reentrant") << "." << Atom::ParaRight; + text << Atom::ParaLeft + << Atom(Atom::FormattingLeft,ATOM_FORMATTING_BOLD) + << "Warning:" + << Atom(Atom::FormattingRight,ATOM_FORMATTING_BOLD) + << " This " + << typeString(node) + << " is not " + << rlink + << "." + << Atom::ParaRight; break; case Node::Reentrant: case Node::ThreadSafe: - text << Atom::ParaLeft << Atom(Atom::FormattingLeft, ATOM_FORMATTING_BOLD); - if (parent == Node::ThreadSafe) { - text << "Warning:"; - } else { - text << "Note:"; - } - text << Atom(Atom::FormattingRight, ATOM_FORMATTING_BOLD) << " "; - - if (node->threadSafeness() == Node::ThreadSafe) - theStockLink = stockLink("thread-safe"); - else - theStockLink = stockLink("reentrant"); + text << Atom::ParaLeft + << Atom(Atom::FormattingLeft,ATOM_FORMATTING_BOLD) + << "Note:" + << Atom(Atom::FormattingRight,ATOM_FORMATTING_BOLD) + << " "; if (node->isInnerNode()) { - const InnerNode *innerNode = static_cast<const InnerNode *>(node); - text << "All the functions in this " << typeString(node) << " are " - << theStockLink; - - NodeList except; + const InnerNode* innerNode = static_cast<const InnerNode*>(node); + text << "All functions in this " + << typeString(node) + << " are "; + if (threadSafeness == Node::ThreadSafe) + text << tlink; + else + text << rlink; + + bool exceptions = false; + NodeList reentrant; + NodeList threadsafe; + NodeList nonreentrant; NodeList::ConstIterator c = innerNode->childNodes().begin(); while (c != innerNode->childNodes().end()) { - if ((*c)->threadSafeness() != Node::UnspecifiedSafeness) - except.append(*c); + switch ((*c)->threadSafeness()) { + case Node::Reentrant: + reentrant.append(*c); + if (threadSafeness == Node::ThreadSafe) + exceptions = true; + break; + case Node::ThreadSafe: + threadsafe.append(*c); + if (threadSafeness == Node::Reentrant) + exceptions = true; + break; + case Node::NonReentrant: + nonreentrant.append(*c); + exceptions = true; + break; + default: + break; + } ++c; } - if (except.isEmpty()) { + if (!exceptions) text << "."; + else if (threadSafeness == Node::Reentrant) { + if (nonreentrant.isEmpty()) { + if (!threadsafe.isEmpty()) { + text << ", but "; + appendFullNames(text,threadsafe,innerNode,marker); + singularPlural(text,threadsafe); + text << " also " << tlink << "."; + } + else + text << "."; + } + else { + text << ", except for "; + appendFullNames(text,nonreentrant,innerNode,marker); + text << ", which"; + singularPlural(text,nonreentrant); + text << " nonreentrant."; + if (!threadsafe.isEmpty()) { + text << " "; + appendFullNames(text,threadsafe,innerNode,marker); + singularPlural(text,threadsafe); + text << " " << tlink << "."; + } + } } - else { - text << ", except "; - - NodeList::ConstIterator e = except.begin(); - int index = 0; - while (e != except.end()) { - appendFullName(text, *e, innerNode, marker); - text << separator(index++, except.count()); - ++e; + else { // thread-safe + if (!nonreentrant.isEmpty() || !reentrant.isEmpty()) { + text << ", except for "; + if (!reentrant.isEmpty()) { + appendFullNames(text,reentrant,innerNode,marker); + text << ", which"; + singularPlural(text,reentrant); + text << " only " << rlink; + if (!nonreentrant.isEmpty()) + text << ", and "; + } + if (!nonreentrant.isEmpty()) { + appendFullNames(text,nonreentrant,innerNode,marker); + text << ", which"; + singularPlural(text,nonreentrant); + text << " nonreentrant."; + } + text << "."; } } } else { - text << "This " << typeString(node) << " is " << theStockLink << "."; + text << "This " << typeString(node) << " is "; + if (threadSafeness == Node::ThreadSafe) + text << tlink; + else + text << rlink; + text << "."; } text << Atom::ParaRight; } - generateText(text, node, marker); + generateText(text,node,marker); } void Generator::generateSince(const Node *node, CodeMarker *marker) { if (!node->since().isEmpty()) { Text text; - text << Atom::ParaLeft << "This " << typeString(node) + text << Atom::ParaLeft + << "This " + << typeString(node) << " was introduced in "; if (project.isEmpty()) text << "version"; @@ -856,10 +995,12 @@ void Generator::generateReimplementedFrom(const FunctionNode *func, { if (func->reimplementedFrom() != 0) { const FunctionNode *from = func->reimplementedFrom(); - if (from->access() != Node::Private && from->parent()->access() != Node::Private) { + if (from->access() != Node::Private && + from->parent()->access() != Node::Private) { Text text; text << Atom::ParaLeft << "Reimplemented from "; - appendFullName(text, from->parent(), func, marker, from); + QString fullName = from->parent()->name() + "::" + from->name() + "()"; + appendFullName(text, from->parent(), fullName, from); text << "." << Atom::ParaRight; generateText(text, func, marker); } @@ -897,8 +1038,8 @@ const Atom *Generator::generateAtomList(const Atom *atom, if (atom->type() == Atom::FormatEndif) { if (generate && numAtoms0 == numAtoms) { - relative->location().warning(tr("Output format %1 not handled"). - arg(format())); + relative->location().warning(tr("Output format %1 not handled") + .arg(format())); Atom unhandledFormatAtom(Atom::UnhandledFormat, format()); generateAtomList(&unhandledFormatAtom, relative, @@ -909,7 +1050,8 @@ const Atom *Generator::generateAtomList(const Atom *atom, atom = atom->next(); } } - else if (atom->type() == Atom::FormatElse || atom->type() == Atom::FormatEndif) { + else if (atom->type() == Atom::FormatElse || + atom->type() == Atom::FormatEndif) { return atom; } else { @@ -939,6 +1081,33 @@ void Generator::appendFullName(Text& text, << Atom(Atom::FormattingRight, ATOM_FORMATTING_LINK); } +void Generator::appendFullName(Text& text, + const Node *apparentNode, + const QString& fullName, + const Node *actualNode) +{ + if (actualNode == 0) + actualNode = apparentNode; + text << Atom(Atom::LinkNode, CodeMarker::stringForNode(actualNode)) + << Atom(Atom::FormattingLeft, ATOM_FORMATTING_LINK) + << Atom(Atom::String, fullName) + << Atom(Atom::FormattingRight, ATOM_FORMATTING_LINK); +} + +void Generator::appendFullNames(Text& text, + const NodeList& nodes, + const Node* relative, + CodeMarker* marker) +{ + NodeList::ConstIterator n = nodes.begin(); + int index = 0; + while (n != nodes.end()) { + appendFullName(text,*n,relative,marker); + text << comma(index++,nodes.count()); + ++n; + } +} + void Generator::appendSortedNames(Text& text, const ClassNode *classe, const QList<RelatedClass> &classes, @@ -950,7 +1119,8 @@ void Generator::appendSortedNames(Text& text, r = classes.begin(); while (r != classes.end()) { - if ((*r).node->access() == Node::Public && (*r).node->status() != Node::Internal + if ((*r).node->access() == Node::Public && + (*r).node->status() != Node::Internal && !(*r).node->doc().isEmpty()) { Text className; appendFullName(className, (*r).node, classe, marker); diff --git a/tools/qdoc3/generator.h b/tools/qdoc3/generator.h index d0909a6..8e3c57e 100644 --- a/tools/qdoc3/generator.h +++ b/tools/qdoc3/generator.h @@ -93,13 +93,16 @@ class Generator virtual void generateClassLikeNode(const InnerNode *inner, CodeMarker *marker); virtual void generateFakeNode(const FakeNode *fake, CodeMarker *marker); - virtual void generateText(const Text& text, + virtual bool generateText(const Text& text, const Node *relative, CodeMarker *marker); #ifdef QDOC_QML - virtual void generateQmlText(const Text& text, + virtual bool generateQmlText(const Text& text, const Node *relative, - CodeMarker *marker); + CodeMarker *marker, + const QString& qmlName); + virtual void generateQmlInherits(const QmlClassNode* cn, + CodeMarker* marker); #endif virtual void generateBody(const Node *node, CodeMarker *marker); virtual void generateAlsoList(const Node *node, CodeMarker *marker); @@ -150,6 +153,14 @@ class Generator const Node *relative, CodeMarker *marker, const Node *actualNode = 0); + void appendFullName(Text& text, + const Node *apparentNode, + const QString& fullName, + const Node *actualNode); + void appendFullNames(Text& text, + const NodeList& nodes, + const Node* relative, + CodeMarker* marker); void appendSortedNames(Text& text, const ClassNode *classe, const QList<RelatedClass> &classes, diff --git a/tools/qdoc3/helpprojectwriter.cpp b/tools/qdoc3/helpprojectwriter.cpp index cf7c618..f862e55 100644 --- a/tools/qdoc3/helpprojectwriter.cpp +++ b/tools/qdoc3/helpprojectwriter.cpp @@ -118,16 +118,19 @@ void HelpProjectWriter::readSelectors(SubProject &subproject, const QStringList typeHash["variable"] = Node::Variable; typeHash["target"] = Node::Target; - QHash<QString, FakeNode::SubType> subTypeHash; - subTypeHash["example"] = FakeNode::Example; - subTypeHash["headerfile"] = FakeNode::HeaderFile; - subTypeHash["file"] = FakeNode::File; - subTypeHash["group"] = FakeNode::Group; - subTypeHash["module"] = FakeNode::Module; - subTypeHash["page"] = FakeNode::Page; - subTypeHash["externalpage"] = FakeNode::ExternalPage; - - QSet<FakeNode::SubType> allSubTypes = QSet<FakeNode::SubType>::fromList(subTypeHash.values()); + QHash<QString, Node::SubType> subTypeHash; + subTypeHash["example"] = Node::Example; + subTypeHash["headerfile"] = Node::HeaderFile; + subTypeHash["file"] = Node::File; + subTypeHash["group"] = Node::Group; + subTypeHash["module"] = Node::Module; + subTypeHash["page"] = Node::Page; + subTypeHash["externalpage"] = Node::ExternalPage; +#ifdef QDOC_QML + subTypeHash["qmlclass"] = Node::QmlClass; +#endif + + QSet<Node::SubType> allSubTypes = QSet<Node::SubType>::fromList(subTypeHash.values()); foreach (const QString &selector, selectors) { QStringList pieces = selector.split(":"); @@ -139,7 +142,7 @@ void HelpProjectWriter::readSelectors(SubProject &subproject, const QStringList QString lower = pieces[0].toLower(); pieces = pieces[1].split(","); if (typeHash.contains(lower)) { - QSet<FakeNode::SubType> subTypes; + QSet<Node::SubType> subTypes; for (int i = 0; i < pieces.size(); ++i) { QString lower = pieces[i].toLower(); if (subTypeHash.contains(lower)) @@ -235,7 +238,7 @@ bool HelpProjectWriter::generateSection(HelpProject &project, // mask. const FakeNode *fakeNode = static_cast<const FakeNode *>(node); if (subproject.selectors[node->type()].contains(fakeNode->subType()) && - fakeNode->subType() != FakeNode::ExternalPage && + fakeNode->subType() != Node::ExternalPage && !fakeNode->fullTitle().isEmpty()) project.subprojects[name].nodes[objName] = node; @@ -324,10 +327,10 @@ bool HelpProjectWriter::generateSection(HelpProject &project, // attributes. case Node::Fake: { const FakeNode *fakeNode = static_cast<const FakeNode*>(node); - if (fakeNode->subType() != FakeNode::ExternalPage && + if (fakeNode->subType() != Node::ExternalPage && !fakeNode->fullTitle().isEmpty()) { - if (fakeNode->subType() != FakeNode::File) { + if (fakeNode->subType() != Node::File) { if (fakeNode->doc().hasKeywords()) { foreach (const Atom *keyword, fakeNode->doc().keywords()) { if (!keyword->string().isEmpty()) { @@ -485,7 +488,7 @@ void HelpProjectWriter::writeNode(HelpProject &project, QXmlStreamWriter &writer writer.writeAttribute("title", fakeNode->fullTitle()); // qDebug() << "Title:" << fakeNode->fullTitle(); - if (fakeNode->subType() == FakeNode::HeaderFile) { + if (fakeNode->subType() == Node::HeaderFile) { // Write subsections for all members, obsolete members and Qt 3 // members. @@ -609,7 +612,7 @@ void HelpProjectWriter::generateProject(HelpProject &project) while (nextPage) { writeNode(project, writer, nextPage); nextTitle = nextPage->links().value(Node::NextLink).first; - if (nextTitle.isEmpty()) + if(nextTitle.isEmpty()) break; nextPage = const_cast<FakeNode *>(tree->findFakeNodeByTitle(nextTitle)); } diff --git a/tools/qdoc3/htmlgenerator.cpp b/tools/qdoc3/htmlgenerator.cpp index 543975e..425c50b 100644 --- a/tools/qdoc3/htmlgenerator.cpp +++ b/tools/qdoc3/htmlgenerator.cpp @@ -61,11 +61,132 @@ QT_BEGIN_NAMESPACE static bool showBrokenLinks = false; +static QRegExp linkTag("(<@link node=\"([^\"]+)\">).*(</@link>)"); +static QRegExp funcTag("(<@func target=\"([^\"]*)\">)(.*)(</@func>)"); +static QRegExp typeTag("(<@(type|headerfile|func)(?: +[^>]*)?>)(.*)(</@\\2>)"); +static QRegExp spanTag("</@(?:comment|preprocessor|string|char)>"); +static QRegExp unknownTag("</?@[^>]*>"); + +bool parseArg(const QString &src, + const QString &tag, + int *pos, + int n, + QStringRef *contents, + QStringRef *par1 = 0, + bool debug = false) +{ +#define SKIP_CHAR(c) \ + if (debug) \ + qDebug() << "looking for " << c << " at " << QString(src.data() + i, n - i); \ + if (i >= n || src[i] != c) { \ + if (debug) \ + qDebug() << " char '" << c << "' not found"; \ + return false; \ + } \ + ++i; + + +#define SKIP_SPACE \ + while (i < n && src[i] == ' ') \ + ++i; + + int i = *pos; + int j = i; + + // assume "<@" has been parsed outside + //SKIP_CHAR('<'); + //SKIP_CHAR('@'); + + if (tag != QStringRef(&src, i, tag.length())) { + if (0 && debug) + qDebug() << "tag " << tag << " not found at " << i; + return false; + } + + if (debug) + qDebug() << "haystack:" << src << "needle:" << tag << "i:" <<i; + + // skip tag + i += tag.length(); + + // parse stuff like: linkTag("(<@link node=\"([^\"]+)\">).*(</@link>)"); + if (par1) { + SKIP_SPACE; + // read parameter name + j = i; + while (i < n && src[i].isLetter()) + ++i; + if (src[i] == '=') { + if (debug) + qDebug() << "read parameter" << QString(src.data() + j, i - j); + SKIP_CHAR('='); + SKIP_CHAR('"'); + // skip parameter name + j = i; + while (i < n && src[i] != '"') + ++i; + *par1 = QStringRef(&src, j, i - j); + SKIP_CHAR('"'); + SKIP_SPACE; + } else { + if (debug) + qDebug() << "no optional parameter found"; + } + } + SKIP_SPACE; + SKIP_CHAR('>'); + + // find contents up to closing "</@tag> + j = i; + for (; true; ++i) { + if (i + 4 + tag.length() > n) + return false; + if (src[i] != '<') + continue; + if (src[i + 1] != '/') + continue; + if (src[i + 2] != '@') + continue; + if (tag != QStringRef(&src, i + 3, tag.length())) + continue; + if (src[i + 3 + tag.length()] != '>') + continue; + break; + } + + *contents = QStringRef(&src, j, i - j); + + i += tag.length() + 4; + + *pos = i; + if (debug) + qDebug() << " tag " << tag << " found: pos now: " << i; + return true; +#undef SKIP_CHAR +} + +static void addLink(const QString &linkTarget, + const QStringRef &nestedStuff, + QString *res) +{ + if (!linkTarget.isEmpty()) { + *res += "<a href=\""; + *res += linkTarget; + *res += "\">"; + *res += nestedStuff; + *res += "</a>"; + } + else { + *res += nestedStuff; + } +} + + HtmlGenerator::HtmlGenerator() : helpProjectWriter(0), inLink(false), inContents(false), inSectionHeading(false), inTableHeader(false), numTableRows(0), threeColumnEnumValueTable(true), funcLeftParen("\\S(\\()"), - tre(0), slow(false) + tre(0), slow(false), obsoleteLinks(false) { } @@ -94,6 +215,7 @@ void HtmlGenerator::initializeGenerator(const Config &config) }; Generator::initializeGenerator(config); + obsoleteLinks = config.getBool(QLatin1String(CONFIG_OBSOLETELINKS)); setImageFileExtensions(QStringList() << "png" << "jpg" << "jpeg" << "gif"); int i = 0; while (defaults[i].key) { @@ -102,11 +224,21 @@ void HtmlGenerator::initializeGenerator(const Config &config) i++; } - style = config.getString(HtmlGenerator::format() + Config::dot + HTMLGENERATOR_STYLE); - postHeader = config.getString(HtmlGenerator::format() + Config::dot + HTMLGENERATOR_POSTHEADER); - footer = config.getString(HtmlGenerator::format() + Config::dot + HTMLGENERATOR_FOOTER); - address = config.getString(HtmlGenerator::format() + Config::dot + HTMLGENERATOR_ADDRESS); - pleaseGenerateMacRef = config.getBool(HtmlGenerator::format() + Config::dot + HTMLGENERATOR_GENERATEMACREFS); + style = config.getString(HtmlGenerator::format() + + Config::dot + + HTMLGENERATOR_STYLE); + postHeader = config.getString(HtmlGenerator::format() + + Config::dot + + HTMLGENERATOR_POSTHEADER); + footer = config.getString(HtmlGenerator::format() + + Config::dot + + HTMLGENERATOR_FOOTER); + address = config.getString(HtmlGenerator::format() + + Config::dot + + HTMLGENERATOR_ADDRESS); + pleaseGenerateMacRef = config.getBool(HtmlGenerator::format() + + Config::dot + + HTMLGENERATOR_GENERATEMACREFS); project = config.getString(CONFIG_PROJECT); @@ -120,10 +252,16 @@ void HtmlGenerator::initializeGenerator(const Config &config) QSet<QString>::ConstIterator edition = editionNames.begin(); while (edition != editionNames.end()) { QString editionName = *edition; - QStringList editionModules = config.getStringList( - CONFIG_EDITION + Config::dot + editionName + Config::dot + "modules"); - QStringList editionGroups = config.getStringList( - CONFIG_EDITION + Config::dot + editionName + Config::dot + "groups"); + QStringList editionModules = config.getStringList(CONFIG_EDITION + + Config::dot + + editionName + + Config::dot + + "modules"); + QStringList editionGroups = config.getStringList(CONFIG_EDITION + + Config::dot + + editionName + + Config::dot + + "groups"); if (!editionModules.isEmpty()) editionModuleMap[editionName] = editionModules; @@ -135,11 +273,17 @@ void HtmlGenerator::initializeGenerator(const Config &config) slow = config.getBool(CONFIG_SLOW); - stylesheets = config.getStringList(HtmlGenerator::format() + Config::dot + HTMLGENERATOR_STYLESHEETS); - customHeadElements = config.getStringList(HtmlGenerator::format() + Config::dot + HTMLGENERATOR_CUSTOMHEADELEMENTS); + stylesheets = config.getStringList(HtmlGenerator::format() + + Config::dot + + HTMLGENERATOR_STYLESHEETS); + customHeadElements = config.getStringList(HtmlGenerator::format() + + Config::dot + + HTMLGENERATOR_CUSTOMHEADELEMENTS); codeIndent = config.getInt(CONFIG_CODEINDENT); - helpProjectWriter = new HelpProjectWriter(config, project.toLower() + ".qhp"); + helpProjectWriter = new HelpProjectWriter(config, + project.toLower() + + ".qhp"); } void HtmlGenerator::terminateGenerator() @@ -173,6 +317,7 @@ void HtmlGenerator::generateTree(const Tree *tree, CodeMarker *marker) nonCompatClasses.clear(); mainClasses.clear(); compatClasses.clear(); + obsoleteClasses.clear(); moduleClassMap.clear(); moduleNamespaceMap.clear(); funcIndex.clear(); @@ -182,9 +327,9 @@ void HtmlGenerator::generateTree(const Tree *tree, CodeMarker *marker) findAllFunctions(tree->root()); findAllLegaleseTexts(tree->root()); findAllNamespaces(tree->root()); -#ifdef ZZZ_QDOC_QML +#ifdef ZZZ_QDOC_QML findAllQmlClasses(tree->root()); -#endif +#endif PageGenerator::generateTree(tree, marker); @@ -260,7 +405,7 @@ int HtmlGenerator::generateAtom(const Atom *atom, case Atom::AutoLink: if (!inLink && !inContents && !inSectionHeading) { const Node *node = 0; - QString link = getLink(atom, relative, marker, node); + QString link = getLink(atom, relative, marker, &node); if (!link.isEmpty()) { beginLink(link, node, relative, marker); generateLink(atom, relative, marker); @@ -288,7 +433,8 @@ int HtmlGenerator::generateAtom(const Atom *atom, QString str; atom = atom->next(); while (atom != 0 && atom->type() != Atom::BriefRight) { - if (atom->type() == Atom::String || atom->type() == Atom::AutoLink) + if (atom->type() == Atom::String || + atom->type() == Atom::AutoLink) str += atom->string(); skipAhead++; atom = atom->next(); @@ -326,21 +472,24 @@ int HtmlGenerator::generateAtom(const Atom *atom, out() << formattingRightMap()[ATOM_FORMATTING_TELETYPE]; break; case Atom::Code: - out() << "<pre>" << trimmedTrailing(highlightedCode(indent(codeIndent, atom->string()), - marker, relative)) + out() << "<pre>" + << trimmedTrailing(highlightedCode(indent(codeIndent,atom->string()), + marker,relative)) << "</pre>\n"; break; -#ifdef QDOC_QML +#ifdef QDOC_QML case Atom::Qml: - out() << "<pre>" << trimmedTrailing(highlightedCode(indent(codeIndent, atom->string()), - marker, relative)) + out() << "<pre>" + << trimmedTrailing(highlightedCode(indent(codeIndent,atom->string()), + marker,relative)) << "</pre>\n"; break; -#endif +#endif case Atom::CodeNew: out() << "<p>you can rewrite it as</p>\n" - << "<pre>" << trimmedTrailing(highlightedCode(indent(codeIndent, atom->string()), - marker, relative)) + << "<pre>" + << trimmedTrailing(highlightedCode(indent(codeIndent,atom->string()), + marker,relative)) << "</pre>\n"; break; case Atom::CodeOld: @@ -348,7 +497,7 @@ int HtmlGenerator::generateAtom(const Atom *atom, // fallthrough case Atom::CodeBad: out() << "<pre><font color=\"#404040\">" - << trimmedTrailing(protect(plainCode(indent(codeIndent, atom->string())))) + << trimmedTrailing(protect(plainCode(indent(codeIndent,atom->string())))) << "</font></pre>\n"; break; case Atom::FootnoteLeft: @@ -388,6 +537,20 @@ int HtmlGenerator::generateAtom(const Atom *atom, out() << formattingRightMap()[atom->string()]; } break; + case Atom::AnnotatedList: + { + const FakeNode *fake = static_cast<const FakeNode *>(relative); + if (fake && !fake->groupMembers().isEmpty()) { + QList<Node*> values = tre->groups().values(atom->string()); + QMap<QString, const Node*> nodeMap; + for (int i = 0; i < values.size(); ++i) { + const Node* n = values.at(i); + nodeMap.insert(n->name(),n); + } + generateAnnotatedList(fake, marker, nodeMap); + } + } + break; case Atom::GeneratedList: if (atom->string() == "annotatedclasses") { generateAnnotatedList(relative, marker, nonCompatClasses); @@ -443,6 +606,9 @@ int HtmlGenerator::generateAtom(const Atom *atom, else if (atom->string() == "compatclasses") { generateCompactList(relative, marker, compatClasses); } + else if (atom->string() == "obsoleteclasses") { + generateCompactList(relative, marker, obsoleteClasses); + } else if (atom->string() == "functionindex") { generateFunctionIndex(relative, marker); } @@ -524,11 +690,12 @@ int HtmlGenerator::generateAtom(const Atom *atom, case Atom::Link: { const Node *node = 0; - QString myLink = getLink(atom, relative, marker, node); - if (myLink.isEmpty()) + QString myLink = getLink(atom, relative, marker, &node); + if (myLink.isEmpty()) { relative->doc().location().warning(tr("Cannot link to '%1' in %2") .arg(atom->string()) .arg(marker->plainFullName(relative))); + } beginLink(myLink, node, relative, marker); skipAhead = 1; } @@ -554,13 +721,17 @@ int HtmlGenerator::generateAtom(const Atom *atom, else if (atom->string() == ATOM_LIST_VALUE) { threeColumnEnumValueTable = isThreeColumnEnumValueTable(atom); if (threeColumnEnumValueTable) { - out() << "<p><table border=\"1\" cellpadding=\"2\" cellspacing=\"1\" width=\"100%\">\n" - "<tr><th width=\"25%\">Constant</th><th width=\"15%\">Value</th>" - "<th width=\"60%\">Description</th></tr>\n"; + out() << "<p><table class=\"valuelist\" border=\"1\" cellpadding=\"2\" " + << "cellspacing=\"1\" width=\"100%\">\n" + << "<tr><th width=\"25%\">Constant</th>" + << "<th width=\"15%\">Value</th>" + << "<th width=\"60%\">Description</th></tr>\n"; } else { - out() << "<p><table border=\"1\" cellpadding=\"2\" cellspacing=\"1\" width=\"40%\">\n" - << "<tr><th width=\"60%\">Constant</th><th width=\"40%\">Value</th></tr>\n"; + out() << "<p><table class=\"valuelist\" border=\"1\" cellpadding=\"2\" " + << "cellspacing=\"1\" width=\"40%\">\n" + << "<tr><th width=\"60%\">Constant</th><th " + << "width=\"40%\">Value</th></tr>\n"; } } else { @@ -734,14 +905,17 @@ int HtmlGenerator::generateAtom(const Atom *atom, } if (!atom->string().isEmpty()) { if (atom->string().contains("%")) - out() << "<p><table width=\"" << atom->string() << "\" " + out() << "<p><table class=\"generic\" width=\"" << atom->string() << "\" " << "align=\"center\" cellpadding=\"2\" " << "cellspacing=\"1\" border=\"0\">\n"; - else - out() << "<p><table align=\"center\" cellpadding=\"2\" cellspacing=\"1\" border=\"0\">\n"; + else { + out() << "<p><table class=\"generic\" align=\"center\" cellpadding=\"2\" " + << "cellspacing=\"1\" border=\"0\">\n"; + } } else { - out() << "<p><table align=\"center\" cellpadding=\"2\" cellspacing=\"1\" border=\"0\">\n"; + out() << "<p><table class=\"generic\" align=\"center\" cellpadding=\"2\" " + << "cellspacing=\"1\" border=\"0\">\n"; } numTableRows = 0; break; @@ -840,7 +1014,7 @@ int HtmlGenerator::generateAtom(const Atom *atom, case Atom::EndQmlText: // don't do anything with these. They are just tags. break; -#endif +#endif default: unknownAtom(atom); } @@ -906,6 +1080,12 @@ void HtmlGenerator::generateClassLikeNode(const InnerNode *inner, generateHeader(title, inner, marker, true); generateTitle(title, subtitleText, SmallSubTitle, inner, marker); +#ifdef QDOC_QML + if (classe && !classe->qmlElement().isEmpty()) { + generateInstantiatedBy(classe,marker); + } +#endif + generateBrief(inner, marker); generateIncludes(inner, marker); generateStatus(inner, marker); @@ -924,12 +1104,16 @@ void HtmlGenerator::generateClassLikeNode(const InnerNode *inner, out() << "<li><a href=\"" << membersLink << "\">" << "List of all members, including inherited members</a></li>\n"; - QString obsoleteLink = generateLowStatusMemberFile(inner, marker, CodeMarker::Obsolete); + QString obsoleteLink = generateLowStatusMemberFile(inner, + marker, + CodeMarker::Obsolete); if (!obsoleteLink.isEmpty()) out() << "<li><a href=\"" << obsoleteLink << "\">" << "Obsolete members</a></li>\n"; - QString compatLink = generateLowStatusMemberFile(inner, marker, CodeMarker::Compat); + QString compatLink = generateLowStatusMemberFile(inner, + marker, + CodeMarker::Compat); if (!compatLink.isEmpty()) out() << "<li><a href=\"" << compatLink << "\">" << "Qt 3 support members</a></li>\n"; @@ -941,14 +1125,34 @@ void HtmlGenerator::generateClassLikeNode(const InnerNode *inner, sections = marker->sections(inner, CodeMarker::Summary, CodeMarker::Okay); s = sections.begin(); while (s != sections.end()) { - if (s->members.isEmpty()) { + if (s->members.isEmpty() && s->reimpMembers.isEmpty()) { if (!s->inherited.isEmpty()) needOtherSection = true; - } else { - out() << "<a name=\"" << registerRef((*s).name.toLower()) << "\"></a>\n"; - out() << "<h3>" << protect((*s).name) << "</h3>\n"; + } + else { + if (!s->members.isEmpty()) { + out() << "<hr />\n"; + out() << "<a name=\"" + << registerRef((*s).name.toLower()) + << "\"></a>\n"; + out() << "<h2>" << protect((*s).name) << "</h2>\n"; + generateSection(s->members, inner, marker, CodeMarker::Summary); + } + if (!s->reimpMembers.isEmpty()) { + QString name = QString("Reimplemented ") + (*s).name; + out() << "<hr />\n"; + out() << "<a name=\"" + << registerRef(name.toLower()) + << "\"></a>\n"; + out() << "<h2>" << protect(name) << "</h2>\n"; + generateSection(s->reimpMembers, inner, marker, CodeMarker::Summary); + } - generateSectionList(*s, inner, marker, CodeMarker::Summary); + if (!s->inherited.isEmpty()) { + out() << "<ul>\n"; + generateSectionInheritedList(*s, inner, marker, true); + out() << "</ul>\n"; + } } ++s; } @@ -997,29 +1201,34 @@ void HtmlGenerator::generateClassLikeNode(const InnerNode *inner, names << (*m)->name(); if ((*m)->type() == Node::Function) { const FunctionNode *func = reinterpret_cast<const FunctionNode *>(*m); - if (func->metaness() == FunctionNode::Ctor || func->metaness() == FunctionNode::Dtor - || func->overloadNumber() != 1) + if (func->metaness() == FunctionNode::Ctor || + func->metaness() == FunctionNode::Dtor || + func->overloadNumber() != 1) names.clear(); - } else if ((*m)->type() == Node::Property) { + } + else if ((*m)->type() == Node::Property) { const PropertyNode *prop = reinterpret_cast<const PropertyNode *>(*m); - if (!prop->getters().isEmpty() && !names.contains(prop->getters().first()->name())) + if (!prop->getters().isEmpty() && + !names.contains(prop->getters().first()->name())) names << prop->getters().first()->name(); if (!prop->setters().isEmpty()) names << prop->setters().first()->name(); if (!prop->resetters().isEmpty()) names << prop->resetters().first()->name(); - } else if ((*m)->type() == Node::Enum) { - const EnumNode *enume = reinterpret_cast<const EnumNode *>(*m); + } + else if ((*m)->type() == Node::Enum) { + const EnumNode *enume = reinterpret_cast<const EnumNode*>(*m); if (enume->flagsType()) names << enume->flagsType()->name(); foreach (const QString &enumName, - enume->doc().enumItemNames().toSet() - - enume->doc().omitEnumItemNames().toSet()) - names << plainCode(marker->markedUpEnumValue(enumName, enume)); + enume->doc().enumItemNames().toSet() - + enume->doc().omitEnumItemNames().toSet()) + names << plainCode(marker->markedUpEnumValue(enumName, + enume)); } foreach (const QString &name, names) - classSection.keywords += qMakePair(name, linkForNode(*m, 0)); + classSection.keywords += qMakePair(name,linkForNode(*m,0)); } ++m; } @@ -1060,16 +1269,19 @@ void HtmlGenerator::generateFakeNode(const FakeNode *fake, CodeMarker *marker) QList<Section>::const_iterator s; QString htmlTitle = fake->fullTitle(); - if (fake->subType() == FakeNode::File && !fake->subTitle().isEmpty()) { + if (fake->subType() == Node::File && !fake->subTitle().isEmpty()) { subTitleSize = SmallSubTitle; htmlTitle += " (" + fake->subTitle() + ")"; } generateHeader(htmlTitle, fake, marker, true); - generateTitle(fake->fullTitle(), Text() << fake->subTitle(), subTitleSize, - fake, marker); + generateTitle(fake->fullTitle(), + Text() << fake->subTitle(), + subTitleSize, + fake, + marker); - if (fake->subType() == FakeNode::Module) { + if (fake->subType() == Node::Module) { // Generate brief text and status for modules. generateBrief(fake, marker); generateStatus(fake, marker); @@ -1083,7 +1295,7 @@ void HtmlGenerator::generateFakeNode(const FakeNode *fake, CodeMarker *marker) generateAnnotatedList(fake, marker, moduleClassMap[fake->name()]); } } - else if (fake->subType() == FakeNode::HeaderFile) { + else if (fake->subType() == Node::HeaderFile) { // Generate brief text and status for modules. generateBrief(fake, marker); generateStatus(fake, marker); @@ -1095,12 +1307,16 @@ void HtmlGenerator::generateFakeNode(const FakeNode *fake, CodeMarker *marker) out() << "<li><a href=\"" << membersLink << "\">" << "List of all members, including inherited members</a></li>\n"; - QString obsoleteLink = generateLowStatusMemberFile(fake, marker, CodeMarker::Obsolete); + QString obsoleteLink = generateLowStatusMemberFile(fake, + marker, + CodeMarker::Obsolete); if (!obsoleteLink.isEmpty()) out() << "<li><a href=\"" << obsoleteLink << "\">" << "Obsolete members</a></li>\n"; - QString compatLink = generateLowStatusMemberFile(fake, marker, CodeMarker::Compat); + QString compatLink = generateLowStatusMemberFile(fake, + marker, + CodeMarker::Compat); if (!compatLink.isEmpty()) out() << "<li><a href=\"" << compatLink << "\">" << "Qt 3 support members</a></li>\n"; @@ -1126,35 +1342,65 @@ void HtmlGenerator::generateFakeNode(const FakeNode *fake, CodeMarker *marker) appendDcfSubSection(&fakeSection, compatSection); } } +#ifdef QDOC_QML + else if (fake->subType() == Node::QmlClass) { + const QmlClassNode* qml_cn = static_cast<const QmlClassNode*>(fake); + const ClassNode* cn = qml_cn->classNode(); + generateQmlInherits(qml_cn, marker); + generateQmlInstantiates(qml_cn, marker); + generateBrief(qml_cn, marker); + sections = marker->qmlSections(qml_cn,CodeMarker::Summary); + s = sections.begin(); + while (s != sections.end()) { + out() << "<a name=\"" << registerRef((*s).name) << "\"></a>\n"; + out() << "<h2>" << protect((*s).name) << "</h2>\n"; + generateQmlSummary(*s,fake,marker); + ++s; + } + + out() << "<a name=\"" << registerRef("details") << "\"></a>\n"; + out() << "<h2>" << "Detailed Description" << "</h2>\n"; + generateBody(fake, marker); + if (cn) + generateQmlText(cn->doc().body(), cn, marker, fake->name()); + generateAlsoList(fake, marker); + out() << "<hr />\n"; + sections = marker->qmlSections(qml_cn,CodeMarker::Detailed); + s = sections.begin(); + while (s != sections.end()) { + out() << "<h2>" << protect((*s).name) << "</h2>\n"; + NodeList::ConstIterator m = (*s).members.begin(); + while (m != (*s).members.end()) { + generateDetailedQmlMember(*m, fake, marker); + out() << "<br />\n"; + fakeSection.keywords += qMakePair((*m)->name(), + linkForNode(*m,0)); + ++m; + } + ++s; + } + generateFooter(fake); + return; + } +#endif + sections = marker->sections(fake, CodeMarker::Summary, CodeMarker::Okay); s = sections.begin(); while (s != sections.end()) { out() << "<a name=\"" << registerRef((*s).name) << "\"></a>\n"; - out() << "<h3>" << protect((*s).name) << "</h3>\n"; + out() << "<h2>" << protect((*s).name) << "</h2>\n"; generateSectionList(*s, fake, marker, CodeMarker::Summary); ++s; } Text brief = fake->doc().briefText(); - if (fake->subType() == FakeNode::Module && !brief.isEmpty()) { + if (fake->subType() == Node::Module && !brief.isEmpty()) { out() << "<a name=\"" << registerRef("details") << "\"></a>\n"; out() << "<h2>" << "Detailed Description" << "</h2>\n"; } generateBody(fake, marker); -#ifdef QDOC_QML - if (fake->subType() == FakeNode::QmlClass) { - //qDebug() << "generateFakeNode(): QML CLASS" << fake->name(); - const QmlNode* qmlNode = static_cast<const QmlNode*>(fake); - const ClassNode* cn = qmlNode->classNode(); - if (cn) { - //qDebug() << " CPP CLASS" << cn->name(); - generateQmlText(cn->doc().body(), cn, marker); - } - } -#endif - generateAlsoList(fake, marker); if (!fake->groupMembers().isEmpty()) { @@ -1184,10 +1430,10 @@ void HtmlGenerator::generateFakeNode(const FakeNode *fake, CodeMarker *marker) } generateFooter(fake); - if (fake->subType() == FakeNode::Example) { + if (fake->subType() == Node::Example) { appendDcfSubSection(&dcfExamplesRoot, fakeSection); } - else if (fake->subType() != FakeNode::File) { + else if (fake->subType() != Node::File) { QString contentsPage = fake->links().value(Node::ContentsLink).first; if (contentsPage == "Qt Designer Manual") { @@ -1407,17 +1653,19 @@ void HtmlGenerator::generateBrief(const Node *node, CodeMarker *marker, void HtmlGenerator::generateIncludes(const InnerNode *inner, CodeMarker *marker) { if (!inner->includes().isEmpty()) { - out() << "<pre>" << trimmedTrailing(highlightedCode(indent(codeIndent, - marker->markedUpIncludes( - inner->includes())), - marker, inner)) + out() << "<pre>" + << trimmedTrailing(highlightedCode(indent(codeIndent, + marker->markedUpIncludes(inner->includes())), + marker,inner)) << "</pre>"; } } -void HtmlGenerator::generateTableOfContents(const Node *node, CodeMarker *marker, +void HtmlGenerator::generateTableOfContents(const Node *node, + CodeMarker *marker, Doc::SectioningUnit sectioningUnit, - int numColumns, const Node *relative) + int numColumns, + const Node *relative) { if (!node->doc().hasTableOfContents()) @@ -1436,7 +1684,8 @@ void HtmlGenerator::generateTableOfContents(const Node *node, CodeMarker *marker QString tdTag; if (numColumns > 1) { tdTag = "<td width=\"" + QString::number((100 + numColumns - 1) / numColumns) + "%\">"; - out() << "<p><table width=\"100%\">\n<tr valign=\"top\">" << tdTag << "\n"; + out() << "<p><table class=\"toc\" width=\"100%\">\n<tr valign=\"top\">" + << tdTag << "\n"; } // disable nested links in table of contents @@ -1455,7 +1704,8 @@ void HtmlGenerator::generateTableOfContents(const Node *node, CodeMarker *marker out() << "<ul>"; sectionNumber.append("1"); } while (sectionNumber.size() < nextLevel); - } else { + } + else { while (sectionNumber.size() > nextLevel) { out() << "</ul>\n"; sectionNumber.removeLast(); @@ -1470,7 +1720,10 @@ void HtmlGenerator::generateTableOfContents(const Node *node, CodeMarker *marker columnSize = 0; } out() << "<li>"; - out() << "<a href=\"" << nodeName << "#" << Doc::canonicalTitle(headingText.toString()) + out() << "<a href=\"" + << nodeName + << "#" + << Doc::canonicalTitle(headingText.toString()) << "\">"; generateAtomList(headingText.firstAtom(), node, marker, true, numAtoms); out() << "</a></li>\n"; @@ -1520,12 +1773,15 @@ void HtmlGenerator::generateNavigationBar(const NavigationBar& bar, } #endif -QString HtmlGenerator::generateListOfAllMemberFile(const InnerNode *inner, CodeMarker *marker) +QString HtmlGenerator::generateListOfAllMemberFile(const InnerNode *inner, + CodeMarker *marker) { QList<Section> sections; QList<Section>::ConstIterator s; - sections = marker->sections(inner, CodeMarker::SeparateList, CodeMarker::Okay); + sections = marker->sections(inner, + CodeMarker::SeparateList, + CodeMarker::Okay); if (sections.isEmpty()) return QString(); @@ -1546,10 +1802,13 @@ QString HtmlGenerator::generateListOfAllMemberFile(const InnerNode *inner, CodeM return fileName; } -QString HtmlGenerator::generateLowStatusMemberFile(const InnerNode *inner, CodeMarker *marker, +QString HtmlGenerator::generateLowStatusMemberFile(const InnerNode *inner, + CodeMarker *marker, CodeMarker::Status status) { - QList<Section> sections = marker->sections(inner, CodeMarker::Summary, status); + QList<Section> sections = marker->sections(inner, + CodeMarker::Summary, + status); QMutableListIterator<Section> j(sections); while (j.hasNext()) { if (j.next().members.size() == 0) @@ -1566,7 +1825,8 @@ QString HtmlGenerator::generateLowStatusMemberFile(const InnerNode *inner, CodeM if (status == CodeMarker::Compat) { title = "Qt 3 Support Members for " + inner->name(); fileName = fileBase(inner) + "-qt3." + fileExtension(inner); - } else { + } + else { title = "Obsolete Members for " + inner->name(); fileName = fileBase(inner) + "-obsolete." + fileExtension(inner); } @@ -1580,18 +1840,20 @@ QString HtmlGenerator::generateLowStatusMemberFile(const InnerNode *inner, CodeM "<a href=\"qt3support.html\">Qt 3 support layer</a>.</b> " "They are provided to help you port old code to Qt 4. We advise against " "using them in new code.</p>\n"; - } else { - out() << "<p><b>The following class members are obsolete.</b> They are provided to keep " - "old source code working. We strongly advise against using them in new " - "code.</p>\n"; + } + else { + out() << "<p><b>The following class members are obsolete.</b> " + << "They are provided to keep old source code working. " + << "We strongly advise against using them in new code.</p>\n"; } - out() << "<p><ul><li><a href=\"" << linkForNode(inner, 0) << "\">" << protect(inner->name()) + out() << "<p><ul><li><a href=\"" + << linkForNode(inner, 0) << "\">" + << protect(inner->name()) << " class reference</a></li></ul></p>\n"; for (i = 0; i < sections.size(); ++i) { - out() << "<h3>" << protect(sections.at(i).name) << "</h3>\n"; - + out() << "<h2>" << protect(sections.at(i).name) << "</h2>\n"; generateSectionList(sections.at(i), inner, marker, CodeMarker::Summary); } @@ -1613,8 +1875,9 @@ QString HtmlGenerator::generateLowStatusMemberFile(const InnerNode *inner, CodeM return fileName; } -void HtmlGenerator::generateClassHierarchy(const Node *relative, CodeMarker *marker, - const QMap<QString, const Node *> &classMap) +void HtmlGenerator::generateClassHierarchy(const Node *relative, + CodeMarker *marker, + const QMap<QString,const Node*> &classMap) { if (classMap.isEmpty()) return; @@ -1636,8 +1899,10 @@ void HtmlGenerator::generateClassHierarchy(const Node *relative, CodeMarker *mar if (stack.top().isEmpty()) { stack.pop(); out() << "</ul>\n"; - } else { - const ClassNode *child = static_cast<const ClassNode *>(*stack.top().begin()); + } + else { + const ClassNode *child = + static_cast<const ClassNode *>(*stack.top().begin()); out() << "<li>"; generateFullName(child, relative, marker); out() << "</li>\n"; @@ -1656,15 +1921,20 @@ void HtmlGenerator::generateClassHierarchy(const Node *relative, CodeMarker *mar } } -void HtmlGenerator::generateAnnotatedList(const Node *relative, CodeMarker *marker, - const QMap<QString, const Node *> &nodeMap) +void HtmlGenerator::generateAnnotatedList(const Node *relative, + CodeMarker *marker, + const QMap<QString, const Node *> &nodeMap) { - out() << "<p><table width=\"100%\" class=\"annotated\" cellpadding=\"2\" cellspacing=\"1\" border=\"0\">\n"; + out() << "<p><table width=\"100%\" class=\"annotated\" cellpadding=\"2\" " + << "cellspacing=\"1\" border=\"0\">\n"; int row = 0; foreach (const QString &name, nodeMap.keys()) { const Node *node = nodeMap[name]; + if (node->status() == Node::Obsolete) + continue; + if (++row % 2 == 1) out() << "<tr valign=\"top\" class=\"odd\">"; else @@ -1680,7 +1950,8 @@ void HtmlGenerator::generateAnnotatedList(const Node *relative, CodeMarker *mark generateText(brief, node, marker); out() << "</td>"; } - } else { + } + else { out() << "<td>"; out() << protect(node->doc().briefText().toString()); out() << "</td>"; @@ -1690,7 +1961,8 @@ void HtmlGenerator::generateAnnotatedList(const Node *relative, CodeMarker *mark out() << "</table></p>\n"; } -void HtmlGenerator::generateCompactList(const Node *relative, CodeMarker *marker, +void HtmlGenerator::generateCompactList(const Node *relative, + CodeMarker *marker, const QMap<QString, const Node *> &classMap) { const int NumParagraphs = 37; // '0' to '9', 'A' to 'Z', '_' @@ -1734,8 +2006,9 @@ void HtmlGenerator::generateCompactList(const Node *relative, CodeMarker *marker last = classMap.begin().key(); if (classMap.size() > 1) { - while (commonPrefixLen < first.length() + 1 && commonPrefixLen < last.length() + 1 - && first[commonPrefixLen] == last[commonPrefixLen]) + while (commonPrefixLen < first.length() + 1 && + commonPrefixLen < last.length() + 1 && + first[commonPrefixLen] == last[commonPrefixLen]) ++commonPrefixLen; } @@ -1764,7 +2037,8 @@ void HtmlGenerator::generateCompactList(const Node *relative, CodeMarker *marker if (key[0].digitValue() != -1) { paragraphNo = key[0].digitValue(); - } else if (key[0] >= QLatin1Char('a') && key[0] <= QLatin1Char('z')) { + } + else if (key[0] >= QLatin1Char('a') && key[0] <= QLatin1Char('z')) { paragraphNo = 10 + key[0].unicode() - 'a'; } @@ -1812,14 +2086,15 @@ void HtmlGenerator::generateCompactList(const Node *relative, CodeMarker *marker } firstOffset[NumColumns] = classMap.count(); - out() << "<p><table width=\"100%\">\n"; + out() << "<p><table class=\"generic\" width=\"100%\">\n"; for (k = 0; k < numRows; k++) { out() << "<tr>\n"; for (i = 0; i < NumColumns; i++) { if (currentOffset[i] >= firstOffset[i + 1]) { // this column is finished out() << "<td>\n</td>\n"; - } else { + } + else { while (currentOffsetInParagraph[i] == paragraph[currentParagraphNo[i]].count()) { ++currentParagraphNo[i]; currentOffsetInParagraph[i] = 0; @@ -1828,29 +2103,34 @@ void HtmlGenerator::generateCompactList(const Node *relative, CodeMarker *marker out() << "<td align=\"right\">"; if (currentOffsetInParagraph[i] == 0) { // start a new paragraph - out() << "<b>" << paragraphName[currentParagraphNo[i]] << " </b>"; - } - out() << "</td>\n"; - - // bad loop - QMap<QString, const Node *>::Iterator it; - it = paragraph[currentParagraphNo[i]].begin(); - for (j = 0; j < currentOffsetInParagraph[i]; j++) - ++it; - - out() << "<td>"; - // Previously, we used generateFullName() for this, but we - // require some special formatting. - out() << "<a href=\"" << linkForNode(it.value(), relative) << "\">"; - QStringList pieces = fullName(it.value(), relative, marker).split("::"); - out() << protect(pieces.last()); - out() << "</a>"; - if (pieces.size() > 1) { - out() << " ("; - generateFullName(it.value()->parent(), relative, marker); - out() << ")"; + out() << "<b>" + << paragraphName[currentParagraphNo[i]] + << " </b>"; } out() << "</td>\n"; + + if (!paragraphName[currentParagraphNo[i]].isEmpty()) { + QMap<QString, const Node *>::Iterator it; + it = paragraph[currentParagraphNo[i]].begin(); + for (j = 0; j < currentOffsetInParagraph[i]; j++) + ++it; + + out() << "<td>"; + // Previously, we used generateFullName() for this, but we + // require some special formatting. + out() << "<a href=\"" + << linkForNode(it.value(), relative) + << "\">"; + QStringList pieces = fullName(it.value(), relative, marker).split("::"); + out() << protect(pieces.last()); + out() << "</a>"; + if (pieces.size() > 1) { + out() << " ("; + generateFullName(it.value()->parent(), relative, marker); + out() << ")"; + } + out() << "</td>\n"; + } currentOffset[i]++; currentOffsetInParagraph[i]++; @@ -1861,7 +2141,8 @@ void HtmlGenerator::generateCompactList(const Node *relative, CodeMarker *marker out() << "</table></p>\n"; } -void HtmlGenerator::generateFunctionIndex(const Node *relative, CodeMarker *marker) +void HtmlGenerator::generateFunctionIndex(const Node *relative, + CodeMarker *marker) { out() << "<p align=\"center\"><font size=\"+1\"><b>"; for (int i = 0; i < 26; i++) { @@ -1910,7 +2191,8 @@ void HtmlGenerator::generateFunctionIndex(const Node *relative, CodeMarker *mark #endif } -void HtmlGenerator::generateLegaleseList(const Node *relative, CodeMarker *marker) +void HtmlGenerator::generateLegaleseList(const Node *relative, + CodeMarker *marker) { QMap<Text, const Node *>::ConstIterator it = legaleseTexts.begin(); while (it != legaleseTexts.end()) { @@ -1928,8 +2210,10 @@ void HtmlGenerator::generateLegaleseList(const Node *relative, CodeMarker *marke } } -void HtmlGenerator::generateSynopsis(const Node *node, const Node *relative, - CodeMarker *marker, CodeMarker::SynopsisStyle style) +/*void HtmlGenerator::generateSynopsis(const Node *node, + const Node *relative, + CodeMarker *marker, + CodeMarker::SynopsisStyle style) { QString marked = marker->markedUpSynopsis(node, relative, style); QRegExp templateTag("(<[^@>]*>)"); @@ -1939,7 +2223,8 @@ void HtmlGenerator::generateSynopsis(const Node *node, const Node *relative, marked.replace(templateTag.pos(1), templateTag.cap(1).length(), contents); } - marked.replace(QRegExp("<@param>([a-z]+)_([1-9n])</@param>"), "<i>\\1<sub>\\2</sub></i>"); + marked.replace(QRegExp("<@param>([a-z]+)_([1-9n])</@param>"), + "<i>\\1<sub>\\2</sub></i>"); marked.replace("<@param>", "<i>"); marked.replace("</@param>", "</i>"); @@ -1950,7 +2235,8 @@ void HtmlGenerator::generateSynopsis(const Node *node, const Node *relative, QRegExp extraRegExp("<@extra>.*</@extra>"); extraRegExp.setMinimal(true); marked.replace(extraRegExp, ""); - } else { + } + else { marked.replace("<@extra>", " <tt>"); marked.replace("</@extra>", "</tt>"); } @@ -1960,7 +2246,40 @@ void HtmlGenerator::generateSynopsis(const Node *node, const Node *relative, marked.replace("</@type>", ""); } out() << highlightedCode(marked, marker, relative); +}*/ + +#ifdef QDOC_QML +void HtmlGenerator::generateQmlItem(const Node *node, + const Node *relative, + CodeMarker *marker, + bool summary) +{ + QString marked = marker->markedUpQmlItem(node,summary); + QRegExp templateTag("(<[^@>]*>)"); + if (marked.indexOf(templateTag) != -1) { + QString contents = protect(marked.mid(templateTag.pos(1), + templateTag.cap(1).length())); + marked.replace(templateTag.pos(1), templateTag.cap(1).length(), + contents); + } + marked.replace(QRegExp("<@param>([a-z]+)_([1-9n])</@param>"), + "<i>\\1<sub>\\2</sub></i>"); + marked.replace("<@param>", "<i>"); + marked.replace("</@param>", "</i>"); + + if (summary) + marked.replace("@name>", "b>"); + + marked.replace("<@extra>", " <tt>"); + marked.replace("</@extra>", "</tt>"); + + if (summary) { + marked.replace("<@type>", ""); + marked.replace("</@type>", ""); + } + out() << highlightedCode(marked, marker, relative); } +#endif void HtmlGenerator::generateOverviewList(const Node *relative, CodeMarker * /* marker */) { @@ -1984,7 +2303,7 @@ void HtmlGenerator::generateOverviewList(const Node *relative, CodeMarker * /* m } // there are too many examples; they would clutter the list - if (fakeNode->subType() == FakeNode::Example) + if (fakeNode->subType() == Node::Example) continue; // not interested either in individual (Qt Designer etc.) manual chapters @@ -1992,7 +2311,7 @@ void HtmlGenerator::generateOverviewList(const Node *relative, CodeMarker * /* m continue; // Discard external nodes. - if (fakeNode->subType() == FakeNode::ExternalPage) + if (fakeNode->subType() == Node::ExternalPage) continue; QString sortKey = fakeNode->fullTitle().toLower(); @@ -2017,7 +2336,8 @@ void HtmlGenerator::generateOverviewList(const Node *relative, CodeMarker * /* m groupTitlesMap[fakeNode->fullTitle()] = const_cast<const FakeNode *>(fakeNode); } } - } else if (!isGroupPage) { + } + else if (!isGroupPage) { // If we encounter a page that belongs to a group then // we add that page to the list for that group. const FakeNode *groupNode = static_cast<const FakeNode *>(tre->root()->findNode(group, Node::Fake)); @@ -2075,21 +2395,100 @@ void HtmlGenerator::generateOverviewList(const Node *relative, CodeMarker * /* m } } -void HtmlGenerator::generateSectionList(const Section& section, const Node *relative, - CodeMarker *marker, CodeMarker::SynopsisStyle style) +#ifdef QDOC_NAME_ALIGNMENT +void HtmlGenerator::generateSection(const NodeList& nl, + const Node *relative, + CodeMarker *marker, + CodeMarker::SynopsisStyle style) +{ + bool name_alignment = true; + if (!nl.isEmpty()) { + bool twoColumn = false; + if (style == CodeMarker::SeparateList) { + name_alignment = false; + twoColumn = (nl.count() >= 16); + } + else if (nl.first()->type() == Node::Property) { + twoColumn = (nl.count() >= 5); + name_alignment = false; + } + if (name_alignment) { + out() << "<table class=\"alignedsummary\" border=\"0\" cellpadding=\"0\" " + << "cellspacing=\"0\" width=\"100%\">\n"; + } + else { + if (twoColumn) + out() << "<p><table class=\"propsummary\" width=\"100%\" " + << "border=\"0\" cellpadding=\"0\"" + << " cellspacing=\"0\">\n" + << "<tr><td width=\"45%\" valign=\"top\">"; + out() << "<ul>\n"; + } + + int i = 0; + NodeList::ConstIterator m = nl.begin(); + while (m != nl.end()) { + if ((*m)->access() == Node::Private) { + ++m; + continue; + } + + if (name_alignment) { + out() << "<tr><td class=\"memItemLeft\" " + << "align=\"right\" valign=\"top\">"; + } + else { + if (twoColumn && i == (int) (nl.count() + 1) / 2) + out() << "</ul></td><td valign=\"top\"><ul>\n"; + out() << "<li><div class=\"fn\">"; + } + + generateSynopsis(*m, relative, marker, style, name_alignment); + if (name_alignment) + out() << "</td></tr>\n"; + else + out() << "</div></li>\n"; + i++; + ++m; + } + if (name_alignment) + out() << "</table>\n"; + else { + out() << "</ul>\n"; + if (twoColumn) + out() << "</td></tr>\n</table></p>\n"; + } + } +} + +void HtmlGenerator::generateSectionList(const Section& section, + const Node *relative, + CodeMarker *marker, + CodeMarker::SynopsisStyle style) { + bool name_alignment = true; if (!section.members.isEmpty()) { bool twoColumn = false; if (style == CodeMarker::SeparateList) { + name_alignment = false; twoColumn = (section.members.count() >= 16); - } else if (section.members.first()->type() == Node::Property) { + } + else if (section.members.first()->type() == Node::Property) { twoColumn = (section.members.count() >= 5); + name_alignment = false; + } + if (name_alignment) { + out() << "<table class=\"alignedsummary\" border=\"0\" cellpadding=\"0\" " + << "cellspacing=\"0\" width=\"100%\">\n"; + } + else { + if (twoColumn) + out() << "<p><table class=\"propsummary\" width=\"100%\" " + << "border=\"0\" cellpadding=\"0\"" + << " cellspacing=\"0\">\n" + << "<tr><td width=\"45%\" valign=\"top\">"; + out() << "<ul>\n"; } - if (twoColumn) - out() << "<p><table width=\"100%\" border=\"0\" cellpadding=\"0\"" - " cellspacing=\"0\">\n" - << "<tr><td width=\"45%\" valign=\"top\">"; - out() << "<ul>\n"; int i = 0; NodeList::ConstIterator m = section.members.begin(); @@ -2099,41 +2498,56 @@ void HtmlGenerator::generateSectionList(const Section& section, const Node *rela continue; } - if (twoColumn && i == (int) (section.members.count() + 1) / 2) - out() << "</ul></td><td valign=\"top\"><ul>\n"; + if (name_alignment) { + out() << "<tr><td class=\"memItemLeft\" " + << "align=\"right\" valign=\"top\">"; + } + else { + if (twoColumn && i == (int) (section.members.count() + 1) / 2) + out() << "</ul></td><td valign=\"top\"><ul>\n"; + out() << "<li><div class=\"fn\">"; + } - out() << "<li><div class=\"fn\"></div>"; - if (style == CodeMarker::Accessors) - out() << "<b>"; - generateSynopsis(*m, relative, marker, style); - if (style == CodeMarker::Accessors) - out() << "</b>"; - out() << "</li>\n"; + generateSynopsis(*m, relative, marker, style, name_alignment); + if (name_alignment) + out() << "</td></tr>\n"; + else + out() << "</div></li>\n"; i++; ++m; } - out() << "</ul>\n"; - if (twoColumn) - out() << "</td></tr>\n</table></p>\n"; + if (name_alignment) + out() << "</table>\n"; + else { + out() << "</ul>\n"; + if (twoColumn) + out() << "</td></tr>\n</table></p>\n"; + } } if (style == CodeMarker::Summary && !section.inherited.isEmpty()) { out() << "<ul>\n"; - generateSectionInheritedList(section, relative, marker); + generateSectionInheritedList(section, relative, marker, name_alignment); out() << "</ul>\n"; } } -void HtmlGenerator::generateSectionInheritedList(const Section& section, const Node *relative, - CodeMarker *marker) +void HtmlGenerator::generateSectionInheritedList(const Section& section, + const Node *relative, + CodeMarker *marker, + bool nameAlignment) { QList<QPair<ClassNode *, int> >::ConstIterator p = section.inherited.begin(); while (p != section.inherited.end()) { - out() << "<li><div class=\"fn\"></div>"; + if (nameAlignment) + out() << "<li><div bar=\"2\" class=\"fn\"></div>"; + else + out() << "<li><div class=\"fn\"></div>"; out() << (*p).second << " "; if ((*p).second == 1) { out() << section.singularMember; - } else { + } + else { out() << section.pluralMember; } out() << " inherited from <a href=\"" << fileName((*p).first) @@ -2144,270 +2558,324 @@ void HtmlGenerator::generateSectionInheritedList(const Section& section, const N } } -void HtmlGenerator::generateLink(const Atom *atom, const Node * /* relative */, CodeMarker *marker) +void HtmlGenerator::generateSynopsis(const Node *node, + const Node *relative, + CodeMarker *marker, + CodeMarker::SynopsisStyle style, + bool nameAlignment) { - static QRegExp camelCase("[A-Z][A-Z][a-z]|[a-z][A-Z0-9]|_"); - - if (funcLeftParen.indexIn(atom->string()) != -1 && marker->recognizeLanguage("Cpp")) { - // hack for C++: move () outside of link - int k = funcLeftParen.pos(1); - out() << protect(atom->string().left(k)); - if (link.isEmpty()) { - if (showBrokenLinks) - out() << "</i>"; - } else { - out() << "</a>"; - } - inLink = false; - out() << protect(atom->string().mid(k)); - } else if (marker->recognizeLanguage("Java")) { - // hack for Java: remove () and use <tt> when appropriate - bool func = atom->string().endsWith("()"); - bool tt = (func || atom->string().contains(camelCase)); - if (tt) - out() << "<tt>"; - if (func) { - out() << protect(atom->string().left(atom->string().length() - 2)); - } else { - out() << protect(atom->string()); - } - out() << "</tt>"; - } else { - out() << protect(atom->string()); + QString marked = marker->markedUpSynopsis(node, relative, style); + QRegExp templateTag("(<[^@>]*>)"); + if (marked.indexOf(templateTag) != -1) { + QString contents = protect(marked.mid(templateTag.pos(1), + templateTag.cap(1).length())); + marked.replace(templateTag.pos(1), templateTag.cap(1).length(), + contents); } -} - -QString HtmlGenerator::cleanRef(const QString& ref) -{ - QString clean; - - if (ref.isEmpty()) - return clean; + marked.replace(QRegExp("<@param>([a-z]+)_([1-9n])</@param>"), + "<i>\\1<sub>\\2</sub></i>"); + marked.replace("<@param>", "<i>"); + marked.replace("</@param>", "</i>"); - clean.reserve(ref.size() + 20); - const QChar c = ref[0]; - const uint u = c.unicode(); + if (style == CodeMarker::Summary) { + marked.replace("<@name>", ""); // was "<b>" + marked.replace("</@name>", ""); // was "</b>" + } - if ((u >= 'a' && u <= 'z') || - (u >= 'A' && u <= 'Z') || - (u >= '0' && u <= '9')) { - clean += c; - } else if (u == '~') { - clean += "dtor."; - } else if (u == '_') { - clean += "underscore."; + if (style == CodeMarker::SeparateList) { + QRegExp extraRegExp("<@extra>.*</@extra>"); + extraRegExp.setMinimal(true); + marked.replace(extraRegExp, ""); } else { - clean += "A"; + marked.replace("<@extra>", " <tt>"); + marked.replace("</@extra>", "</tt>"); } - for (int i = 1; i < (int) ref.length(); i++) { - const QChar c = ref[i]; - const uint u = c.unicode(); - if ((u >= 'a' && u <= 'z') || - (u >= 'A' && u <= 'Z') || - (u >= '0' && u <= '9') || u == '-' || - u == '_' || u == ':' || u == '.') { - clean += c; - } else if (c.isSpace()) { - clean += "-"; - } else if (u == '!') { - clean += "-not"; - } else if (u == '&') { - clean += "-and"; - } else if (u == '<') { - clean += "-lt"; - } else if (u == '=') { - clean += "-eq"; - } else if (u == '>') { - clean += "-gt"; - } else if (u == '#') { - clean += "#"; - } else { - clean += "-"; - clean += QString::number((int)u, 16); - } + if (style != CodeMarker::Detailed) { + marked.replace("<@type>", ""); + marked.replace("</@type>", ""); } - return clean; + out() << highlightedCode(marked, marker, relative, style, nameAlignment); } -QString HtmlGenerator::registerRef(const QString& ref) +QString HtmlGenerator::highlightedCode(const QString& markedCode, + CodeMarker *marker, + const Node *relative, + CodeMarker::SynopsisStyle , + bool nameAlignment) { - QString clean = HtmlGenerator::cleanRef(ref); + QString src = markedCode; + QString html; + QStringRef arg; + QStringRef par1; - for (;;) { - QString& prevRef = refMap[clean.toLower()]; - if (prevRef.isEmpty()) { - prevRef = ref; - break; - } else if (prevRef == ref) { - break; + const QChar charLangle = '<'; + const QChar charAt = '@'; + + // replace all <@link> tags: "(<@link node=\"([^\"]+)\">).*(</@link>)" + static const QString linkTag("link"); + bool done = false; + for (int i = 0, n = src.size(); i < n;) { + if (src.at(i) == charLangle && src.at(i + 1).unicode() == '@') { + if (nameAlignment && !done) {// && (i != 0)) Why was this here? + html += "</td><td class=\"memItemRight\" valign=\"bottom\">"; + done = true; + } + i += 2; + if (parseArg(src, linkTag, &i, n, &arg, &par1)) { + html += "<b>"; + QString link = linkForNode( + CodeMarker::nodeForString(par1.toString()), relative); + addLink(link, arg, &html); + html += "</b>"; + } + else { + html += charLangle; + html += charAt; + } + } + else { + html += src.at(i++); } - clean += "x"; } - return clean; -} - -QString HtmlGenerator::protect(const QString& string) -{ -#define APPEND(x) \ - if (html.isEmpty()) { \ - html = string; \ - html.truncate(i); \ - } \ - html += (x); - QString html; - int n = string.length(); - for (int i = 0; i < n; ++i) { - QChar ch = string.at(i); + if (slow) { + // is this block ever used at all? + // replace all <@func> tags: "(<@func target=\"([^\"]*)\">)(.*)(</@func>)" + src = html; + html = QString(); + static const QString funcTag("func"); + for (int i = 0, n = src.size(); i < n;) { + if (src.at(i) == charLangle && src.at(i + 1) == charAt) { + i += 2; + if (parseArg(src, funcTag, &i, n, &arg, &par1)) { + QString link = linkForNode( + marker->resolveTarget(par1.toString(), + tre, + relative), + relative); + addLink(link, arg, &html); + par1 = QStringRef(); + } + else { + html += charLangle; + html += charAt; + } + } + else { + html += src.at(i++); + } + } + } - if (ch == QLatin1Char('&')) { - APPEND("&"); - } else if (ch == QLatin1Char('<')) { - APPEND("<"); - } else if (ch == QLatin1Char('>')) { - APPEND(">"); - } else if (ch == QLatin1Char('"')) { - APPEND("""); - } else if (ch.unicode() > 0x007F - || (ch == QLatin1Char('*') && i + 1 < n && string.at(i) == QLatin1Char('/')) - || (ch == QLatin1Char('.') && i > 2 && string.at(i - 2) == QLatin1Char('.'))) { - // we escape '*/' and the last dot in 'e.g.' and 'i.e.' for the Javadoc generator - APPEND("&#x"); - html += QString::number(ch.unicode(), 16); - html += QLatin1Char(';'); - } else { - if (!html.isEmpty()) - html += ch; + // replace all "(<@(type|headerfile|func)(?: +[^>]*)?>)(.*)(</@\\2>)" tags + src = html; + html = QString(); + static const QString typeTags[] = { "type", "headerfile", "func" }; + for (int i = 0, n = src.size(); i < n;) { + if (src.at(i) == charLangle && src.at(i + 1) == charAt) { + i += 2; + bool handled = false; + for (int k = 0; k != 3; ++k) { + if (parseArg(src, typeTags[k], &i, n, &arg, &par1)) { + par1 = QStringRef(); + QString link = linkForNode( + marker->resolveTarget(arg.toString(), tre, relative), + relative); + addLink(link, arg, &html); + handled = true; + break; + } + } + if (!handled) { + html += charLangle; + html += charAt; + } + } + else { + html += src.at(i++); } } - if (!html.isEmpty()) - return html; - return string; + // replace all + // "<@comment>" -> "<span class=\"comment\">"; + // "<@preprocessor>" -> "<span class=\"preprocessor\">"; + // "<@string>" -> "<span class=\"string\">"; + // "<@char>" -> "<span class=\"char\">"; + // "</@(?:comment|preprocessor|string|char)>" -> "</span>" + src = html; + html = QString(); + static const QString spanTags[] = { + "<@comment>", "<span class=\"comment\">", + "<@preprocessor>", "<span class=\"preprocessor\">", + "<@string>", "<span class=\"string\">", + "<@char>", "<span class=\"char\">", + "</@comment>", "</span>", + "</@preprocessor>","</span>", + "</@string>", "</span>", + "</@char>", "</span>" + // "<@char>", "<font color=blue>", + // "</@char>", "</font>", + // "<@func>", "<font color=green>", + // "</@func>", "</font>", + // "<@id>", "<i>", + // "</@id>", "</i>", + // "<@keyword>", "<b>", + // "</@keyword>", "</b>", + // "<@number>", "<font color=yellow>", + // "</@number>", "</font>", + // "<@op>", "<b>", + // "</@op>", "</b>", + // "<@param>", "<i>", + // "</@param>", "</i>", + // "<@string>", "<font color=green>", + // "</@string>", "</font>", + }; + for (int i = 0, n = src.size(); i < n;) { + if (src.at(i) == charLangle) { + bool handled = false; + for (int k = 0; k != 8; ++k) { + const QString & tag = spanTags[2 * k]; + if (tag == QStringRef(&src, i, tag.length())) { + html += spanTags[2 * k + 1]; + i += tag.length(); + handled = true; + break; + } + } + if (!handled) { + ++i; + if (src.at(i) == charAt || + (src.at(i) == QLatin1Char('/') && src.at(i + 1) == charAt)) { + // drop 'our' unknown tags (the ones still containing '@') + while (i < n && src.at(i) != QLatin1Char('>')) + ++i; + ++i; + } + else { + // retain all others + html += charLangle; + } + } + } + else { + html += src.at(i); + ++i; + } + } -#undef APPEND + return html; } -static QRegExp linkTag("(<@link node=\"([^\"]+)\">).*(</@link>)"); -static QRegExp funcTag("(<@func target=\"([^\"]*)\">)(.*)(</@func>)"); -static QRegExp typeTag("(<@(type|headerfile|func)(?: +[^>]*)?>)(.*)(</@\\2>)"); -static QRegExp spanTag("</@(?:comment|preprocessor|string|char)>"); -static QRegExp unknownTag("</?@[^>]*>"); - -bool parseArg(const QString &src, - const QString &tag, - int *pos, - int n, - QStringRef *contents, - QStringRef *par1 = 0, - bool debug = false) +#else +void HtmlGenerator::generateSectionList(const Section& section, + const Node *relative, + CodeMarker *marker, + CodeMarker::SynopsisStyle style) { -#define SKIP_CHAR(c) \ - if (debug) \ - qDebug() << "looking for " << c << " at " << QString(src.data() + i, n - i); \ - if (i >= n || src[i] != c) { \ - if (debug) \ - qDebug() << " char '" << c << "' not found"; \ - return false; \ - } \ - ++i; - - -#define SKIP_SPACE \ - while (i < n && src[i] == ' ') \ - ++i; + if (!section.members.isEmpty()) { + bool twoColumn = false; + if (style == CodeMarker::SeparateList) { + twoColumn = (section.members.count() >= 16); + } + else if (section.members.first()->type() == Node::Property) { + twoColumn = (section.members.count() >= 5); + } + if (twoColumn) + out() << "<p><table class=\"generic\" width=\"100%\" border=\"0\" " + << "cellpadding=\"0\" cellspacing=\"0\">\n" + << "<tr><td width=\"45%\" valign=\"top\">"; + out() << "<ul>\n"; - int i = *pos; - int j = i; + int i = 0; + NodeList::ConstIterator m = section.members.begin(); + while (m != section.members.end()) { + if ((*m)->access() == Node::Private) { + ++m; + continue; + } - // assume "<@" has been parsed outside - //SKIP_CHAR('<'); - //SKIP_CHAR('@'); + if (twoColumn && i == (int) (section.members.count() + 1) / 2) + out() << "</ul></td><td valign=\"top\"><ul>\n"; - if (tag != QStringRef(&src, i, tag.length())) { - if (0 && debug) - qDebug() << "tag " << tag << " not found at " << i; - return false; + out() << "<li><div class=\"fn\"></div>"; + if (style == CodeMarker::Accessors) + out() << "<b>"; + generateSynopsis(*m, relative, marker, style); + if (style == CodeMarker::Accessors) + out() << "</b>"; + out() << "</li>\n"; + i++; + ++m; + } + out() << "</ul>\n"; + if (twoColumn) + out() << "</td></tr>\n</table></p>\n"; } - if (debug) - qDebug() << "haystack:" << src << "needle:" << tag << "i:" <<i; - - // skip tag - i += tag.length(); + if (style == CodeMarker::Summary && !section.inherited.isEmpty()) { + out() << "<ul>\n"; + generateSectionInheritedList(section, relative, marker); + out() << "</ul>\n"; + } +} - // parse stuff like: linkTag("(<@link node=\"([^\"]+)\">).*(</@link>)"); - if (par1) { - SKIP_SPACE; - // read parameter name - j = i; - while (i < n && src[i].isLetter()) - ++i; - if (src[i] == '=') { - if (debug) - qDebug() << "read parameter" << QString(src.data() + j, i - j); - SKIP_CHAR('='); - SKIP_CHAR('"'); - // skip parameter name - j = i; - while (i < n && src[i] != '"') - ++i; - *par1 = QStringRef(&src, j, i - j); - SKIP_CHAR('"'); - SKIP_SPACE; +void HtmlGenerator::generateSectionInheritedList(const Section& section, + const Node *relative, + CodeMarker *marker) +{ + QList<QPair<ClassNode *, int> >::ConstIterator p = section.inherited.begin(); + while (p != section.inherited.end()) { + out() << "<li><div bar=\"2\" class=\"fn\"></div>"; + out() << (*p).second << " "; + if ((*p).second == 1) { + out() << section.singularMember; } else { - if (debug) - qDebug() << "no optional parameter found"; + out() << section.pluralMember; } + out() << " inherited from <a href=\"" << fileName((*p).first) + << "#" << HtmlGenerator::cleanRef(section.name.toLower()) << "\">" + << protect(marker->plainFullName((*p).first, relative)) + << "</a></li>\n"; + ++p; } - SKIP_SPACE; - SKIP_CHAR('>'); +} - // find contents up to closing "</@tag> - j = i; - for (; true; ++i) { - if (i + 4 + tag.length() > n) - return false; - if (src[i] != '<') - continue; - if (src[i + 1] != '/') - continue; - if (src[i + 2] != '@') - continue; - if (tag != QStringRef(&src, i + 3, tag.length())) - continue; - if (src[i + 3 + tag.length()] != '>') - continue; - break; +void HtmlGenerator::generateSynopsis(const Node *node, + const Node *relative, + CodeMarker *marker, + CodeMarker::SynopsisStyle style) +{ + QString marked = marker->markedUpSynopsis(node, relative, style); + QRegExp templateTag("(<[^@>]*>)"); + if (marked.indexOf(templateTag) != -1) { + QString contents = protect(marked.mid(templateTag.pos(1), + templateTag.cap(1).length())); + marked.replace(templateTag.pos(1), templateTag.cap(1).length(), + contents); } + marked.replace(QRegExp("<@param>([a-z]+)_([1-9n])</@param>"), "<i>\\1<sub>\\2</sub></i>"); + marked.replace("<@param>", "<i>"); + marked.replace("</@param>", "</i>"); - *contents = QStringRef(&src, j, i - j); - - i += tag.length() + 4; - - *pos = i; - if (debug) - qDebug() << " tag " << tag << " found: pos now: " << i; - return true; -#undef SKIP_CHAR -} + if (style == CodeMarker::Summary) + marked.replace("@name>", "b>"); -static void addLink(const QString &linkTarget, - const QStringRef &nestedStuff, - QString *res) -{ - if (!linkTarget.isEmpty()) { - *res += "<a href=\""; - *res += linkTarget; - *res += "\">"; - *res += nestedStuff; - *res += "</a>"; + if (style == CodeMarker::SeparateList) { + QRegExp extraRegExp("<@extra>.*</@extra>"); + extraRegExp.setMinimal(true); + marked.replace(extraRegExp, ""); + } else { + marked.replace("<@extra>", " <tt>"); + marked.replace("</@extra>", "</tt>"); } - else { - *res += nestedStuff; + + if (style != CodeMarker::Detailed) { + marked.replace("<@type>", ""); + marked.replace("</@type>", ""); } + out() << highlightedCode(marked, marker, relative); } QString HtmlGenerator::highlightedCode(const QString& markedCode, @@ -2428,8 +2896,8 @@ QString HtmlGenerator::highlightedCode(const QString& markedCode, if (src.at(i) == charLangle && src.at(i + 1) == charAt) { i += 2; if (parseArg(src, linkTag, &i, n, &arg, &par1)) { - QString link = linkForNode( - CodeMarker::nodeForString(par1.toString()), relative); + const Node* node = CodeMarker::nodeForString(par1.toString()); + QString link = linkForNode(node, relative); addLink(link, arg, &html); } else { @@ -2442,7 +2910,6 @@ QString HtmlGenerator::highlightedCode(const QString& markedCode, } } - if (slow) { // is this block ever used at all? // replace all <@func> tags: "(<@func target=\"([^\"]*)\">)(.*)(</@func>)" @@ -2570,6 +3037,155 @@ QString HtmlGenerator::highlightedCode(const QString& markedCode, return html; } +#endif + +void HtmlGenerator::generateLink(const Atom* atom, + const Node* /* relative */, + CodeMarker* marker) +{ + static QRegExp camelCase("[A-Z][A-Z][a-z]|[a-z][A-Z0-9]|_"); + + if (funcLeftParen.indexIn(atom->string()) != -1 && marker->recognizeLanguage("Cpp")) { + // hack for C++: move () outside of link + int k = funcLeftParen.pos(1); + out() << protect(atom->string().left(k)); + if (link.isEmpty()) { + if (showBrokenLinks) + out() << "</i>"; + } else { + out() << "</a>"; + } + inLink = false; + out() << protect(atom->string().mid(k)); + } else if (marker->recognizeLanguage("Java")) { + // hack for Java: remove () and use <tt> when appropriate + bool func = atom->string().endsWith("()"); + bool tt = (func || atom->string().contains(camelCase)); + if (tt) + out() << "<tt>"; + if (func) { + out() << protect(atom->string().left(atom->string().length() - 2)); + } else { + out() << protect(atom->string()); + } + out() << "</tt>"; + } else { + out() << protect(atom->string()); + } +} + +QString HtmlGenerator::cleanRef(const QString& ref) +{ + QString clean; + + if (ref.isEmpty()) + return clean; + + clean.reserve(ref.size() + 20); + const QChar c = ref[0]; + const uint u = c.unicode(); + + if ((u >= 'a' && u <= 'z') || + (u >= 'A' && u <= 'Z') || + (u >= '0' && u <= '9')) { + clean += c; + } else if (u == '~') { + clean += "dtor."; + } else if (u == '_') { + clean += "underscore."; + } else { + clean += "A"; + } + + for (int i = 1; i < (int) ref.length(); i++) { + const QChar c = ref[i]; + const uint u = c.unicode(); + if ((u >= 'a' && u <= 'z') || + (u >= 'A' && u <= 'Z') || + (u >= '0' && u <= '9') || u == '-' || + u == '_' || u == ':' || u == '.') { + clean += c; + } else if (c.isSpace()) { + clean += "-"; + } else if (u == '!') { + clean += "-not"; + } else if (u == '&') { + clean += "-and"; + } else if (u == '<') { + clean += "-lt"; + } else if (u == '=') { + clean += "-eq"; + } else if (u == '>') { + clean += "-gt"; + } else if (u == '#') { + clean += "#"; + } else { + clean += "-"; + clean += QString::number((int)u, 16); + } + } + return clean; +} + +QString HtmlGenerator::registerRef(const QString& ref) +{ + QString clean = HtmlGenerator::cleanRef(ref); + + for (;;) { + QString& prevRef = refMap[clean.toLower()]; + if (prevRef.isEmpty()) { + prevRef = ref; + break; + } else if (prevRef == ref) { + break; + } + clean += "x"; + } + return clean; +} + +QString HtmlGenerator::protect(const QString& string) +{ +#define APPEND(x) \ + if (html.isEmpty()) { \ + html = string; \ + html.truncate(i); \ + } \ + html += (x); + + QString html; + int n = string.length(); + + for (int i = 0; i < n; ++i) { + QChar ch = string.at(i); + + if (ch == QLatin1Char('&')) { + APPEND("&"); + } else if (ch == QLatin1Char('<')) { + APPEND("<"); + } else if (ch == QLatin1Char('>')) { + APPEND(">"); + } else if (ch == QLatin1Char('"')) { + APPEND("""); + } else if (ch.unicode() > 0x007F + || (ch == QLatin1Char('*') && i + 1 < n && string.at(i) == QLatin1Char('/')) + || (ch == QLatin1Char('.') && i > 2 && string.at(i - 2) == QLatin1Char('.'))) { + // we escape '*/' and the last dot in 'e.g.' and 'i.e.' for the Javadoc generator + APPEND("&#x"); + html += QString::number(ch.unicode(), 16); + html += QLatin1Char(';'); + } else { + if (!html.isEmpty()) + html += ch; + } + } + + if (!html.isEmpty()) + return html; + return string; + +#undef APPEND +} QString HtmlGenerator::fileBase(const Node *node) { @@ -2618,10 +3234,9 @@ QString HtmlGenerator::fileBase(const Node *node, QString HtmlGenerator::fileName(const Node *node) { if (node->type() == Node::Fake) { - if (static_cast<const FakeNode *>(node)->subType() == FakeNode::ExternalPage) + if (static_cast<const FakeNode *>(node)->subType() == Node::ExternalPage) return node->name(); } - return PageGenerator::fileName(node); } @@ -2643,7 +3258,8 @@ QString HtmlGenerator::refForNode(const Node *node) typedeffe = static_cast<const TypedefNode *>(node); if (typedeffe->associatedEnum()) { return refForNode(typedeffe->associatedEnum()); - } else { + } + else { ref = node->name() + "-typedef"; } break; @@ -2651,15 +3267,27 @@ QString HtmlGenerator::refForNode(const Node *node) func = static_cast<const FunctionNode *>(node); if (func->associatedProperty()) { return refForNode(func->associatedProperty()); - } else { + } + else { ref = func->name(); if (func->overloadNumber() != 1) ref += "-" + QString::number(func->overloadNumber()); } break; case Node::Property: +#ifdef QDOC_QML + case Node::QmlProperty: +#endif ref = node->name() + "-prop"; break; +#ifdef QDOC_QML + case Node::QmlSignal: + ref = node->name() + "-signal"; + break; + case Node::QmlMethod: + ref = node->name() + "-method"; + break; +#endif case Node::Variable: ref = node->name() + "-var"; break; @@ -2708,9 +3336,11 @@ QString HtmlGenerator::refForAtom(Atom *atom, const Node * /* node */) { if (atom->type() == Atom::SectionLeft) { return Doc::canonicalTitle(Text::sectionHeading(atom).toString()); - } else if (atom->type() == Atom::Target) { + } + else if (atom->type() == Atom::Target) { return Doc::canonicalTitle(atom->string()); - } else { + } + else { return QString(); } } @@ -2754,7 +3384,10 @@ void HtmlGenerator::generateDetailedMember(const Node *node, out() << "<a name=\"" + refForNode(node) + "\"></a>"; generateSynopsis(enume, relative, marker, CodeMarker::Detailed); out() << "<br />"; - generateSynopsis(enume->flagsType(), relative, marker, CodeMarker::Detailed); + generateSynopsis(enume->flagsType(), + relative, + marker, + CodeMarker::Detailed); out() << "</h3>\n"; } else { @@ -2778,7 +3411,7 @@ void HtmlGenerator::generateDetailedMember(const Node *node, section.members += property->resetters(); if (!section.members.isEmpty()) { - out() << "<p>Access functions:</p>\n"; + out() << "<p><b>Access functions:</b></p>\n"; generateSectionList(section, node, marker, CodeMarker::Accessors); } } @@ -2789,7 +3422,8 @@ void HtmlGenerator::generateDetailedMember(const Node *node, << " type is a typedef for " << "<a href=\"qflags.html\">QFlags</a><" << protect(enume->name()) - << ">. It stores an OR combination of " << protect(enume->name()) + << ">. It stores an OR combination of " + << protect(enume->name()) << " values.</p>\n"; } } @@ -2803,7 +3437,8 @@ void HtmlGenerator::findAllClasses(const InnerNode *node) if ((*c)->access() != Node::Private && (*c)->url().isEmpty()) { if ((*c)->type() == Node::Class && !(*c)->doc().isEmpty()) { QString className = (*c)->name(); - if ((*c)->parent() && (*c)->parent()->type() == Node::Namespace && + if ((*c)->parent() && + (*c)->parent()->type() == Node::Namespace && !(*c)->parent()->name().isEmpty()) className = (*c)->parent()->name()+"::"+className; @@ -2811,6 +3446,9 @@ void HtmlGenerator::findAllClasses(const InnerNode *node) if ((*c)->status() == Node::Compat) { compatClasses.insert(className, *c); } + else if ((*c)->status() == Node::Obsolete) { + obsoleteClasses.insert(className, *c); + } else { nonCompatClasses.insert(className, *c); if ((*c)->status() == Node::Main) @@ -2851,7 +3489,7 @@ void HtmlGenerator::findAllFunctions(const InnerNode *node) const FunctionNode *func = static_cast<const FunctionNode *>(*c); if (func->status() > Node::Obsolete && func->metaness() != FunctionNode::Ctor && func->metaness() != FunctionNode::Dtor) { - funcIndex[(*c)->name()].insert((*c)->parent()->name(), *c); + funcIndex[(*c)->name()].insert(tre->fullDocumentName((*c)->parent()), *c); } } } @@ -2901,7 +3539,7 @@ void HtmlGenerator::findAllNamespaces(const InnerNode *node) } } -#ifdef ZZZ_QDOC_QML +#ifdef ZZZ_QDOC_QML /*! This function finds all the qml element nodes and stores them in a map for later use. @@ -2912,24 +3550,16 @@ void HtmlGenerator::findAllQmlClasses(const InnerNode *node) while (c != node->childNodes().constEnd()) { if ((*c)->type() == Node::Fake) { const FakeNode* fakeNode = static_cast<const FakeNode *>(*c); - if (fakeNode->subType() == FakeNode::QmlClass) { - const QmlNode* qmlNode = static_cast<const QmlNode*>(fakeNode); - //qDebug() << "HtmlGenerator: QML CLASS" << qmlNode->name(); + if (fakeNode->subType() == Node::QmlClass) { + const QmlClassNode* qmlNode = + static_cast<const QmlClassNode*>(fakeNode); const Node* n = qmlNode->classNode(); - if (n) - //qDebug() << " FOUND IT!" << n->name(); } qmlClasses.insert(fakeNode->name(),*c); } ++c; } } -#endif - -#if 0 - else if ((*c)->isInnerNode()) { - findAllClasses(static_cast<InnerNode *>(*c)); - } #endif int HtmlGenerator::hOffset(const Node *node) @@ -3007,10 +3637,11 @@ const QPair<QString,QString> HtmlGenerator::anchorForNode(const Node *node) QString HtmlGenerator::getLink(const Atom *atom, const Node *relative, CodeMarker *marker, - const Node *node) + const Node** node) { QString link; - node = 0; + *node = 0; + inObsoleteLink = false; if (atom->string().contains(":") && (atom->string().startsWith("file:") @@ -3034,40 +3665,86 @@ QString HtmlGenerator::getLink(const Atom *atom, QString first = path.first().trimmed(); if (first.isEmpty()) { - node = relative; + *node = relative; } else if (first.endsWith(".html")) { - node = tre->root()->findNode(first, Node::Fake); + *node = tre->root()->findNode(first, Node::Fake); } else { - node = marker->resolveTarget(first, tre, relative); - if (!node) - node = tre->findFakeNodeByTitle(first); - if (!node) - node = tre->findUnambiguousTarget(first, targetAtom); + *node = marker->resolveTarget(first, tre, relative); + if (!*node) + *node = tre->findFakeNodeByTitle(first); + if (!*node) + *node = tre->findUnambiguousTarget(first, targetAtom); } - if (node) { - if (!node->url().isEmpty()) - return node->url(); + if (*node) { + if (!(*node)->url().isEmpty()) + return (*node)->url(); else path.removeFirst(); } else { - node = relative; + *node = relative; + } + + if (*node) { + if ((*node)->status() == Node::Obsolete) { + if (relative) { + if (relative->parent() != *node) { + if (relative->status() != Node::Obsolete) { + bool porting = false; + if (relative->type() == Node::Fake) { + const FakeNode* fake = static_cast<const FakeNode*>(relative); + if (fake->title().startsWith("Porting")) + porting = true; + } + QString name = marker->plainFullName(relative); + if (!porting && !name.startsWith("Q3")) { + if (obsoleteLinks) { + relative->doc().location().warning(tr("Link to obsolete item '%1' in %2") + .arg(atom->string()) + .arg(name)); + } + inObsoleteLink = true; + } +#if 0 + qDebug() << "Link to Obsolete entity" + << (*node)->name(); + qDebug() << " relative entity" + << relative->name(); +#endif + } + } + } + else { + qDebug() << "Link to Obsolete entity" + << (*node)->name() << "no relative"; + } + } +#if 0 + else if ((*node)->status() == Node::Deprecated) { + qDebug() << "Link to Deprecated entity"; + } + else if ((*node)->status() == Node::Internal) { + qDebug() << "Link to Internal entity"; + } + //else + //qDebug() << "Node Status:" << (*node)->status(); +#endif } while (!path.isEmpty()) { - targetAtom = tre->findTarget(path.first(), node); + targetAtom = tre->findTarget(path.first(), *node); if (targetAtom == 0) break; path.removeFirst(); } if (path.isEmpty()) { - link = linkForNode(node, relative); + link = linkForNode(*node, relative); if (targetAtom) - link += "#" + refForAtom(targetAtom, node); + link += "#" + refForAtom(targetAtom, *node); } } return link; @@ -3186,10 +3863,225 @@ void HtmlGenerator::endLink() out() << "</i>"; } else { + if (inObsoleteLink) { + out() << "<sup>(obsolete)</sup>"; + } out() << "</a>"; } } inLink = false; + inObsoleteLink = false; } QT_END_NAMESPACE + +#ifdef QDOC_QML + +/*! + Generates the summary for for the \a section. Only used for + sections of QML element documentation. + + Currently handles only the QML property group. + */ +void HtmlGenerator::generateQmlSummary(const Section& section, + const Node *relative, + CodeMarker *marker) +{ + if (!section.members.isEmpty()) { + NodeList::ConstIterator m; + int count = section.members.size(); + bool twoColumn = false; + if (section.members.first()->type() == Node::QmlProperty) { + twoColumn = (count >= 5); + } + if (twoColumn) + out() << "<p><table width=\"100%\" border=\"0\" cellpadding=\"0\"" + " cellspacing=\"0\">\n" + << "<tr><td width=\"45%\" valign=\"top\">"; + out() << "<ul>\n"; + + int row = 0; + m = section.members.begin(); + while (m != section.members.end()) { + if (twoColumn && row == (int) (count + 1) / 2) + out() << "</ul></td><td valign=\"top\"><ul>\n"; + out() << "<li><div class=\"fn\"></div>"; + generateQmlItem(*m,relative,marker,true); + out() << "</li>\n"; + row++; + ++m; + } + out() << "</ul>\n"; + if (twoColumn) + out() << "</td></tr>\n</table></p>\n"; + } +} + +/*! + Outputs the html detailed documentation for a section + on a QML element reference page. + */ +void HtmlGenerator::generateDetailedQmlMember(const Node *node, + const InnerNode *relative, + CodeMarker *marker) +{ + const QmlPropertyNode* qpn = 0; + generateMacRef(node, marker); + out() << "<div class=\"qmlitem\">"; + if (node->subType() == Node::QmlPropertyGroup) { + const QmlPropGroupNode* qpgn = static_cast<const QmlPropGroupNode*>(node); + NodeList::ConstIterator p = qpgn->childNodes().begin(); + out() << "<div class=\"qmlproto\">"; + out() << "<table class=\"qmlname\">"; + + while (p != qpgn->childNodes().end()) { + if ((*p)->type() == Node::QmlProperty) { + qpn = static_cast<const QmlPropertyNode*>(*p); + out() << "<tr><td>"; + out() << "<a name=\"" + refForNode(qpn) + "\"></a>"; + generateQmlItem(qpn, relative, marker, false); + out() << "</td></tr>"; + if (qpgn->isDefault()) { + out() << "</table>" + << "</div></div>" + << "<div class=\"qmlitem\">" + << "<div class=\"qmlproto\">" + << "<table class=\"qmlname\">" + << "<tr><td><font color=\"green\">" + << "default</font></td></tr>"; + } + } + ++p; + } + out() << "</table>"; + out() << "</div>"; + } + else if (node->type() == Node::QmlSignal) { + const QmlSignalNode* qsn = static_cast<const QmlSignalNode*>(node); + out() << "<div class=\"qmlproto\">"; + out() << "<table class=\"qmlname\">"; + out() << "<tr><td>"; + out() << "<a name=\"" + refForNode(qsn) + "\"></a>"; + generateQmlItem(qsn,relative,marker,false); + out() << "</td></tr>"; + out() << "</table>"; + out() << "</div>"; + } + else if (node->type() == Node::QmlMethod) { + const QmlMethodNode* qmn = static_cast<const QmlMethodNode*>(node); + out() << "<div class=\"qmlproto\">"; + out() << "<table class=\"qmlname\">"; + out() << "<tr><td>"; + out() << "<a name=\"" + refForNode(qmn) + "\"></a>"; + generateQmlItem(qmn,relative,marker,false); + out() << "</td></tr>"; + out() << "</table>"; + out() << "</div>"; + } + out() << "<div class=\"qmldoc\">"; + generateStatus(node, marker); + generateBody(node, marker); + generateThreadSafeness(node, marker); + generateSince(node, marker); + generateAlsoList(node, marker); + out() << "</div>"; + out() << "</div>"; +} + +/*! + Output the "Inherits" line for the QML element, + if there should be one. + */ +void HtmlGenerator::generateQmlInherits(const QmlClassNode* cn, + CodeMarker* marker) +{ + if (cn && !cn->links().empty()) { + if (cn->links().contains(Node::InheritsLink)) { + QPair<QString,QString> linkPair; + linkPair = cn->links()[Node::InheritsLink]; + QStringList strList(linkPair.first); + const Node* n = tre->findNode(strList,Node::Fake); + if (n && n->subType() == Node::QmlClass) { + const QmlClassNode* qcn = static_cast<const QmlClassNode*>(n); + out() << "<p style=\"text-align: center\">"; + Text text; + text << "[Inherits "; + text << Atom(Atom::LinkNode,CodeMarker::stringForNode(qcn)); + text << Atom(Atom::FormattingLeft, ATOM_FORMATTING_LINK); + text << Atom(Atom::String, linkPair.second); + text << Atom(Atom::FormattingRight, ATOM_FORMATTING_LINK); + text << "]"; + generateText(text, cn, marker); + out() << "</p>"; + } +// else +// qDebug() << "generateQmlInherits(): " +// << "Inherited element not documented -->" +// << linkPair.first; + } + } +} + +/*! + Output the "[Xxx instantiates the C++ class QFxXxx]" + line for the QML element, if there should be one. + + If there is no class node, or if the class node status + is set to Node::Internal, do nothing. + */ +void HtmlGenerator::generateQmlInstantiates(const QmlClassNode* qcn, + CodeMarker* marker) +{ + const ClassNode* cn = qcn->classNode(); + if (cn && (cn->status() != Node::Internal)) { + out() << "<p style=\"text-align: center\">"; + Text text; + text << "["; + text << Atom(Atom::LinkNode,CodeMarker::stringForNode(qcn)); + text << Atom(Atom::FormattingLeft, ATOM_FORMATTING_LINK); + text << Atom(Atom::String, qcn->name()); + text << Atom(Atom::FormattingRight, ATOM_FORMATTING_LINK); + text << " instantiates the C++ class "; + text << Atom(Atom::LinkNode,CodeMarker::stringForNode(cn)); + text << Atom(Atom::FormattingLeft, ATOM_FORMATTING_LINK); + text << Atom(Atom::String, cn->name()); + text << Atom(Atom::FormattingRight, ATOM_FORMATTING_LINK); + text << "]"; + generateText(text, qcn, marker); + out() << "</p>"; + } +} + +/*! + Output the "[QFxXxx is instantiated by QML element Xxx]" + line for the class, if there should be one. + + If there is no QML element, or if the class node status + is set to Node::Internal, do nothing. + */ +void HtmlGenerator::generateInstantiatedBy(const ClassNode* cn, + CodeMarker* marker) +{ + if (cn && cn->status() != Node::Internal && !cn->qmlElement().isEmpty()) { + const Node* n = tre->root()->findNode(cn->qmlElement(),Node::Fake); + if (n && n->subType() == Node::QmlClass) { + out() << "<p style=\"text-align: center\">"; + Text text; + text << "["; + text << Atom(Atom::LinkNode,CodeMarker::stringForNode(cn)); + text << Atom(Atom::FormattingLeft, ATOM_FORMATTING_LINK); + text << Atom(Atom::String, cn->name()); + text << Atom(Atom::FormattingRight, ATOM_FORMATTING_LINK); + text << " is instantiated by QML element "; + text << Atom(Atom::LinkNode,CodeMarker::stringForNode(n)); + text << Atom(Atom::FormattingLeft, ATOM_FORMATTING_LINK); + text << Atom(Atom::String, n->name()); + text << Atom(Atom::FormattingRight, ATOM_FORMATTING_LINK); + text << "]"; + generateText(text, cn, marker); + out() << "</p>"; + } + } +} + +#endif diff --git a/tools/qdoc3/htmlgenerator.h b/tools/qdoc3/htmlgenerator.h index 8ff32f8..c22fe20 100644 --- a/tools/qdoc3/htmlgenerator.h +++ b/tools/qdoc3/htmlgenerator.h @@ -46,6 +46,8 @@ #ifndef HTMLGENERATOR_H #define HTMLGENERATOR_H +#define QDOC_NAME_ALIGNMENT + #include <qmap.h> #include <qregexp.h> @@ -139,27 +141,69 @@ class HtmlGenerator : public PageGenerator void generateFunctionIndex(const Node *relative, CodeMarker *marker); void generateLegaleseList(const Node *relative, CodeMarker *marker); void generateOverviewList(const Node *relative, CodeMarker *marker); - void generateSynopsis(const Node *node, - const Node *relative, - CodeMarker *marker, - CodeMarker::SynopsisStyle style); void generateSectionList(const Section& section, const Node *relative, CodeMarker *marker, CodeMarker::SynopsisStyle style); +#ifdef QDOC_QML + void generateQmlSummary(const Section& section, + const Node *relative, + CodeMarker *marker); + void generateQmlItem(const Node *node, + const Node *relative, + CodeMarker *marker, + bool summary); + void generateDetailedQmlMember(const Node *node, + const InnerNode *relative, + CodeMarker *marker); + void generateQmlInherits(const QmlClassNode* cn, CodeMarker* marker); + void generateQmlInstantiates(const QmlClassNode* qcn, CodeMarker* marker); + void generateInstantiatedBy(const ClassNode* cn, CodeMarker* marker); +#endif +#ifdef QDOC_NAME_ALIGNMENT + void generateSection(const NodeList& nl, + const Node *relative, + CodeMarker *marker, + CodeMarker::SynopsisStyle style); + void generateSynopsis(const Node *node, + const Node *relative, + CodeMarker *marker, + CodeMarker::SynopsisStyle style, + bool nameAlignment = false); + void generateSectionInheritedList(const Section& section, + const Node *relative, + CodeMarker *marker, + bool nameAlignment = false); + QString highlightedCode(const QString& markedCode, + CodeMarker *marker, + const Node *relative, + CodeMarker::SynopsisStyle style = CodeMarker::Accessors, + bool nameAlignment = false); +#else + void generateSynopsis(const Node *node, + const Node *relative, + CodeMarker *marker, + CodeMarker::SynopsisStyle style); void generateSectionInheritedList(const Section& section, const Node *relative, CodeMarker *marker); + QString highlightedCode(const QString& markedCode, + CodeMarker *marker, + const Node *relative); +#endif void generateFullName(const Node *apparentNode, const Node *relative, CodeMarker *marker, const Node *actualNode = 0); - void generateDetailedMember(const Node *node, const InnerNode *relative, CodeMarker *marker); - void generateLink(const Atom *atom, const Node *relative, CodeMarker *marker); + void generateDetailedMember(const Node *node, + const InnerNode *relative, + CodeMarker *marker); + void generateLink(const Atom *atom, + const Node *relative, + CodeMarker *marker); void generateStatus(const Node *node, CodeMarker *marker); QString registerRef(const QString& ref); - QString highlightedCode(const QString& markedCode, CodeMarker *marker, const Node *relative); QString fileBase(const Node *node); #if 0 QString fileBase(const Node *node, const SectionIterator& section); @@ -177,7 +221,7 @@ class HtmlGenerator : public PageGenerator virtual QString getLink(const Atom *atom, const Node *relative, CodeMarker *marker, - const Node *node = 0); + const Node** node); virtual void generateDcf(const QString &fileBase, const QString &startPage, const QString &title, DcfSection &dcfRoot); @@ -205,6 +249,7 @@ class HtmlGenerator : public PageGenerator DcfSection dcfQmakeRoot; HelpProjectWriter *helpProjectWriter; bool inLink; + bool inObsoleteLink; bool inContents; bool inSectionHeading; bool inTableHeader; @@ -226,11 +271,13 @@ class HtmlGenerator : public PageGenerator QStringList customHeadElements; const Tree *tre; bool slow; + bool obsoleteLinks; QMap<QString, QMap<QString, const Node *> > moduleClassMap; QMap<QString, QMap<QString, const Node *> > moduleNamespaceMap; QMap<QString, const Node *> nonCompatClasses; QMap<QString, const Node *> mainClasses; QMap<QString, const Node *> compatClasses; + QMap<QString, const Node *> obsoleteClasses; QMap<QString, const Node *> namespaceIndex; QMap<QString, const Node *> serviceClasses; #ifdef QDOC_QML diff --git a/tools/qdoc3/jambiapiparser.cpp b/tools/qdoc3/jambiapiparser.cpp index f981e6d..70e9260 100644 --- a/tools/qdoc3/jambiapiparser.cpp +++ b/tools/qdoc3/jambiapiparser.cpp @@ -234,8 +234,9 @@ void JambiApiParser::doneParsingSourceFiles(Tree * /* tree */) foreach (Node *cppNode, cppTre->root()->childNodes()) { if (cppNode->type() == Node::Fake) { FakeNode *cppFake = static_cast<FakeNode *>(cppNode); - if (cppFake->subType() == FakeNode::Page) { - FakeNode *javaFake = new FakeNode(javaTre->root(), cppFake->name(), + if (cppFake->subType() == Node::Page) { + FakeNode *javaFake = new FakeNode(javaTre->root(), + cppFake->name(), cppFake->subType()); javaFake->setModuleName("com.trolltech.qt"); // ### hard-coded javaFake->setTitle(cppFake->title()); diff --git a/tools/qdoc3/javadocgenerator.cpp b/tools/qdoc3/javadocgenerator.cpp index b32425c..294877b 100644 --- a/tools/qdoc3/javadocgenerator.cpp +++ b/tools/qdoc3/javadocgenerator.cpp @@ -272,9 +272,10 @@ void JavadocGenerator::generateFakeNode(const FakeNode *fake, CodeMarker *marker HtmlGenerator::generateFakeNode(fake, marker); } -void JavadocGenerator::generateText(const Text& text, const Node *relative, CodeMarker *marker) +bool JavadocGenerator::generateText(const Text& text, const Node *relative, CodeMarker *marker) { HtmlGenerator::generateText(text, relative, marker); + return true; } void JavadocGenerator::generateBody(const Node *node, CodeMarker *marker) diff --git a/tools/qdoc3/javadocgenerator.h b/tools/qdoc3/javadocgenerator.h index ba9b15d..5431c38 100644 --- a/tools/qdoc3/javadocgenerator.h +++ b/tools/qdoc3/javadocgenerator.h @@ -68,7 +68,7 @@ protected: void generateClassLikeNode(const InnerNode *inner, CodeMarker *marker); void generateFakeNode( const FakeNode *fake, CodeMarker *marker ); - void generateText( const Text& text, const Node *relative, CodeMarker *marker ); + bool generateText( const Text& text, const Node *relative, CodeMarker *marker ); void generateBody( const Node *node, CodeMarker *marker ); void generateAlsoList( const Node *node, CodeMarker *marker ); diff --git a/tools/qdoc3/main.cpp b/tools/qdoc3/main.cpp index e3b2f08..9338203 100644 --- a/tools/qdoc3/main.cpp +++ b/tools/qdoc3/main.cpp @@ -95,11 +95,11 @@ static const struct { }; static bool slow = false; +static bool showInternal = false; +static bool obsoleteLinks = false; static QStringList defines; static QHash<QString, Tree *> trees; -//static int doxygen = 0; - /*! Find the Tree for language \a lang and return a pointer to it. If there is no Tree for language \a lang in the Tree table, add @@ -122,14 +122,18 @@ static void printHelp() { Location::information(tr("Usage: qdoc [options] file1.qdocconf ...\n" "Options:\n" - " -help " + " -help " "Display this information and exit\n" - " -version " + " -version " "Display version of qdoc and exit\n" - " -D<name> " + " -D<name> " "Define <name> as a macro while parsing sources\n" - " -slow " - "Turn on features that slow down qdoc") ); + " -slow " + "Turn on features that slow down qdoc\n" + " -showinternal " + "Include stuff marked internal\n" + " -obsoletelinks " + "Report links from obsolete items to non-obsolete items") ); } /*! @@ -162,6 +166,10 @@ static void processQdocconfFile(const QString &fileName) ++i; } config.setStringList(CONFIG_SLOW, QStringList(slow ? "true" : "false")); + config.setStringList(CONFIG_SHOWINTERNAL, + QStringList(showInternal ? "true" : "false")); + config.setStringList(CONFIG_OBSOLETELINKS, + QStringList(obsoleteLinks ? "true" : "false")); /* With the default configuration values in place, load @@ -224,18 +232,6 @@ static void processQdocconfFile(const QString &fileName) QString lang = config.getString(CONFIG_LANGUAGE); Location langLocation = config.lastLocation(); -#ifdef QDOC2DOX - // qdoc -> doxygen - if (doxygen == 2) { - qDebug() << "READING anchors.txt"; - DoxWriter::readAnchors(); - qDebug() << "READING title maps"; - DoxWriter::readTitles(); - qDebug() << "READING member multimaps"; - DoxWriter::readMembers(); - } -#endif - /* Initialize the tree where all the parsed sources will be stored. The tree gets built as the source files are parsed, and then the @@ -322,17 +318,6 @@ static void processQdocconfFile(const QString &fileName) tree->resolveGroups(); tree->resolveTargets(); -#ifdef QDOC2DOX - // qdoc -> doxygen - if (doxygen == 1) { - DoxWriter::writeAnchors(); - DoxWriter::writeTitles(); - DoxWriter::writeMembers(); - } - - if (doxygen == 0) { -#endif - /* Now the tree has been built, and all the stuff that needed resolving has been resolved. Now it is time to traverse @@ -351,17 +336,13 @@ static void processQdocconfFile(const QString &fileName) /* Generate the XML tag file, if it was requested. */ + QString tagFile = config.getString(CONFIG_TAGFILE); if (!tagFile.isEmpty()) tree->generateTagFile(tagFile); - + tree->setVersion(""); Generator::terminate(); - -#ifdef QDOC2DOX - } -#endif - CodeParser::terminate(); CodeMarker::terminate(); CppToQsConverter::terminate(); @@ -372,7 +353,6 @@ static void processQdocconfFile(const QString &fileName) foreach (QTranslator *translator, translators) delete translator; - delete tree; } @@ -456,26 +436,12 @@ int main(int argc, char **argv) else if (opt == "-slow") { slow = true; } - -#ifdef QDOC2DOX - else if (opt == "-doxygen1") { - // qdoc -> doxygen - // Don't use this; it isn't ready yet. - // Now it's a fossil. - qDebug() << "doxygen pass 1"; - doxygen = 1; - DoxWriter::setDoxPass(1); + else if (opt == "-showinternal") { + showInternal = true; } - else if (opt == "-doxygen2") { - // qdoc -> doxygen - // Don't use this; it isn't ready yet. - // Now it's a fossil. - qDebug() << "doxygen pass 2"; - doxygen = 2; - DoxWriter::setDoxPass(2); + else if (opt == "-obsoletelinks") { + obsoleteLinks = true; } -#endif - else { qdocFiles.append(opt); } diff --git a/tools/qdoc3/node.cpp b/tools/qdoc3/node.cpp index 0f9468a..610249d 100644 --- a/tools/qdoc3/node.cpp +++ b/tools/qdoc3/node.cpp @@ -43,6 +43,7 @@ node.cpp */ +#include <QtCore> #include "node.h" QT_BEGIN_NAMESPACE @@ -113,6 +114,9 @@ void Node::setRelates(InnerNode *pseudoParent) } /*! + This function creates a pair that describes a link. + The pair is composed from \a link and \a desc. The + \a linkType is the map index the pair is filed under. */ void Node::setLink(LinkType linkType, const QString &link, const QString &desc) { @@ -623,7 +627,7 @@ void InnerNode::removeRelated(Node *pseudoChild) */ /*! - Returns false because this is an InnerNode. + Returns false because this is a LeafNode. */ bool LeafNode::isInnerNode() const { @@ -713,9 +717,11 @@ void ClassNode::fixBaseClasses() */ /*! + The type of a FakeNode is Fake, and it has a \a subtype, + which specifies the type of FakeNode. */ -FakeNode::FakeNode(InnerNode *parent, const QString& name, SubType subType) - : InnerNode(Fake, parent, name), sub(subType) +FakeNode::FakeNode(InnerNode *parent, const QString& name, SubType subtype) + : InnerNode(Fake, parent, name), sub(subtype) { } @@ -868,6 +874,18 @@ void FunctionNode::setOverload(bool overlode) } /*! + Sets the function node's reimplementation flag to \a r. + When \a r is true, it is supposed to mean that this function + is a reimplementation of a virtual function in a base class, + but it really just means the \e reimp command was seen in the + qdoc comment. + */ +void FunctionNode::setReimp(bool r) +{ + reimp = r; +} + +/*! */ void FunctionNode::addParameter(const Parameter& parameter) { @@ -1021,4 +1039,98 @@ bool TargetNode::isInnerNode() const return false; } +#ifdef QDOC_QML +/*! + Constructor for the Qml class node. + */ +QmlClassNode::QmlClassNode(InnerNode *parent, + const QString& name, + const ClassNode* cn) + : FakeNode(parent, name, QmlClass), cnode(cn) +{ + setTitle("QML " + name + " Element Reference"); +} + +/*! + The base file name for this kind of node has "qml_" + prepended to it. + + But not yet. Still testing. + */ +QString QmlClassNode::fileBase() const +{ +#if 0 + if (Node::fileBase() == "item") + qDebug() << "FILEBASE: qmlitem" << name(); + return "qml_" + Node::fileBase(); +#endif + return Node::fileBase(); +} + +/*! + Constructor for the Qml property group node. \a parent is + always a QmlClassNode. + */ +QmlPropGroupNode::QmlPropGroupNode(QmlClassNode* parent, const QString& name) + : FakeNode(parent, name, QmlPropertyGroup), isdefault(false) +{ + // nothing. +} + +/*! + Constructor for the QML property node. + */ +QmlPropertyNode::QmlPropertyNode(QmlPropGroupNode *parent, + const QString& name, + const QString& type) + : LeafNode(QmlProperty, parent, name), + dt(type), + sto(Trool_Default), + des(Trool_Default) +{ + // nothing. +} + +/*! + I don't know what this is. + */ +QmlPropertyNode::Trool QmlPropertyNode::toTrool(bool boolean) +{ + return boolean ? Trool_True : Trool_False; +} + +/*! + I don't know what this is either. + */ +bool QmlPropertyNode::fromTrool(Trool troolean, bool defaultValue) +{ + switch (troolean) { + case Trool_True: + return true; + case Trool_False: + return false; + default: + return defaultValue; + } +} + +/*! + Constructor for the QML signal node. + */ +QmlSignalNode::QmlSignalNode(QmlClassNode *parent, const QString& name) + : LeafNode(QmlSignal, parent, name) +{ + // nothing. +} + +/*! + Constructor for the QML method node. + */ +QmlMethodNode::QmlMethodNode(QmlClassNode *parent, const QString& name) + : LeafNode(QmlMethod, parent, name) +{ + // nothing. +} +#endif + QT_END_NAMESPACE diff --git a/tools/qdoc3/node.h b/tools/qdoc3/node.h index 0a671b37d..17ec447 100644 --- a/tools/qdoc3/node.h +++ b/tools/qdoc3/node.h @@ -72,7 +72,31 @@ class Node Function, Property, Variable, +#ifdef QDOC_QML + Target, + QmlProperty, + QmlSignal, + QmlMethod +#else Target +#endif + }; + + enum SubType { + NoSubType, + Example, + HeaderFile, + File, + Group, + Module, + Page, +#ifdef QDOC_QML + ExternalPage, + QmlClass, + QmlPropertyGroup +#else + ExternalPage +#endif }; enum Access { Public, Protected, Private }; @@ -99,7 +123,8 @@ class Node NextLink, PreviousLink, ContentsLink, - IndexLink /*, + IndexLink, + InheritsLink /*, GlossaryLink, CopyrightLink, ChapterLink, @@ -123,7 +148,9 @@ class Node void setTemplateStuff(const QString &templateStuff) { tpl = templateStuff; } virtual bool isInnerNode() const = 0; + virtual bool isReimp() const { return false; } Type type() const { return typ; } + virtual SubType subType() const { return NoSubType; } InnerNode *parent() const { return par; } InnerNode *relates() const { return rel; } const QString& name() const { return nam; } @@ -143,7 +170,7 @@ class Node void clearRelated() { rel = 0; } - QString fileBase() const; + virtual QString fileBase() const; protected: Node(Type type, InnerNode *parent, const QString& name); @@ -180,7 +207,7 @@ typedef QList<Node *> NodeList; class InnerNode : public Node { public: - ~InnerNode(); + virtual ~InnerNode(); Node *findNode(const QString& name); Node *findNode(const QString& name, Type type); @@ -202,6 +229,7 @@ class InnerNode : public Node const EnumNode *findEnumNodeForValue(const QString &enumValue) const; const NodeList & childNodes() const { return children; } const NodeList & relatedNodes() const { return related; } + int count() const { return children.size(); } int overloadNumber(const FunctionNode *func) const; int numOverloads(const QString& funcName) const; NodeList overloads(const QString &funcName) const; @@ -231,17 +259,19 @@ class LeafNode : public Node { public: LeafNode(); + virtual ~LeafNode() { } virtual bool isInnerNode() const; protected: - LeafNode(Type type, InnerNode *parent, const QString& name); + LeafNode(Type type, InnerNode* parent, const QString& name); }; class NamespaceNode : public InnerNode { public: NamespaceNode(InnerNode *parent, const QString& name); + virtual ~NamespaceNode() { } }; class ClassNode; @@ -265,6 +295,7 @@ class ClassNode : public InnerNode { public: ClassNode(InnerNode *parent, const QString& name); + virtual ~ClassNode() { } void addBaseClass(Access access, ClassNode *node, @@ -279,29 +310,23 @@ class ClassNode : public InnerNode QString serviceName() const { return sname; } void setServiceName(const QString& value) { sname = value; } + QString qmlElement() const { return qmlelement; } + void setQmlElement(const QString& value) { qmlelement = value; } private: QList<RelatedClass> bas; QList<RelatedClass> der; bool hidden; QString sname; + QString qmlelement; }; class FakeNode : public InnerNode { public: - enum SubType { - Example, - HeaderFile, - File, - Group, - Module, - Page, - ExternalPage, - QmlClass - }; FakeNode(InnerNode *parent, const QString& name, SubType subType); + virtual ~FakeNode() { } void setTitle(const QString &title) { tle = title; } void setSubTitle(const QString &subTitle) { stle = subTitle; } @@ -320,18 +345,85 @@ class FakeNode : public InnerNode NodeList gr; }; -class QmlNode : public FakeNode +#ifdef QDOC_QML +class QmlClassNode : public FakeNode { public: - QmlNode(InnerNode *parent, const QString& name, const ClassNode* cn) - : FakeNode(parent, name, QmlClass), cnode(cn) { } + QmlClassNode(InnerNode *parent, + const QString& name, + const ClassNode* cn); + virtual ~QmlClassNode() { } const ClassNode* classNode() const { return cnode; } + virtual QString fileBase() const; private: const ClassNode* cnode; }; +class QmlPropGroupNode : public FakeNode +{ + public: + QmlPropGroupNode(QmlClassNode* parent, const QString& name); + virtual ~QmlPropGroupNode() { } + + const QString& element() const { return name(); } + void setDefault() { isdefault = true; } + bool isDefault() const { return isdefault; } + + private: + bool isdefault; +}; + +class QmlPropertyNode : public LeafNode +{ + public: + QmlPropertyNode(QmlPropGroupNode* parent, + const QString& name, + const QString& type); + virtual ~QmlPropertyNode() { } + + void setDataType(const QString& dataType) { dt = dataType; } + void setStored(bool stored) { sto = toTrool(stored); } + void setDesignable(bool designable) { des = toTrool(designable); } + + const QString &dataType() const { return dt; } + QString qualifiedDataType() const { return dt; } + bool isStored() const { return fromTrool(sto,true); } + bool isDesignable() const { return fromTrool(des,false); } + + const QString& element() const { return parent()->name(); } + + private: + enum Trool { Trool_True, Trool_False, Trool_Default }; + + static Trool toTrool(bool boolean); + static bool fromTrool(Trool troolean, bool defaultValue); + + QString dt; + Trool sto; + Trool des; +}; + +class QmlSignalNode : public LeafNode +{ + public: + QmlSignalNode(QmlClassNode* parent, const QString& name); + virtual ~QmlSignalNode() { } + + const QString& element() const { return parent()->name(); } +}; + +class QmlMethodNode : public LeafNode +{ + public: + QmlMethodNode(QmlClassNode* parent, const QString& name); + virtual ~QmlMethodNode() { } + + const QString& element() const { return parent()->name(); } +}; +#endif + class EnumItem { public: @@ -357,6 +449,7 @@ class EnumNode : public LeafNode { public: EnumNode(InnerNode *parent, const QString& name); + virtual ~EnumNode() { } void addItem(const EnumItem& item); void setFlagsType(TypedefNode *typedeff); @@ -377,6 +470,7 @@ class TypedefNode : public LeafNode { public: TypedefNode(InnerNode *parent, const QString& name); + virtual ~TypedefNode() { } const EnumNode *associatedEnum() const { return ae; } @@ -437,6 +531,7 @@ class FunctionNode : public LeafNode enum Virtualness { NonVirtual, ImpureVirtual, PureVirtual }; FunctionNode(InnerNode *parent, const QString &name); + virtual ~FunctionNode() { } void setReturnType(const QString& returnType) { rt = returnType; } void setMetaness(Metaness metaness) { met = metaness; } @@ -444,6 +539,7 @@ class FunctionNode : public LeafNode void setConst(bool conste) { con = conste; } void setStatic(bool statique) { sta = statique; } void setOverload(bool overlode); + void setReimp(bool r); void addParameter(const Parameter& parameter); inline void setParameters(const QList<Parameter>& parameters); void borrowParameterNames(const FunctionNode *source); @@ -458,6 +554,7 @@ class FunctionNode : public LeafNode bool isConst() const { return con; } bool isStatic() const { return sta; } bool isOverload() const { return ove; } + bool isReimp() const { return reimp; } int overloadNumber() const; int numOverloads() const; const QList<Parameter>& parameters() const { return params; } @@ -483,6 +580,7 @@ class FunctionNode : public LeafNode bool con : 1; bool sta : 1; bool ove : 1; + bool reimp: 1; QList<Parameter> params; const FunctionNode *rf; const PropertyNode *ap; @@ -496,6 +594,7 @@ class PropertyNode : public LeafNode enum { NumFunctionRoles = Resetter + 1 }; PropertyNode(InnerNode *parent, const QString& name); + virtual ~PropertyNode() { } void setDataType(const QString& dataType) { dt = dataType; } void addFunction(FunctionNode *function, FunctionRole role); @@ -553,6 +652,7 @@ class VariableNode : public LeafNode { public: VariableNode(InnerNode *parent, const QString &name); + virtual ~VariableNode() { } void setLeftType(const QString &leftType) { lt = leftType; } void setRightType(const QString &rightType) { rt = rightType; } @@ -578,6 +678,7 @@ class TargetNode : public LeafNode { public: TargetNode(InnerNode *parent, const QString& name); + virtual ~TargetNode() { } virtual bool isInnerNode() const; }; diff --git a/tools/qdoc3/pagegenerator.cpp b/tools/qdoc3/pagegenerator.cpp index 06ff398..8715f4a 100644 --- a/tools/qdoc3/pagegenerator.cpp +++ b/tools/qdoc3/pagegenerator.cpp @@ -81,30 +81,50 @@ QString PageGenerator::fileBase(const Node *node) { if (node->relates()) node = node->relates(); - else if (!node->isInnerNode()) + else if (!node->isInnerNode()) { node = node->parent(); +#ifdef QDOC_QML + if (node->subType() == Node::QmlPropertyGroup) { + node = node->parent(); + } +#endif + } QString base = node->doc().baseName(); if (!base.isEmpty()) return base; - const Node *p = node; - - forever { - base.prepend(p->name()); + const Node *p = node; + + forever { + base.prepend(p->name()); +#ifdef QDOC_QML + /* + To avoid file name conflicts in the html directory, + we prepend "qml-" to the file name of QML element doc + files. + */ + if ((p->subType() == Node::QmlClass) || + (p->subType() == Node::QmlPropertyGroup)) + base.prepend("qml-"); + else if ((p->type() == Node::QmlProperty) || + (p->type() == Node::QmlSignal) || + (p->type() == Node::QmlMethod)) + base.prepend("qml-"); +#endif const Node *pp = p->parent(); if (!pp || pp->name().isEmpty() || pp->type() == Node::Fake) - break; + break; base.prepend(QLatin1Char('-')); p = pp; - } - - if (node->type() == Node::Fake) { + } + + if (node->type() == Node::Fake) { #ifdef QDOC2_COMPAT - if (base.endsWith(".html")) - base.truncate(base.length() - 5); + if (base.endsWith(".html")) + base.truncate(base.length() - 5); #endif - } + } // the code below is effectively equivalent to: // base.replace(QRegExp("[^A-Za-z0-9]+"), " "); @@ -126,7 +146,8 @@ QString PageGenerator::fileBase(const Node *node) if ((u >= 'a' && u <= 'z') || (u >= '0' && u <= '9')) { res += QLatin1Char(u); begun = true; - } else if (begun) { + } + else if (begun) { res += QLatin1Char('-'); begun = false; } @@ -187,8 +208,12 @@ void PageGenerator::generateInnerNode(const InnerNode *node, if (node->type() == Node::Fake) { const FakeNode *fakeNode = static_cast<const FakeNode *>(node); - if (fakeNode->subType() == FakeNode::ExternalPage) + if (fakeNode->subType() == Node::ExternalPage) + return; +#ifdef QDOC_QML + if (fakeNode->subType() == Node::QmlPropertyGroup) return; +#endif } if (node->parent() != 0) { @@ -197,12 +222,6 @@ void PageGenerator::generateInnerNode(const InnerNode *node, generateClassLikeNode(node, marker); } else if (node->type() == Node::Fake) { - const FakeNode* fakeNode = static_cast<const FakeNode *>(node); -#ifdef QDOC_QML - if (fakeNode->subType() == FakeNode::QmlClass) { - //qDebug() << "FILENAME:" << fileName(node); - } -#endif generateFakeNode(static_cast<const FakeNode *>(node), marker); } endSubPage(); diff --git a/tools/qdoc3/qdoc3.pro b/tools/qdoc3/qdoc3.pro index 2bba8fb..49a16e6 100644 --- a/tools/qdoc3/qdoc3.pro +++ b/tools/qdoc3/qdoc3.pro @@ -1,12 +1,17 @@ DEFINES += QDOC2_COMPAT -#DEFINES += QT_NO_CAST_TO_ASCII +DEFINES += QT_NO_CAST_TO_ASCII #DEFINES += QT_NO_CAST_FROM_ASCII +#DEFINES += QT_USE_FAST_OPERATOR_PLUS +#DEFINES += QT_USE_FAST_CONCATENATION QT = core xml CONFIG += console +CONFIG -= debug_and_release_target +#CONFIG += debug build_all:!build_pass { CONFIG -= build_all CONFIG += release +# CONFIG += debug } mac:CONFIG -= app_bundle HEADERS += apigenerator.h \ diff --git a/tools/qdoc3/separator.cpp b/tools/qdoc3/separator.cpp index 8f27f90..60674be 100644 --- a/tools/qdoc3/separator.cpp +++ b/tools/qdoc3/separator.cpp @@ -48,22 +48,30 @@ QT_BEGIN_NAMESPACE -QString separator( int index, int count ) +QString separator(int index, int count) { - if ( index == count - 1 ) - return tr( ".", "terminator" ); + if (index == count - 1) + return tr(".", "terminator"); + if (count == 2) + return tr(" and ", "separator when N = 2"); + if (index == 0) + return tr(", ", "first separator when N > 2"); + if (index < count - 2) + return tr(", ", "general separator when N > 2"); + return tr(", and ", "last separator when N > 2"); +} - if ( count == 2 ) { - return tr( " and ", "separator when N = 2" ); - } else { - if ( index == 0 ) { - return tr( ", ", "first separator when N > 2" ); - } else if ( index < count - 2 ) { - return tr( ", ", "general separator when N > 2" ); - } else { - return tr( ", and ", "last separator when N > 2" ); - } - } +QString comma(int index, int count) +{ + if (index == count - 1) + return QString(""); + if (count == 2) + return tr(" and ", "separator when N = 2"); + if (index == 0) + return tr(", ", "first separator when N > 2"); + if (index < count - 2) + return tr(", ", "general separator when N > 2"); + return tr(", and ", "last separator when N > 2"); } QT_END_NAMESPACE diff --git a/tools/qdoc3/separator.h b/tools/qdoc3/separator.h index 70ba624..2336d94 100644 --- a/tools/qdoc3/separator.h +++ b/tools/qdoc3/separator.h @@ -51,6 +51,7 @@ QT_BEGIN_NAMESPACE QString separator( int index, int count ); +QString comma( int index, int count ); QT_END_NAMESPACE diff --git a/tools/qdoc3/test/assistant.qdocconf b/tools/qdoc3/test/assistant.qdocconf index 71de998..44815ff 100644 --- a/tools/qdoc3/test/assistant.qdocconf +++ b/tools/qdoc3/test/assistant.qdocconf @@ -6,18 +6,18 @@ include(qt-defines.qdocconf) project = Qt Assistant description = Qt Assistant Manual -url = http://doc.qtsoftware.com/4.5 +url = http://doc.qtsoftware.com/4.6 indexes = $QT_BUILD_TREE/doc-build/html-qt/qt.index qhp.projects = Assistant qhp.Assistant.file = assistant.qhp -qhp.Assistant.namespace = com.trolltech.assistant.453 +qhp.Assistant.namespace = com.trolltech.assistant.460 qhp.Assistant.virtualFolder = qdoc qhp.Assistant.indexTitle = Qt Assistant Manual qhp.Assistant.extraFiles = classic.css images/qt-logo.png images/trolltech-logo.png -qhp.Assistant.filterAttributes = qt 4.5.3 tools assistant +qhp.Assistant.filterAttributes = qt 4.6.0 tools assistant qhp.Assistant.customFilters.Assistant.name = Qt Assistant Manual qhp.Assistant.customFilters.Assistant.filterAttributes = qt tools assistant qhp.Assistant.subprojects = manual examples diff --git a/tools/qdoc3/test/classic.css b/tools/qdoc3/test/classic.css index f22a77a..4225a1b 100644 --- a/tools/qdoc3/test/classic.css +++ b/tools/qdoc3/test/classic.css @@ -1,12 +1,82 @@ +BODY,H1,H2,H3,H4,H5,H6,P,CENTER,TD,TH,UL,DL,DIV { + font-family: Arial, Geneva, Helvetica, sans-serif; +} +H1 { + text-align: center; + font-size: 160%; +} +H2 { + font-size: 120%; +} +H3 { + font-size: 100%; +} + h3.fn,span.fn { - margin-left: 1cm; - text-indent: -1cm; + background-color: #eee; + border-width: 1px; + border-style: solid; + border-color: #ddd; + font-weight: bold; + padding: 6px 0px 6px 10px; + margin: 42px 0px 0px 0px; +} + +hr { + border: 0; + color: #a0a0a0; + background-color: #ccc; + height: 1px; + width: 100%; + text-align: left; + margin: 34px 0px 34px 0px; +} + +table.valuelist { + border-width: 1px 1px 1px 1px; + border-style: solid; + border-color: #dddddd; + border-collapse: collapse; + background-color: #f0f0f0; +} + +table.indextable { + border-width: 1px 1px 1px 1px; + border-collapse: collapse; + background-color: #f0f0f0; + border-color:#555; +} + + +table.valuelist th { + border-width: 1px 1px 1px 2px; + padding: 4px; + border-style: solid; + border-color: #666; + color:white; + background-color:#666; +} + +th.titleheader { + border-width: 1px 0px 1px 0px; + padding: 4px; + border-style: solid; + border-color: #444; + color:white; + background-color:#555555; +} + +p { + + margin-left: 4px; + margin-top: 8px; + margin-bottom: 8px; } a:link { - color: #004faf; + color: #0046ad; text-decoration: none } @@ -40,20 +110,38 @@ a.compat:visited text-decoration: none } -td.postheader +body { - font-family: sans-serif + background: #ffffff; + color: black } -tr.address +table.generic, table.annotated { - font-family: sans-serif + border-width: 1px; + border-color:#bbb; + border-style:solid; + border-collapse:collapse; } -body -{ - background: #ffffff; - color: black +table td.memItemLeft { + width: 180px; + padding: 2px 0px 0px 8px; + margin: 4px; + border-width: 1px; + border-color: #E0E0E0; + border-style: none; + font-size: 100%; + white-space: nowrap +} + +table td.memItemRight { + padding: 2px 8px 0px 8px; + margin: 4px; + border-width: 1px; + border-color: #E0E0E0; + border-style: none; + font-size: 100%; } table tr.odd { @@ -137,3 +225,52 @@ span.string,span.char { font-size: 0.65em } + +.qmlitem { + padding: 0; +} + +.qmlname { + white-space: nowrap; + font-weight: bold; + font-size: 125%; +} + +.qmltype { + font-weight: bold; + font-size: 125%; +} + +.qmlproto, .qmldoc { + // border-top: 1px solid #84b0c7; +} + +.qmlproto { + padding: 0; + //background-color: #e4e4e4;//#d5e1e8; + //font-weight: bold; + //-webkit-border-top-left-radius: 8px; + //-webkit-border-top-right-radius: 8px; + //-moz-border-radius-topleft: 8px; + //-moz-border-radius-topright: 8px; +} + +.qmldoc { + border-top: 1px solid #e4e4e4; + //padding: 2px 5px; + //background-color: #eef3f5; + //border-top-width: 0; + //-webkit-border-bottom-left-radius: 8px; + //-webkit-border-bottom-right-radius: 8px; + //-moz-border-radius-bottomleft: 8px; + //-moz-border-radius-bottomright: 8px; +} + +.qmldoc p, .qmldoc dl, .qmldoc ul { + //margin: 6px 0; +} + +*.qmlitem p { + //margin-top: 0px; + //margin-bottom: 0px; +} diff --git a/tools/qdoc3/test/designer.qdocconf b/tools/qdoc3/test/designer.qdocconf index 0c39bb8..88f8dc9 100644 --- a/tools/qdoc3/test/designer.qdocconf +++ b/tools/qdoc3/test/designer.qdocconf @@ -6,18 +6,18 @@ include(qt-defines.qdocconf) project = Qt Designer description = Qt Designer Manual -url = http://doc.qtsoftware.com/4.5 +url = http://doc.qtsoftware.com/4.6 indexes = $QT_BUILD_TREE/doc-build/html-qt/qt.index qhp.projects = Designer qhp.Designer.file = designer.qhp -qhp.Designer.namespace = com.trolltech.designer.453 +qhp.Designer.namespace = com.trolltech.designer.460 qhp.Designer.virtualFolder = qdoc qhp.Designer.indexTitle = Qt Designer Manual qhp.Designer.extraFiles = classic.css images/qt-logo.png images/trolltech-logo.png -qhp.Designer.filterAttributes = qt 4.5.3 tools designer +qhp.Designer.filterAttributes = qt 4.6.0 tools designer qhp.Designer.customFilters.Designer.name = Qt Designer Manual qhp.Designer.customFilters.Designer.filterAttributes = qt tools designer qhp.Designer.subprojects = manual examples diff --git a/tools/qdoc3/test/linguist.qdocconf b/tools/qdoc3/test/linguist.qdocconf index b6bd375..1c0a585 100644 --- a/tools/qdoc3/test/linguist.qdocconf +++ b/tools/qdoc3/test/linguist.qdocconf @@ -6,18 +6,18 @@ include(qt-defines.qdocconf) project = Qt Linguist description = Qt Linguist Manual -url = http://doc.qtsoftware.com/4.5 +url = http://doc.qtsoftware.com/4.6 indexes = $QT_BUILD_TREE/doc-build/html-qt/qt.index qhp.projects = Linguist qhp.Linguist.file = linguist.qhp -qhp.Linguist.namespace = com.trolltech.linguist.453 +qhp.Linguist.namespace = com.trolltech.linguist.460 qhp.Linguist.virtualFolder = qdoc qhp.Linguist.indexTitle = Qt Linguist Manual qhp.Linguist.extraFiles = classic.css images/qt-logo.png images/trolltech-logo.png -qhp.Linguist.filterAttributes = qt 4.5.3 tools linguist +qhp.Linguist.filterAttributes = qt 4.6.0 tools linguist qhp.Linguist.customFilters.Linguist.name = Qt Linguist Manual qhp.Linguist.customFilters.Linguist.filterAttributes = qt tools linguist qhp.Linguist.subprojects = manual examples diff --git a/tools/qdoc3/test/macros.qdocconf b/tools/qdoc3/test/macros.qdocconf index 85fe1db..f7dcdc0 100644 --- a/tools/qdoc3/test/macros.qdocconf +++ b/tools/qdoc3/test/macros.qdocconf @@ -1,14 +1,15 @@ +macro.aacute.HTML = "á" macro.Aring.HTML = "Å" macro.aring.HTML = "å" macro.Auml.HTML = "Ä" macro.author = "\\bold{Author:}" macro.br.HTML = "<br />" macro.BR.HTML = "<br />" -macro.aacute.HTML = "á" +macro.copyright.HTML = "©" macro.eacute.HTML = "é" -macro.iacute.HTML = "í" macro.gui = "\\bold" macro.hr.HTML = "<hr />" +macro.iacute.HTML = "í" macro.key = "\\bold" macro.menu = "\\bold" macro.note = "\\bold{Note:}" diff --git a/tools/qdoc3/test/qmake.qdocconf b/tools/qdoc3/test/qmake.qdocconf index 83220ae..0f98132 100644 --- a/tools/qdoc3/test/qmake.qdocconf +++ b/tools/qdoc3/test/qmake.qdocconf @@ -6,18 +6,18 @@ include(qt-defines.qdocconf) project = QMake description = QMake Manual -url = http://doc.qtsoftware.com/4.5 +url = http://doc.qtsoftware.com/4.6 indexes = $QT_BUILD_TREE/doc-build/html-qt/qt.index qhp.projects = qmake qhp.qmake.file = qmake.qhp -qhp.qmake.namespace = com.trolltech.qmake.453 +qhp.qmake.namespace = com.trolltech.qmake.460 qhp.qmake.virtualFolder = qdoc qhp.qmake.indexTitle = QMake Manual qhp.qmake.extraFiles = classic.css images/qt-logo.png images/trolltech-logo.png -qhp.qmake.filterAttributes = qt 4.5.3 tools qmake +qhp.qmake.filterAttributes = qt 4.6.0 tools qmake qhp.qmake.customFilters.qmake.name = qmake Manual qhp.qmake.customFilters.qmake.filterAttributes = qt tools qmake qhp.qmake.subprojects = manual diff --git a/tools/qdoc3/test/qt-build-docs.qdocconf b/tools/qdoc3/test/qt-build-docs.qdocconf index 5169714..b4f0c7a 100644 --- a/tools/qdoc3/test/qt-build-docs.qdocconf +++ b/tools/qdoc3/test/qt-build-docs.qdocconf @@ -6,7 +6,7 @@ include(qt-defines.qdocconf) project = Qt description = Qt Reference Documentation -url = http://doc.qtsoftware.com/4.5 +url = http://doc.qtsoftware.com/4.6 edition.Console.modules = QtCore QtDBus QtNetwork QtScript QtSql QtXml \ QtXmlPatterns QtTest @@ -20,7 +20,7 @@ edition.DesktopLight.groups = -graphicsview-api qhp.projects = Qt qhp.Qt.file = qt.qhp -qhp.Qt.namespace = com.trolltech.qt.453 +qhp.Qt.namespace = com.trolltech.qt.460 qhp.Qt.virtualFolder = qdoc qhp.Qt.indexTitle = Qt Reference Documentation qhp.Qt.indexRoot = @@ -34,9 +34,9 @@ qhp.Qt.extraFiles = classic.css \ images/dynamiclayouts-example.png \ images/stylesheet-coffee-plastique.png -qhp.Qt.filterAttributes = qt 4.5.3 qtrefdoc -qhp.Qt.customFilters.Qt.name = Qt 4.5.3 -qhp.Qt.customFilters.Qt.filterAttributes = qt 4.5.3 +qhp.Qt.filterAttributes = qt 4.6.0 qtrefdoc +qhp.Qt.customFilters.Qt.name = Qt 4.6.0 +qhp.Qt.customFilters.Qt.filterAttributes = qt 4.6.0 qhp.Qt.subprojects = classes overviews examples qhp.Qt.subprojects.classes.title = Classes qhp.Qt.subprojects.classes.indexTitle = Qt's Classes diff --git a/tools/qdoc3/test/qt-cpp-ignore.qdocconf b/tools/qdoc3/test/qt-cpp-ignore.qdocconf index 107c692..709e336 100644 --- a/tools/qdoc3/test/qt-cpp-ignore.qdocconf +++ b/tools/qdoc3/test/qt-cpp-ignore.qdocconf @@ -12,6 +12,7 @@ Cpp.ignoretokens = QAXFACTORY_EXPORT \ QM_EXPORT_ICONVIEW \ QM_EXPORT_NETWORK \ QM_EXPORT_OPENGL \ + QM_EXPORT_OPENVG \ QM_EXPORT_SQL \ QM_EXPORT_TABLE \ QM_EXPORT_WORKSPACE \ @@ -50,6 +51,7 @@ Cpp.ignoretokens = QAXFACTORY_EXPORT \ Q_INTERNAL_WIN_NO_THROW \ Q_NETWORK_EXPORT \ Q_OPENGL_EXPORT \ + Q_OPENVG_EXPORT \ Q_OUTOFLINE_TEMPLATE \ Q_SQL_EXPORT \ Q_SVG_EXPORT \ @@ -65,7 +67,9 @@ Cpp.ignoretokens = QAXFACTORY_EXPORT \ QT_BEGIN_INCLUDE_NAMESPACE \ QT_END_NAMESPACE \ QT_END_INCLUDE_NAMESPACE \ - PHONON_EXPORT + PHONON_EXPORT \ + Q_GADGET \ + QWEBKIT_EXPORT Cpp.ignoredirectives = Q_DECLARE_HANDLE \ Q_DECLARE_INTERFACE \ Q_DECLARE_METATYPE \ diff --git a/tools/qdoc3/test/qt-inc.qdocconf b/tools/qdoc3/test/qt-inc.qdocconf index d6cb0e6..379511f 100644 --- a/tools/qdoc3/test/qt-inc.qdocconf +++ b/tools/qdoc3/test/qt-inc.qdocconf @@ -3,7 +3,7 @@ include(macros.qdocconf) project = Qt description = Qt Reference Documentation -url = http://doc.qtsoftware.com/4.5 +url = http://doc.qtsoftware.com/4.6 edition.Console = QtCore QtNetwork QtSql QtXml QtScript QtTest edition.Desktop = QtCore QtGui QtNetwork QtOpenGL QtSql QtSvg QtXml QtScript \ @@ -99,7 +99,9 @@ Cpp.ignoretokens = QAXFACTORY_EXPORT \ Q_TESTLIB_EXPORT \ Q_TYPENAME \ Q_XML_EXPORT \ - QDBUS_EXPORT + QDBUS_EXPORT \ + Q_GADGET \ + QWEBKIT_EXPORT Cpp.ignoredirectives = Q_DECLARE_HANDLE \ Q_DECLARE_INTERFACE \ Q_DECLARE_METATYPE \ diff --git a/tools/qdoc3/test/qt.qdocconf b/tools/qdoc3/test/qt.qdocconf index f1fd8a2..10e0fcd 100644 --- a/tools/qdoc3/test/qt.qdocconf +++ b/tools/qdoc3/test/qt.qdocconf @@ -8,7 +8,7 @@ project = Qt versionsym = version = %VERSION% description = Qt Reference Documentation -url = http://doc.qtsoftware.com/4.5 +url = http://doc.qtsoftware.com/4.6 edition.Console.modules = QtCore QtDBus QtNetwork QtScript QtSql QtXml \ QtXmlPatterns QtTest @@ -22,7 +22,7 @@ edition.DesktopLight.groups = -graphicsview-api qhp.projects = Qt qhp.Qt.file = qt.qhp -qhp.Qt.namespace = com.trolltech.qt.453 +qhp.Qt.namespace = com.trolltech.qt.460 qhp.Qt.virtualFolder = qdoc qhp.Qt.indexTitle = Qt Reference Documentation qhp.Qt.indexRoot = @@ -36,9 +36,9 @@ qhp.Qt.extraFiles = classic.css \ images/dynamiclayouts-example.png \ images/stylesheet-coffee-plastique.png -qhp.Qt.filterAttributes = qt 4.5.3 qtrefdoc -qhp.Qt.customFilters.Qt.name = Qt 4.5.3 -qhp.Qt.customFilters.Qt.filterAttributes = qt 4.5.3 +qhp.Qt.filterAttributes = qt 4.6.0 qtrefdoc +qhp.Qt.customFilters.Qt.name = Qt 4.6.0 +qhp.Qt.customFilters.Qt.filterAttributes = qt 4.6.0 qhp.Qt.subprojects = classes overviews examples qhp.Qt.subprojects.classes.title = Classes qhp.Qt.subprojects.classes.indexTitle = Qt's Classes diff --git a/tools/qdoc3/tree.cpp b/tools/qdoc3/tree.cpp index c992688..d75af70 100644 --- a/tools/qdoc3/tree.cpp +++ b/tools/qdoc3/tree.cpp @@ -176,6 +176,8 @@ const Node *Tree::findNode(const QStringList &path, } /*! + Find the node with the specified \a path name of the + specified \a type. */ Node *Tree::findNode(const QStringList &path, Node::Type type, @@ -189,6 +191,8 @@ Node *Tree::findNode(const QStringList &path, } /*! + Find the node with the specified \a path name of the + specified \a type. */ const Node *Tree::findNode(const QStringList &path, Node::Type type, @@ -208,7 +212,9 @@ FunctionNode *Tree::findFunctionNode(const QStringList& path, int findFlags) { return const_cast<FunctionNode *>( - const_cast<const Tree *>(this)->findFunctionNode(path, relative, findFlags)); + const_cast<const Tree *>(this)->findFunctionNode(path, + relative, + findFlags)); } /*! @@ -233,7 +239,8 @@ const FunctionNode *Tree::findFunctionNode(const QStringList &path, else next = ((InnerNode *) node)->findNode(path.at(i)); - if (!next && node->type() == Node::Class && (findFlags & SearchBaseClasses)) { + if (!next && node->type() == Node::Class && + (findFlags & SearchBaseClasses)) { NodeList baseClasses = allBaseClasses(static_cast<const ClassNode *>(node)); foreach (const Node *baseClass, baseClasses) { if (i == path.size() - 1) @@ -412,6 +419,8 @@ void Tree::addPropertyFunction(PropertyNode *property, } /*! + This function adds the \a node to the \a group. The group + can be listed anywhere using the \e{annotated list} command. */ void Tree::addToGroup(Node *node, const QString &group) { @@ -563,7 +572,7 @@ void Tree::resolveGroups() FakeNode *fake = static_cast<FakeNode*>(findNode(QStringList(i.key()),Node::Fake)); - if (fake && fake->subType() == FakeNode::Group) { + if (fake && fake->subType() == Node::Group) { fake->addGroupMember(i.value()); } else { @@ -770,21 +779,21 @@ void Tree::readIndexSection(const QDomElement &element, } else if (element.nodeName() == "page") { - FakeNode::SubType subtype; + Node::SubType subtype; if (element.attribute("subtype") == "example") - subtype = FakeNode::Example; + subtype = Node::Example; else if (element.attribute("subtype") == "header") - subtype = FakeNode::HeaderFile; + subtype = Node::HeaderFile; else if (element.attribute("subtype") == "file") - subtype = FakeNode::File; + subtype = Node::File; else if (element.attribute("subtype") == "group") - subtype = FakeNode::Group; + subtype = Node::Group; else if (element.attribute("subtype") == "module") - subtype = FakeNode::Module; + subtype = Node::Module; else if (element.attribute("subtype") == "page") - subtype = FakeNode::Page; + subtype = Node::Page; else if (element.attribute("subtype") == "externalpage") - subtype = FakeNode::ExternalPage; + subtype = Node::ExternalPage; else return; @@ -1226,25 +1235,25 @@ bool Tree::generateIndexSection(QXmlStreamWriter &writer, const FakeNode *fakeNode = static_cast<const FakeNode*>(node); switch (fakeNode->subType()) { - case FakeNode::Example: + case Node::Example: writer.writeAttribute("subtype", "example"); break; - case FakeNode::HeaderFile: + case Node::HeaderFile: writer.writeAttribute("subtype", "header"); break; - case FakeNode::File: + case Node::File: writer.writeAttribute("subtype", "file"); break; - case FakeNode::Group: + case Node::Group: writer.writeAttribute("subtype", "group"); break; - case FakeNode::Module: + case Node::Module: writer.writeAttribute("subtype", "module"); break; - case FakeNode::Page: + case Node::Page: writer.writeAttribute("subtype", "page"); break; - case FakeNode::ExternalPage: + case Node::ExternalPage: writer.writeAttribute("subtype", "externalpage"); break; default: @@ -1383,7 +1392,7 @@ bool Tree::generateIndexSection(QXmlStreamWriter &writer, bool external = false; if (inner->type() == Node::Fake) { const FakeNode *fakeNode = static_cast<const FakeNode *>(inner); - if (fakeNode->subType() == FakeNode::ExternalPage) + if (fakeNode->subType() == Node::ExternalPage) external = true; } @@ -1863,7 +1872,7 @@ void Tree::generateTagFile(const QString &fileName) const */ void Tree::addExternalLink(const QString &url, const Node *relative) { - FakeNode *fakeNode = new FakeNode(root(), url, FakeNode::ExternalPage); + FakeNode *fakeNode = new FakeNode(root(), url, Node::ExternalPage); fakeNode->setAccess(Node::Public); // Create some content for the node. @@ -1884,23 +1893,30 @@ QString Tree::fullDocumentLocation(const Node *node) const if (!node->url().isEmpty()) return node->url(); + QString parentName; + QString anchorRef; + if (node->type() == Node::Namespace) { // The root namespace has no name - check for this before creating // an attribute containing the location of any documentation. if (!node->fileBase().isEmpty()) - return node->fileBase() + ".html"; + parentName = node->fileBase() + ".html"; else return ""; } else if (node->type() == Node::Fake) { - return node->fileBase() + ".html"; +#ifdef QDOC_QML + if (node->subType() == Node::QmlClass) + return "qml-" + node->fileBase() + ".html"; + else +#endif + parentName = node->fileBase() + ".html"; } else if (node->fileBase().isEmpty()) return ""; - QString parentName; Node *parentNode = 0; if ((parentNode = node->relates())) @@ -1912,10 +1928,11 @@ QString Tree::fullDocumentLocation(const Node *node) const case Node::Class: case Node::Namespace: if (parentNode && !parentNode->name().isEmpty()) - return parentName.replace(".html", "") + "-" - + node->fileBase().toLower() + ".html"; + parentName = parentName.replace(".html", "") + "-" + + node->fileBase().toLower() + ".html"; else - return node->fileBase() + ".html"; + parentName = node->fileBase() + ".html"; + break; case Node::Function: { /* @@ -1925,29 +1942,17 @@ QString Tree::fullDocumentLocation(const Node *node) const const FunctionNode *functionNode = static_cast<const FunctionNode *>(node); - // Functions can be compatibility functions or be obsolete. - switch (node->status()) { - case Node::Compat: - parentName.replace(".html", "-qt3.html"); - break; - case Node::Obsolete: - parentName.replace(".html", "-obsolete.html"); - break; - default: - ; - } - if (functionNode->metaness() == FunctionNode::Dtor) - return parentName + "#dtor." + functionNode->name().mid(1); + anchorRef = "#dtor." + functionNode->name().mid(1); - if (functionNode->associatedProperty()) + else if (functionNode->associatedProperty()) return fullDocumentLocation(functionNode->associatedProperty()); - if (functionNode->overloadNumber() > 1) - return parentName + "#" + functionNode->name() - + "-" + QString::number(functionNode->overloadNumber()); + else if (functionNode->overloadNumber() > 1) + anchorRef = "#" + functionNode->name() + + "-" + QString::number(functionNode->overloadNumber()); else - return parentName + "#" + functionNode->name(); + anchorRef = "#" + functionNode->name(); } /* @@ -1955,27 +1960,52 @@ QString Tree::fullDocumentLocation(const Node *node) const the latter returns the name in lower-case. For HTML anchors, we need to preserve the case. */ + break; case Node::Enum: - return parentName + "#" + node->name() + "-enum"; + anchorRef = "#" + node->name() + "-enum"; + break; case Node::Typedef: - return parentName + "#" + node->name() + "-typedef"; + anchorRef = "#" + node->name() + "-typedef"; + break; case Node::Property: - return parentName + "#" + node->name() + "-prop"; + anchorRef = "#" + node->name() + "-prop"; + break; case Node::Variable: - return parentName + "#" + node->name() + "-var"; + anchorRef = "#" + node->name() + "-var"; + break; case Node::Target: - return parentName + "#" + Doc::canonicalTitle(node->name()); + anchorRef = "#" + Doc::canonicalTitle(node->name()); + break; case Node::Fake: { - QString pageName = node->name(); - return pageName.replace("/", "-").replace(".", "-") + ".html"; + /* + Use node->fileBase() for fake nodes because they are represented + by pages whose file names are lower-case. + */ + parentName = node->fileBase(); + parentName.replace("/", "-").replace(".", "-"); + parentName += ".html"; } break; default: break; } - return ""; + // Various objects can be compat (deprecated) or obsolete. + if (node->type() != Node::Class && node->type() != Node::Namespace) { + switch (node->status()) { + case Node::Compat: + parentName.replace(".html", "-qt3.html"); + break; + case Node::Obsolete: + parentName.replace(".html", "-obsolete.html"); + break; + default: + ; + } + } + + return parentName.toLower() + anchorRef; } /*! diff --git a/tools/qdoc3/webxmlgenerator.cpp b/tools/qdoc3/webxmlgenerator.cpp index c5209b8..e87e812 100644 --- a/tools/qdoc3/webxmlgenerator.cpp +++ b/tools/qdoc3/webxmlgenerator.cpp @@ -191,7 +191,7 @@ void WebXMLGenerator::generateIndexSections(QXmlStreamWriter &writer, generateRelations(writer, node, marker); - if (fake->subType() == FakeNode::Module) { + if (fake->subType() == Node::Module) { writer.writeStartElement("generatedlist"); writer.writeAttribute("contents", "classesbymodule"); @@ -264,7 +264,7 @@ void WebXMLGenerator::generateInnerNode(const InnerNode *node, CodeMarker *marke if (node->type() == Node::Fake) { const FakeNode *fakeNode = static_cast<const FakeNode *>(node); - if (fakeNode->subType() == FakeNode::ExternalPage) + if (fakeNode->subType() == Node::ExternalPage) return; } |