diff options
Diffstat (limited to 'src/tools')
33 files changed, 1231 insertions, 933 deletions
diff --git a/src/tools/qdbuscpp2xml/qdbuscpp2xml.cpp b/src/tools/qdbuscpp2xml/qdbuscpp2xml.cpp index a66757907d..0e1fa59b90 100644 --- a/src/tools/qdbuscpp2xml/qdbuscpp2xml.cpp +++ b/src/tools/qdbuscpp2xml/qdbuscpp2xml.cpp @@ -47,6 +47,7 @@ #include <qbuffer.h> #include <qregexp.h> #include <qvector.h> +#include <qdebug.h> #include <stdio.h> #include <stdlib.h> @@ -95,14 +96,14 @@ static const char help[] = "\n"; -int qDBusParametersForMethod(const FunctionDef &mm, QVector<int>& metaTypes) +int qDBusParametersForMethod(const FunctionDef &mm, QVector<int>& metaTypes, QString &errorMsg) { QList<QByteArray> parameterTypes; foreach (const ArgumentDef &arg, mm.arguments) parameterTypes.append(arg.normalizedType); - return qDBusParametersForMethod(parameterTypes, metaTypes); + return qDBusParametersForMethod(parameterTypes, metaTypes, errorMsg); } @@ -140,9 +141,12 @@ static QString addFunction(const FunctionDef &mm, bool isSignal = false) { } QList<ArgumentDef> names = mm.arguments; QVector<int> types; - int inputCount = qDBusParametersForMethod(mm, types); - if (inputCount == -1) + QString errorMsg; + int inputCount = qDBusParametersForMethod(mm, types, errorMsg); + if (inputCount == -1) { + qWarning() << qPrintable(errorMsg); return QString(); // invalid form + } if (isSignal && inputCount + 1 != types.count()) return QString(); // signal with output arguments? if (isSignal && types.at(inputCount) == QDBusMetaTypeId::message()) diff --git a/src/tools/qdbusxml2cpp/qdbusxml2cpp.cpp b/src/tools/qdbusxml2cpp/qdbusxml2cpp.cpp index e6d77643de..f2b9441ea4 100644 --- a/src/tools/qdbusxml2cpp/qdbusxml2cpp.cpp +++ b/src/tools/qdbusxml2cpp/qdbusxml2cpp.cpp @@ -401,6 +401,8 @@ static QStringList makeArgNames(const QDBusIntrospection::Arguments &inputArgs, QString name = arg.name; if (name.isEmpty()) name = QString( QLatin1String("in%1") ).arg(i); + else + name.replace(QLatin1Char('-'), QLatin1Char('_')); while (retval.contains(name)) name += QLatin1String("_"); retval << name; @@ -410,6 +412,8 @@ static QStringList makeArgNames(const QDBusIntrospection::Arguments &inputArgs, QString name = arg.name; if (name.isEmpty()) name = QString( QLatin1String("out%1") ).arg(i); + else + name.replace(QLatin1Char('-'), QLatin1Char('_')); while (retval.contains(name)) name += QLatin1String("_"); retval << name; diff --git a/src/tools/qdoc/codemarker.cpp b/src/tools/qdoc/codemarker.cpp index c7d9c5b339..8faac66b1b 100644 --- a/src/tools/qdoc/codemarker.cpp +++ b/src/tools/qdoc/codemarker.cpp @@ -398,7 +398,7 @@ void CodeMarker::insert(FastSection &fastSection, bool inheritedMember = false; if (!node->relates()) { InnerNode* p = node->parent(); - if (p->subType() == Node::QmlPropertyGroup) + if (p->type() == Node::QmlPropertyGroup) p = p->parent(); if (p != fastSection.parent_) { // && !node->parent()->isAbstract()) { if (p->subType() != Node::QmlClass || !p->isAbstract()) { diff --git a/src/tools/qdoc/codeparser.cpp b/src/tools/qdoc/codeparser.cpp index 7b534a6c95..1be67894cc 100644 --- a/src/tools/qdoc/codeparser.cpp +++ b/src/tools/qdoc/codeparser.cpp @@ -65,6 +65,7 @@ QT_BEGIN_NAMESPACE #define COMMAND_PAGEKEYWORDS Doc::alias(QLatin1String("pagekeywords")) #define COMMAND_PRELIMINARY Doc::alias(QLatin1String("preliminary")) #define COMMAND_INPUBLICGROUP Doc::alias(QLatin1String("inpublicgroup")) +#define COMMAND_QTVARIABLE Doc::alias(QLatin1String("qtvariable")) #define COMMAND_REENTRANT Doc::alias(QLatin1String("reentrant")) #define COMMAND_SINCE Doc::alias(QLatin1String("since")) #define COMMAND_SUBTITLE Doc::alias(QLatin1String("subtitle")) @@ -199,29 +200,34 @@ CodeParser *CodeParser::parserForSourceFile(const QString &filePath) return 0; } +static QSet<QString> commonMetaCommands_; /*! Returns the set of strings representing the common metacommands. */ -QSet<QString> CodeParser::commonMetaCommands() +const QSet<QString>& CodeParser::commonMetaCommands() { - return QSet<QString>() << COMMAND_COMPAT - << COMMAND_DEPRECATED - << COMMAND_INGROUP - << COMMAND_INMODULE - << COMMAND_INQMLMODULE - << COMMAND_INTERNAL - << COMMAND_MAINCLASS - << COMMAND_NONREENTRANT - << COMMAND_OBSOLETE - << COMMAND_PAGEKEYWORDS - << COMMAND_PRELIMINARY - << COMMAND_INPUBLICGROUP - << COMMAND_REENTRANT - << COMMAND_SINCE - << COMMAND_SUBTITLE - << COMMAND_THREADSAFE - << COMMAND_TITLE - << COMMAND_WRAPPER; + if (commonMetaCommands_.isEmpty()) { + commonMetaCommands_ << COMMAND_COMPAT + << COMMAND_DEPRECATED + << COMMAND_INGROUP + << COMMAND_INMODULE + << COMMAND_INQMLMODULE + << COMMAND_INTERNAL + << COMMAND_MAINCLASS + << COMMAND_NONREENTRANT + << COMMAND_OBSOLETE + << COMMAND_PAGEKEYWORDS + << COMMAND_PRELIMINARY + << COMMAND_INPUBLICGROUP + << COMMAND_QTVARIABLE + << COMMAND_REENTRANT + << COMMAND_SINCE + << COMMAND_SUBTITLE + << COMMAND_THREADSAFE + << COMMAND_TITLE + << COMMAND_WRAPPER; + } + return commonMetaCommands_; } /*! @@ -269,8 +275,8 @@ void CodeParser::processCommonMetaCommand(const Location& location, if (!showInternal) { node->setAccess(Node::Private); node->setStatus(Node::Internal); - if (node->subType() == Node::QmlPropertyGroup) { - const QmlPropGroupNode* qpgn = static_cast<const QmlPropGroupNode*>(node); + if (node->type() == Node::QmlPropertyGroup) { + const QmlPropertyGroupNode* qpgn = static_cast<const QmlPropertyGroupNode*>(node); NodeList::ConstIterator p = qpgn->childNodes().constBegin(); while (p != qpgn->childNodes().constEnd()) { if ((*p)->type() == Node::QmlProperty) { @@ -317,6 +323,15 @@ void CodeParser::processCommonMetaCommand(const Location& location, else location.warning(tr("Ignored '\\%1'").arg(COMMAND_TITLE)); } + else if (command == COMMAND_QTVARIABLE) { + if (node->subType() == Node::Module) { + DocNode *dn = static_cast<DocNode *>(node); + dn->setQtVariable(arg.first); + } + else + location.warning(tr("Command '\\%1' found outside of '\\module'. It can only be used within a module page.") + .arg(COMMAND_QTVARIABLE)); + } } /*! diff --git a/src/tools/qdoc/codeparser.h b/src/tools/qdoc/codeparser.h index 8c398aeb05..89f661abeb 100644 --- a/src/tools/qdoc/codeparser.h +++ b/src/tools/qdoc/codeparser.h @@ -86,7 +86,7 @@ public: static const QString& currentOutputSubdirectory() { return currentSubDir_; } protected: - QSet<QString> commonMetaCommands(); + const QSet<QString>& commonMetaCommands(); void processCommonMetaCommand(const Location& location, const QString& command, const ArgLocPair& arg, diff --git a/src/tools/qdoc/config.cpp b/src/tools/qdoc/config.cpp index a475ccbfb6..8729bf387f 100644 --- a/src/tools/qdoc/config.cpp +++ b/src/tools/qdoc/config.cpp @@ -279,10 +279,19 @@ int Config::getInt(const QString& var) const */ QString Config::getOutputDir() const { + QString t; if (overrideOutputDir.isNull()) - return getString(QLatin1String(CONFIG_OUTPUTDIR)); + t = getString(QLatin1String(CONFIG_OUTPUTDIR)); else - return overrideOutputDir; + t = overrideOutputDir; + if (!Generator::useOutputSubdirs()) { + t = t.left(t.lastIndexOf('/')); + QString singleOutputSubdir = getString("HTML.outputsubdir"); + if (singleOutputSubdir.isEmpty()) + singleOutputSubdir = "html"; + t += QLatin1Char('/') + singleOutputSubdir; + } + return t; } /*! diff --git a/src/tools/qdoc/config.h b/src/tools/qdoc/config.h index 8787d27eb3..948f31c01a 100644 --- a/src/tools/qdoc/config.h +++ b/src/tools/qdoc/config.h @@ -165,7 +165,9 @@ private: #define CONFIG_ALIAS "alias" #define CONFIG_BASE "base" #define CONFIG_BASEDIR "basedir" +#define CONFIG_BUILDVERSION "buildversion" #define CONFIG_CODEINDENT "codeindent" +#define CONFIG_CPPCLASSESPAGE "cppclassespage" #define CONFIG_DEFINES "defines" #define CONFIG_DEPENDS "depends" #define CONFIG_DESCRIPTION "description" @@ -184,15 +186,18 @@ private: #define CONFIG_HEADERS "headers" #define CONFIG_HEADERSCRIPTS "headerscripts" #define CONFIG_HEADERSTYLES "headerstyles" +#define CONFIG_HOMEPAGE "homepage" #define CONFIG_IGNOREDIRECTIVES "ignoredirectives" #define CONFIG_IGNORETOKENS "ignoretokens" #define CONFIG_IMAGEDIRS "imagedirs" #define CONFIG_IMAGES "images" #define CONFIG_INDEXES "indexes" #define CONFIG_LANGUAGE "language" +#define CONFIG_LANDINGPAGE "landingpage" #define CONFIG_MACRO "macro" #define CONFIG_MANIFESTMETA "manifestmeta" #define CONFIG_NATURALLANGUAGE "naturallanguage" +#define CONFIG_NAVIGATION "navigation" #define CONFIG_NOLINKERRORS "nolinkerrors" #define CONFIG_OBSOLETELINKS "obsoletelinks" #define CONFIG_OUTPUTDIR "outputdir" @@ -201,7 +206,9 @@ private: #define CONFIG_OUTPUTFORMATS "outputformats" #define CONFIG_OUTPUTPREFIXES "outputprefixes" #define CONFIG_PROJECT "project" +#define CONFIG_REDIRECTDOCUMENTATIONTODEVNULL "redirectdocumentationtodevnull" #define CONFIG_QHP "qhp" +#define CONFIG_QMLTYPESPAGE "qmltypespage" #define CONFIG_QUOTINGINFORMATION "quotinginformation" #define CONFIG_SCRIPTDIRS "scriptdirs" #define CONFIG_SCRIPTS "scripts" diff --git a/src/tools/qdoc/cppcodemarker.cpp b/src/tools/qdoc/cppcodemarker.cpp index 75e49f288a..ad3c5cba47 100644 --- a/src/tools/qdoc/cppcodemarker.cpp +++ b/src/tools/qdoc/cppcodemarker.cpp @@ -1110,40 +1110,15 @@ QList<Section> CppCodeMarker::qmlSections(const QmlClassNode* qmlClassNode, Syno while (qcn != 0) { NodeList::ConstIterator c = qcn->childNodes().constBegin(); while (c != qcn->childNodes().constEnd()) { - if ((*c)->subType() == Node::QmlPropertyGroup) { - const QmlPropGroupNode* qpgn = static_cast<const QmlPropGroupNode*>(*c); - NodeList::ConstIterator p = qpgn->childNodes().constBegin(); - while (p != qpgn->childNodes().constEnd()) { - if ((*p)->type() == Node::QmlProperty) { - const QmlPropertyNode* pn = static_cast<const QmlPropertyNode*>(*p); - if (pn->isAttached()) - insert(qmlattachedproperties,*p,style,Okay); - else - insert(qmlproperties,*p,style,Okay); - } - ++p; - } + if ((*c)->type() == Node::QmlPropertyGroup) { + insert(qmlproperties, *c, style, Okay); } else if ((*c)->type() == Node::QmlProperty) { const QmlPropertyNode* pn = static_cast<const QmlPropertyNode*>(*c); - if (pn->qmlPropNodes().isEmpty()) { - if (pn->isAttached()) - insert(qmlattachedproperties,*c,style,Okay); - else - insert(qmlproperties,*c,style,Okay); - } + if (pn->isAttached()) + insert(qmlattachedproperties,*c,style,Okay); else { - NodeList::ConstIterator p = pn->qmlPropNodes().constBegin(); - while (p != pn->qmlPropNodes().constEnd()) { - if ((*p)->type() == Node::QmlProperty) { - const QmlPropertyNode* pn = static_cast<const QmlPropertyNode*>(*p); - if (pn->isAttached()) - insert(qmlattachedproperties,*p,style,Okay); - else - insert(qmlproperties,*p,style,Okay); - } - ++p; - } + insert(qmlproperties,*c,style,Okay); } } else if ((*c)->type() == Node::QmlSignal) { @@ -1196,24 +1171,8 @@ QList<Section> CppCodeMarker::qmlSections(const QmlClassNode* qmlClassNode, Syno while (qcn != 0) { NodeList::ConstIterator c = qcn->childNodes().constBegin(); while (c != qcn->childNodes().constEnd()) { - if ((*c)->subType() == Node::QmlPropertyGroup) { - bool attached = false; - const QmlPropGroupNode* pgn = static_cast<const QmlPropGroupNode*>(*c); - NodeList::ConstIterator C = pgn->childNodes().constBegin(); - while (C != pgn->childNodes().constEnd()) { - if ((*C)->type() == Node::QmlProperty) { - const QmlPropertyNode* pn = static_cast<const QmlPropertyNode*>(*C); - if (pn->isAttached()) { - attached = true; - break; - } - } - ++C; - } - if (attached) - insert(qmlattachedproperties,*c,style,Okay); - else - insert(qmlproperties,*c,style,Okay); + if ((*c)->type() == Node::QmlPropertyGroup) { + insert(qmlproperties,*c,style,Okay); } else if ((*c)->type() == Node::QmlProperty) { const QmlPropertyNode* pn = static_cast<const QmlPropertyNode*>(*c); @@ -1278,8 +1237,8 @@ QList<Section> CppCodeMarker::qmlSections(const QmlClassNode* qmlClassNode, Syno } NodeList::ConstIterator c = current->childNodes().constBegin(); while (c != current->childNodes().constEnd()) { - if ((*c)->subType() == Node::QmlPropertyGroup) { - const QmlPropGroupNode* qpgn = static_cast<const QmlPropGroupNode*>(*c); + if ((*c)->type() == Node::QmlPropertyGroup) { + const QmlPropertyGroupNode* qpgn = static_cast<const QmlPropertyGroupNode*>(*c); NodeList::ConstIterator p = qpgn->childNodes().constBegin(); while (p != qpgn->childNodes().constEnd()) { if ((*p)->type() == Node::QmlProperty) { diff --git a/src/tools/qdoc/cppcodeparser.cpp b/src/tools/qdoc/cppcodeparser.cpp index 5c25eeedc4..3e63432047 100644 --- a/src/tools/qdoc/cppcodeparser.cpp +++ b/src/tools/qdoc/cppcodeparser.cpp @@ -272,37 +272,42 @@ void CppCodeParser::doneParsingSourceFiles() qdb_->treeRoot()->makeUndocumentedChildrenInternal(); } +static QSet<QString> topicCommands_; /*! Returns the set of strings reopresenting the topic commands. */ -QSet<QString> CppCodeParser::topicCommands() +const QSet<QString>& CppCodeParser::topicCommands() { - return QSet<QString>() << COMMAND_CLASS - << COMMAND_DITAMAP - << COMMAND_ENUM - << COMMAND_EXAMPLE - << COMMAND_EXTERNALPAGE - << COMMAND_FILE - << COMMAND_FN - << COMMAND_GROUP - << COMMAND_HEADERFILE - << COMMAND_MACRO - << COMMAND_MODULE - << COMMAND_NAMESPACE - << COMMAND_PAGE - << COMMAND_PROPERTY - << COMMAND_TYPEDEF - << COMMAND_VARIABLE - << COMMAND_QMLCLASS - << COMMAND_QMLTYPE - << COMMAND_QMLPROPERTY - << COMMAND_QMLATTACHEDPROPERTY - << COMMAND_QMLSIGNAL - << COMMAND_QMLATTACHEDSIGNAL - << COMMAND_QMLMETHOD - << COMMAND_QMLATTACHEDMETHOD - << COMMAND_QMLBASICTYPE - << COMMAND_QMLMODULE; + if (topicCommands_.isEmpty()) { + topicCommands_ << COMMAND_CLASS + << COMMAND_DITAMAP + << COMMAND_ENUM + << COMMAND_EXAMPLE + << COMMAND_EXTERNALPAGE + << COMMAND_FILE + << COMMAND_FN + << COMMAND_GROUP + << COMMAND_HEADERFILE + << COMMAND_MACRO + << COMMAND_MODULE + << COMMAND_NAMESPACE + << COMMAND_PAGE + << COMMAND_PROPERTY + << COMMAND_TYPEDEF + << COMMAND_VARIABLE + << COMMAND_QMLCLASS + << COMMAND_QMLTYPE + << COMMAND_QMLPROPERTY + << COMMAND_QMLPROPERTYGROUP + << COMMAND_QMLATTACHEDPROPERTY + << COMMAND_QMLSIGNAL + << COMMAND_QMLATTACHEDSIGNAL + << COMMAND_QMLMETHOD + << COMMAND_QMLATTACHEDMETHOD + << COMMAND_QMLBASICTYPE + << COMMAND_QMLMODULE; + } + return topicCommands_; } /*! @@ -607,10 +612,10 @@ Node* CppCodeParser::processTopicCommand(const Doc& doc, (command == COMMAND_QMLATTACHEDSIGNAL) || (command == COMMAND_QMLATTACHEDMETHOD)) { QString module; - QString element; + QString qmlType; QString type; - if (splitQmlMethodArg(arg.first,type,module,element)) { - QmlClassNode* qmlClass = qdb_->findQmlType(module,element); + if (splitQmlMethodArg(arg.first,type,module,qmlType)) { + QmlClassNode* qmlClass = qdb_->findQmlType(module,qmlType); if (qmlClass) { bool attached = false; Node::Type nodeType = Node::QmlMethod; @@ -643,28 +648,57 @@ Node* CppCodeParser::processTopicCommand(const Doc& doc, } /*! + A QML property group argument has the form... + + <QML-module>::<QML-type>::<name> + + This function splits the argument into those parts. + A <QML-module> is the QML equivalent of a C++ namespace. + So this function splits \a arg on "::" and stores the + parts in \a module, \a qmlType, and \a name, and returns + true. If any part is not found, a qdoc warning is emitted + and false is returned. + */ +bool CppCodeParser::splitQmlPropertyGroupArg(const QString& arg, + QString& module, + QString& qmlType, + QString& name) +{ + QStringList colonSplit = arg.split("::"); + if (colonSplit.size() == 3) { + module = colonSplit[0]; + qmlType = colonSplit[1]; + name = colonSplit[2]; + return true; + } + QString msg = "Unrecognizable QML module/component qualifier for " + arg; + location().warning(tr(msg.toLatin1().data())); + return false; +} + +/*! A QML property argument has the form... - <type> <element>::<name> - <type> <QML-module>::<element>::<name> + <type> <QML-type>::<name> + <type> <QML-module>::<QML-type>::<name> This function splits the argument into one of those two forms. The three part form is the old form, which was used before the creation of Qt Quick 2 and Qt Components. A <QML-module> is the QML equivalent of a C++ namespace. So this function splits \a arg on "::" - and stores the parts in \a type, \a module, \a element, + and stores the parts in \a type, \a module, \a qmlType, and \a name, and returns true. If any part other than \a module is not found, a qdoc warning is emitted and false is returned. - \note The two elements \e{Component} and \e{QtObject} never - have a module qualifier. + \note The two QML types \e{Component} and \e{QtObject} + never have a module qualifier. */ bool CppCodeParser::splitQmlPropertyArg(const QString& arg, QString& type, QString& module, - QString& element, + QString& qmlType, QString& name) { QStringList blankSplit = arg.split(QLatin1Char(' ')); @@ -673,13 +707,13 @@ bool CppCodeParser::splitQmlPropertyArg(const QString& arg, QStringList colonSplit(blankSplit[1].split("::")); if (colonSplit.size() == 3) { module = colonSplit[0]; - element = colonSplit[1]; + qmlType = colonSplit[1]; name = colonSplit[2]; return true; } if (colonSplit.size() == 2) { module.clear(); - element = colonSplit[0]; + qmlType = colonSplit[0]; name = colonSplit[1]; return true; } @@ -696,21 +730,21 @@ bool CppCodeParser::splitQmlPropertyArg(const QString& arg, /*! A QML signal or method argument has the form... - <type> <element>::<name>(<param>, <param>, ...) - <type> <QML-module>::<element>::<name>(<param>, <param>, ...) + <type> <QML-type>::<name>(<param>, <param>, ...) + <type> <QML-module>::<QML-type>::<name>(<param>, <param>, ...) This function splits the argument into one of those two - forms, sets \a module, \a element, and \a name, and returns + forms, sets \a module, \a qmlType, and \a name, and returns true. If the argument doesn't match either form, an error message is emitted and false is returned. - \note The two elements \e{Component} and \e{QtObject} never + \note The two QML types \e{Component} and \e{QtObject} never have a module qualifier. */ bool CppCodeParser::splitQmlMethodArg(const QString& arg, QString& type, QString& module, - QString& element) + QString& qmlType) { QStringList colonSplit(arg.split("::")); if (colonSplit.size() > 1) { @@ -719,22 +753,22 @@ bool CppCodeParser::splitQmlMethodArg(const QString& arg, type = blankSplit[0]; if (colonSplit.size() > 2) { module = blankSplit[1]; - element = colonSplit[1]; + qmlType = colonSplit[1]; } else { module.clear(); - element = blankSplit[1]; + qmlType = blankSplit[1]; } } else { type.clear(); if (colonSplit.size() > 2) { module = colonSplit[0]; - element = colonSplit[1]; + qmlType = colonSplit[1]; } else { module.clear(); - element = colonSplit[0]; + qmlType = colonSplit[0]; } } return true; @@ -750,79 +784,118 @@ bool CppCodeParser::splitQmlMethodArg(const QString& arg, Currently, this function is called only for \e{qmlproperty} and \e{qmlattachedproperty}. */ -Node* CppCodeParser::processTopicCommandGroup(const Doc& doc, - const QString& command, - const ArgList& args) +void CppCodeParser::processQmlProperties(const Doc& doc, NodeList& nodes, DocList& docs) { - QmlPropGroupNode* qmlPropGroup = 0; - if ((command == COMMAND_QMLPROPERTY) || - (command == COMMAND_QMLATTACHEDPROPERTY)) { - QString arg; - QString type; - QString module; - QString element; - QString property; - QmlClassNode* qmlClass = 0; - bool attached = (command == COMMAND_QMLATTACHEDPROPERTY); - ArgList::ConstIterator argsIter = args.constBegin(); - arg = argsIter->first; - if (splitQmlPropertyArg(arg,type,module,element,property)) { - qmlClass = qdb_->findQmlType(module,element); - if (qmlClass) { - qmlPropGroup = new QmlPropGroupNode(qmlClass,property); //,attached); - qmlPropGroup->setLocation(doc.startLocation()); - } + QString arg; + QString type; + QString topic; + QString module; + QString qmlType; + QString property; + QmlPropertyNode* qpn = 0; + QmlClassNode* qmlClass = 0; + QmlPropertyGroupNode* qpgn = 0; + + Topic qmlPropertyGroupTopic; + const TopicList& topics = doc.topicsUsed(); + for (int i=0; i<topics.size(); ++i) { + if (topics.at(i).topic == COMMAND_QMLPROPERTYGROUP) { + qmlPropertyGroupTopic = topics.at(i); + break; } - if (qmlPropGroup) { - if (qmlClass->hasProperty(property)) { - doc.startLocation().warning(tr("QML property documented multiple times: '%1'").arg(arg)); + } + if (qmlPropertyGroupTopic.isEmpty() && topics.size() > 1) { + qmlPropertyGroupTopic = topics.at(0); + qmlPropertyGroupTopic.topic = COMMAND_QMLPROPERTYGROUP; + arg = qmlPropertyGroupTopic.args; + if (splitQmlPropertyArg(arg, type, module, qmlType, property)) { + int i = property.indexOf('.'); + if (i != -1) { + property = property.left(i); + qmlPropertyGroupTopic.args = module + "::" + qmlType + "::" + property; + doc.location().warning(tr("No QML property group command found; using \\%1 %2") + .arg(COMMAND_QMLPROPERTYGROUP).arg(qmlPropertyGroupTopic.args)); } else { - QmlPropertyNode *qmlPropNode = new QmlPropertyNode(qmlPropGroup,property,type,attached); - qmlPropNode->setLocation(doc.startLocation()); + /* + Assumption: No '.' in the property name + means there is no property group. + */ + qmlPropertyGroupTopic.clear(); + } + } + } + + if (!qmlPropertyGroupTopic.isEmpty()) { + arg = qmlPropertyGroupTopic.args; + if (splitQmlPropertyGroupArg(arg, module, qmlType, property)) { + qmlClass = qdb_->findQmlType(module, qmlType); + if (qmlClass) { + qpgn = new QmlPropertyGroupNode(qmlClass, property); + qpgn->setLocation(doc.startLocation()); } - ++argsIter; - while (argsIter != args.constEnd()) { - arg = argsIter->first; - if (splitQmlPropertyArg(arg,type,module,element,property)) { - if (qmlClass->hasProperty(property)) { - doc.startLocation().warning(tr("QML property documented multiple times: '%1'").arg(arg)); + } + if (topics.size() == 1) { + nodes.append(qpgn); + docs.append(doc); + return; + } + } + for (int i=0; i<topics.size(); ++i) { + if (topics.at(i).topic == COMMAND_QMLPROPERTYGROUP) + continue; + topic = topics.at(i).topic; + arg = topics.at(i).args; + if ((topic == COMMAND_QMLPROPERTY) || (topic == COMMAND_QMLATTACHEDPROPERTY)) { + bool attached = (topic == COMMAND_QMLATTACHEDPROPERTY); + if (splitQmlPropertyArg(arg, type, module, qmlType, property)) { + qmlClass = qdb_->findQmlType(module, qmlType); + if (qmlClass) { + if (qmlClass->hasQmlProperty(property) != 0) { + QString msg = tr("QML property documented multiple times: '%1'").arg(arg); + doc.startLocation().warning(msg); + } + else if (qpgn) { + qpn = new QmlPropertyNode(qpgn, property, type, attached); + qpn->setLocation(doc.startLocation()); } else { - QmlPropertyNode* qmlPropNode = new QmlPropertyNode(qmlPropGroup, - property, - type, - attached); - qmlPropNode->setLocation(doc.startLocation()); + qpn = new QmlPropertyNode(qmlClass, property, type, attached); + qpn->setLocation(doc.startLocation()); + nodes.append(qpn); + docs.append(doc); } } - ++argsIter; } } } - return qmlPropGroup; } +static QSet<QString> otherMetaCommands_; /*! Returns the set of strings representing the common metacommands plus some other metacommands. */ -QSet<QString> CppCodeParser::otherMetaCommands() +const QSet<QString>& CppCodeParser::otherMetaCommands() { - return commonMetaCommands() << COMMAND_INHEADERFILE - << COMMAND_OVERLOAD - << COMMAND_REIMP - << COMMAND_RELATES - << COMMAND_CONTENTSPAGE - << COMMAND_NEXTPAGE - << COMMAND_PREVIOUSPAGE - << COMMAND_INDEXPAGE - << COMMAND_STARTPAGE - << COMMAND_QMLINHERITS - << COMMAND_QMLINSTANTIATES - << COMMAND_QMLDEFAULT - << COMMAND_QMLREADONLY - << COMMAND_QMLABSTRACT; + if (otherMetaCommands_.isEmpty()) { + otherMetaCommands_ = commonMetaCommands(); + otherMetaCommands_ << COMMAND_INHEADERFILE + << COMMAND_OVERLOAD + << COMMAND_REIMP + << COMMAND_RELATES + << COMMAND_CONTENTSPAGE + << COMMAND_NEXTPAGE + << COMMAND_PREVIOUSPAGE + << COMMAND_INDEXPAGE + << COMMAND_STARTPAGE + << COMMAND_QMLINHERITS + << COMMAND_QMLINSTANTIATES + << COMMAND_QMLDEFAULT + << COMMAND_QMLREADONLY + << COMMAND_QMLABSTRACT; + } + return otherMetaCommands_; } /*! @@ -855,8 +928,8 @@ void CppCodeParser::processOtherMetaCommand(const Doc& doc, } } else if (command == COMMAND_REIMP) { - if (node->parent() && !node->parent()->isInternal()) { - if (node != 0 && node->type() == Node::Function) { + if (node != 0 && node->parent() && !node->parent()->isInternal()) { + if (node->type() == Node::Function) { FunctionNode *func = (FunctionNode *) node; const FunctionNode *from = func->reimplementedFrom(); if (from == 0) { @@ -961,8 +1034,8 @@ void CppCodeParser::processOtherMetaCommand(const Doc& doc, QmlPropertyNode* qpn = static_cast<QmlPropertyNode*>(node); qpn->setDefault(); } - else if (node->type() == Node::Document && node->subType() == Node::QmlPropertyGroup) { - QmlPropGroupNode* qpgn = static_cast<QmlPropGroupNode*>(node); + else if (node->type() == Node::QmlPropertyGroup) { + QmlPropertyGroupNode* qpgn = static_cast<QmlPropertyGroupNode*>(node); NodeList::ConstIterator p = qpgn->childNodes().constBegin(); while (p != qpgn->childNodes().constEnd()) { if ((*p)->type() == Node::QmlProperty) { @@ -978,8 +1051,8 @@ void CppCodeParser::processOtherMetaCommand(const Doc& doc, QmlPropertyNode* qpn = static_cast<QmlPropertyNode*>(node); qpn->setReadOnly(1); } - else if (node->type() == Node::Document && node->subType() == Node::QmlPropertyGroup) { - QmlPropGroupNode* qpgn = static_cast<QmlPropGroupNode*>(node); + else if (node->type() == Node::QmlPropertyGroup) { + QmlPropertyGroupNode* qpgn = static_cast<QmlPropertyGroupNode*>(node); NodeList::ConstIterator p = qpgn->childNodes().constBegin(); while (p != qpgn->childNodes().constEnd()) { if ((*p)->type() == Node::QmlProperty) { @@ -2067,10 +2140,9 @@ bool CppCodeParser::matchDeclList(InnerNode *parent) bool CppCodeParser::matchDocsAndStuff() { ExtraFuncData extra; - QSet<QString> topicCommandsAllowed = topicCommands(); - QSet<QString> otherMetacommandsAllowed = otherMetaCommands(); - QSet<QString> metacommandsAllowed = topicCommandsAllowed + - otherMetacommandsAllowed; + const QSet<QString>& topicCommandsAllowed = topicCommands(); + const QSet<QString>& otherMetacommandsAllowed = otherMetaCommands(); + const QSet<QString>& metacommandsAllowed = topicCommandsAllowed + otherMetacommandsAllowed; while (tok != Tok_Eoi) { if (tok == Tok_Doc) { @@ -2087,25 +2159,22 @@ bool CppCodeParser::matchDocsAndStuff() /* Doc parses the comment. */ - Doc doc(start_loc,end_loc,comment,metacommandsAllowed); - + Doc doc(start_loc,end_loc,comment,metacommandsAllowed, topicCommandsAllowed); QString topic; - ArgList args; - - QSet<QString> topicCommandsUsed = topicCommandsAllowed & doc.metaCommandsUsed(); + bool isQmlPropertyTopic = false; - /* - There should be one topic command in the set, - or none. If the set is empty, then the comment - should be a function description. - */ - if (topicCommandsUsed.count() > 0) { - topic = *topicCommandsUsed.constBegin(); - args = doc.metaCommandArgs(topic); + const TopicList& topics = doc.topicsUsed(); + if (!topics.isEmpty()) { + topic = topics[0].topic; + if ((topic == COMMAND_QMLPROPERTY) || + (topic == COMMAND_QMLPROPERTYGROUP) || + (topic == COMMAND_QMLATTACHEDPROPERTY)) { + isQmlPropertyTopic = true; + } } - + // if (isQmlPropertyTopic && doc.location().fileName().endsWith("qquickitem.cpp")) { NodeList nodes; - QList<Doc> docs; + DocList docs; if (topic.isEmpty()) { QStringList parentPath; @@ -2133,43 +2202,39 @@ bool CppCodeParser::matchDocsAndStuff() .arg(COMMAND_FN).arg(COMMAND_PAGE)); } } + else if (isQmlPropertyTopic) { + Doc nodeDoc = doc; + processQmlProperties(nodeDoc, nodes, docs); + } else { - /* - There is a topic command. Process it. - */ - if ((topic == COMMAND_QMLPROPERTY) || - (topic == COMMAND_QMLATTACHEDPROPERTY)) { + ArgList args; + const QSet<QString>& topicCommandsUsed = topicCommandsAllowed & doc.metaCommandsUsed(); + if (topicCommandsUsed.count() > 0) { + topic = *topicCommandsUsed.constBegin(); + args = doc.metaCommandArgs(topic); + } + if (topicCommandsUsed.count() > 1) { + QString topics; + QSet<QString>::ConstIterator t = topicCommandsUsed.constBegin(); + while (t != topicCommandsUsed.constEnd()) { + topics += " \\" + *t + ","; + ++t; + } + topics[topics.lastIndexOf(',')] = '.'; + int i = topics.lastIndexOf(','); + topics[i] = ' '; + topics.insert(i+1,"and"); + doc.location().warning(tr("Multiple topic commands found in comment: %1").arg(topics)); + } + ArgList::ConstIterator a = args.constBegin(); + while (a != args.constEnd()) { Doc nodeDoc = doc; - Node *node = processTopicCommandGroup(nodeDoc, topic,args); + Node *node = processTopicCommand(nodeDoc,topic,*a); if (node != 0) { nodes.append(node); docs.append(nodeDoc); } - } - else { - if (topicCommandsUsed.count() > 1) { - QString topics; - QSet<QString>::ConstIterator t = topicCommandsUsed.constBegin(); - while (t != topicCommandsUsed.constEnd()) { - topics += " \\" + *t + ","; - ++t; - } - topics[topics.lastIndexOf(',')] = '.'; - int i = topics.lastIndexOf(','); - topics[i] = ' '; - topics.insert(i+1,"and"); - doc.location().warning(tr("Multiple topic commands found in comment: %1").arg(topics)); - } - ArgList::ConstIterator a = args.constBegin(); - while (a != args.constEnd()) { - Doc nodeDoc = doc; - Node *node = processTopicCommand(nodeDoc,topic,*a); - if (node != 0) { - nodes.append(node); - docs.append(nodeDoc); - } - ++a; - } + ++a; } } @@ -2262,7 +2327,7 @@ bool CppCodeParser::makeFunctionNode(const QString& signature, the \a type. \a parent is the QML class node. The QML module and QML - element names have already been consumed to find \a parent. + type names have already been consumed to find \a parent. What remains in \a sig is the method signature. The method must be a child of \a parent. */ diff --git a/src/tools/qdoc/cppcodeparser.h b/src/tools/qdoc/cppcodeparser.h index 957142712b..5ab72f7f54 100644 --- a/src/tools/qdoc/cppcodeparser.h +++ b/src/tools/qdoc/cppcodeparser.h @@ -84,13 +84,16 @@ public: virtual void doneParsingSourceFiles(); protected: - virtual QSet<QString> topicCommands(); + const QSet<QString>& topicCommands(); + const QSet<QString>& otherMetaCommands(); virtual Node* processTopicCommand(const Doc& doc, const QString& command, const ArgLocPair& arg); - virtual Node *processTopicCommandGroup(const Doc& doc, - const QString& command, - const ArgList& args); + void processQmlProperties(const Doc& doc, NodeList& nodes, DocList& docs); + bool splitQmlPropertyGroupArg(const QString& arg, + QString& module, + QString& element, + QString& name); bool splitQmlPropertyArg(const QString& arg, QString& type, QString& module, @@ -100,7 +103,6 @@ protected: QString& type, QString& module, QString& element); - virtual QSet<QString> otherMetaCommands(); virtual void processOtherMetaCommand(const Doc& doc, const QString& command, const ArgLocPair& argLocPair, @@ -212,6 +214,7 @@ protected: #define COMMAND_QMLCLASS Doc::alias("qmlclass") #define COMMAND_QMLTYPE Doc::alias("qmltype") #define COMMAND_QMLPROPERTY Doc::alias("qmlproperty") +#define COMMAND_QMLPROPERTYGROUP Doc::alias("qmlpropertygroup") #define COMMAND_QMLATTACHEDPROPERTY Doc::alias("qmlattachedproperty") #define COMMAND_QMLINHERITS Doc::alias("inherits") #define COMMAND_QMLINSTANTIATES Doc::alias("instantiates") @@ -238,6 +241,7 @@ protected: #define COMMAND_LICENSENAME Doc::alias("licensename") #define COMMAND_LICENSEDESCRIPTION Doc::alias("licensedescription") #define COMMAND_RELEASEDATE Doc::alias("releasedate") +#define COMMAND_QTVARIABLE Doc::alias("qtvariable") QT_END_NAMESPACE diff --git a/src/tools/qdoc/ditaxmlgenerator.cpp b/src/tools/qdoc/ditaxmlgenerator.cpp index 96f5519be4..241fcbba43 100644 --- a/src/tools/qdoc/ditaxmlgenerator.cpp +++ b/src/tools/qdoc/ditaxmlgenerator.cpp @@ -3677,8 +3677,8 @@ QString DitaXmlGenerator::guidForNode(const Node* node) return fn->guid(); } case Node::Document: - if (node->subType() != Node::QmlPropertyGroup) - break; + break; + case Node::QmlPropertyGroup: case Node::QmlProperty: case Node::Property: return node->guid(); @@ -3743,7 +3743,7 @@ QString DitaXmlGenerator::linkForNode(const Node* node, const Node* relative) } QString link = fn; - if (!node->isInnerNode() || node->subType() == Node::QmlPropertyGroup) { + if (!node->isInnerNode() || node->type() == Node::QmlPropertyGroup) { QString guid = guidForNode(node); if (relative && fn == fileName(relative) && guid == guidForNode(relative)) { return QString(); @@ -3758,7 +3758,7 @@ QString DitaXmlGenerator::linkForNode(const Node* node, const Node* relative) back down into the other subdirectory. */ if (node && relative && (node != relative)) { - if (node->outputSubdirectory() != relative->outputSubdirectory()) + if (useOutputSubdirs() && node->outputSubdirectory() != relative->outputSubdirectory()) link.prepend(QString("../" + node->outputSubdirectory() + QLatin1Char('/'))); } return link; @@ -4079,8 +4079,8 @@ void DitaXmlGenerator::generateDetailedQmlMember(Node* node, QString marked; QmlPropertyNode* qpn = 0; - if (node->subType() == Node::QmlPropertyGroup) { - const QmlPropGroupNode* qpgn = static_cast<const QmlPropGroupNode*>(node); + if (node->type() == Node::QmlPropertyGroup) { + const QmlPropertyGroupNode* qpgn = static_cast<const QmlPropertyGroupNode*>(node); NodeList::ConstIterator p = qpgn->childNodes().constBegin(); if (qpgn->childNodes().size() == 1) { qpn = static_cast<QmlPropertyNode*>(*p); @@ -4114,50 +4114,10 @@ void DitaXmlGenerator::generateDetailedQmlMember(Node* node, } else if (node->type() == Node::QmlProperty) { qpn = static_cast<QmlPropertyNode*>(node); - if (qpn->qmlPropNodes().isEmpty()) { - startQmlProperty(qpn,relative,marker); - writeApiDesc(node, marker, node->title()); - writeEndTag(); // </qmlPropertyDetail> - writeEndTag(); // </qmlProperty> - } - else if (qpn->qmlPropNodes().size() == 1) { - Node* n = qpn->qmlPropNodes().at(0); - if (n->type() == Node::QmlProperty) { - qpn = static_cast<QmlPropertyNode*>(n); - startQmlProperty(qpn,relative,marker); - writeApiDesc(node, marker, node->title()); - writeEndTag(); // </qmlPropertyDetail> - writeEndTag(); // </qmlProperty> - } - } - else { - /* - The QML property node has multiple override nodes. - Process the whole list as we would for a QML property - group. - */ - writeStartTag(DT_qmlPropertyGroup); - QString id = "id-qml-propertygroup-" + node->name(); - id.replace('.','-'); - xmlWriter().writeAttribute("id",id); - writeStartTag(DT_apiName); - //writeCharacters("..."); - writeEndTag(); // </apiName> - writeStartTag(DT_qmlPropertyGroupDetail); - writeApiDesc(node, marker, node->title()); - writeEndTag(); // </qmlPropertyGroupDetail> - NodeList::ConstIterator p = qpn->qmlPropNodes().constBegin(); - while (p != qpn->qmlPropNodes().constEnd()) { - if ((*p)->type() == Node::QmlProperty) { - QmlPropertyNode* q = static_cast<QmlPropertyNode*>(*p); - startQmlProperty(q,relative,marker); - writeEndTag(); // </qmlPropertyDetail> - writeEndTag(); // </qmlProperty> - } - ++p; - } - writeEndTag(); // </qmlPropertyGroup - } + startQmlProperty(qpn,relative,marker); + writeApiDesc(node, marker, node->title()); + writeEndTag(); // </qmlPropertyDetail> + writeEndTag(); // </qmlProperty> } else if (node->type() == Node::QmlSignal) writeQmlRef(DT_qmlSignal,node,relative,marker); @@ -5326,13 +5286,13 @@ DitaXmlGenerator::generateInnerNode(InnerNode* node) return; if (docNode->subType() == Node::Image) return; - if (docNode->subType() == Node::QmlPropertyGroup) - return; if (docNode->subType() == Node::Page) { if (node->count() > 0) qDebug("PAGE %s HAS CHILDREN", qPrintable(docNode->title())); } } + else if (node->type() == Node::QmlPropertyGroup) + return; /* Obtain a code marker for the source file. @@ -5487,8 +5447,6 @@ Node* DitaXmlGenerator::collectNodesByTypeAndSubtype(const InnerNode* parent) if (!isDuplicate(nodeSubtypeMaps[Node::QmlClass],child->title(),child)) nodeSubtypeMaps[Node::QmlClass]->insert(child->title(),child); break; - case Node::QmlPropertyGroup: - break; case Node::QmlBasicType: if (!isDuplicate(nodeSubtypeMaps[Node::QmlBasicType],child->title(),child)) nodeSubtypeMaps[Node::QmlBasicType]->insert(child->title(),child); @@ -5517,6 +5475,8 @@ Node* DitaXmlGenerator::collectNodesByTypeAndSubtype(const InnerNode* parent) break; case Node::QmlProperty: break; + case Node::QmlPropertyGroup: + break; case Node::QmlSignal: break; case Node::QmlSignalHandler: diff --git a/src/tools/qdoc/doc.cpp b/src/tools/qdoc/doc.cpp index 42b98502e0..4d6b0b1a2c 100644 --- a/src/tools/qdoc/doc.cpp +++ b/src/tools/qdoc/doc.cpp @@ -80,7 +80,6 @@ enum { CMD_ANNOTATEDLIST, CMD_B, CMD_BADCODE, - CMD_BASENAME, CMD_BOLD, CMD_BR, CMD_BRIEF, @@ -198,7 +197,6 @@ static struct { { "annotatedlist", CMD_ANNOTATEDLIST, 0 }, { "b", CMD_B, 0 }, { "badcode", CMD_BADCODE, 0 }, - { "basename", CMD_BASENAME, 0 }, // ### don't document for now { "bold", CMD_BOLD, 0 }, { "br", CMD_BR, 0 }, { "brief", CMD_BRIEF, 0 }, @@ -316,7 +314,6 @@ Q_GLOBAL_STATIC(QHash_QString_Macro, macroHash) class DocPrivateExtra { public: - QString baseName; Doc::Sections granularity; Doc::Sections section; // ### QList<Atom*> tableOfContents; @@ -376,7 +373,7 @@ public: bool hasLegalese : 1; bool hasSectioningUnits : 1; DocPrivateExtra *extra; - TopicList topics; + TopicList topics_; DitaRefList ditamap_; }; @@ -466,7 +463,6 @@ private: Location& location(); QString detailsUnknownCommand(const QSet<QString>& metaCommandSet, const QString& str); - void insertBaseName(const QString &baseName); void insertTarget(const QString& target, bool keyword); void include(const QString& fileName, const QString& identifier); void startFormat(const QString& format, int cmd); @@ -571,7 +567,7 @@ void DocParser::parse(const QString& source, cachedPos = 0; priv = docPrivate; priv->text << Atom::Nop; - priv->topics.clear(); + priv->topics_.clear(); paraState = OutsideParagraph; inTableHeader = false; @@ -644,10 +640,6 @@ void DocParser::parse(const QString& source, leavePara(); append(Atom::CodeBad,getCode(CMD_BADCODE, marker)); break; - case CMD_BASENAME: - leavePara(); - insertBaseName(getArgument()); - break; case CMD_BR: leavePara(); append(Atom::BR); @@ -1404,7 +1396,7 @@ void DocParser::parse(const QString& source, QString arg = getMetaCommandArgument(cmdStr); priv->metaCommandMap[cmdStr].append(ArgLocPair(arg,location())); if (possibleTopics.contains(cmdStr)) { - priv->topics.append(Topic(cmdStr,arg)); + priv->topics_.append(Topic(cmdStr,arg)); } } else if (macroHash()->contains(cmdStr)) { @@ -1669,29 +1661,6 @@ QString DocParser::detailsUnknownCommand(const QSet<QString> &metaCommandSet, return tr("Maybe you meant '\\%1'?").arg(best); } -void DocParser::insertBaseName(const QString &baseName) -{ - priv->constructExtra(); - if (currentSection == priv->extra->section) { - priv->extra->baseName = baseName; - } - else { - Atom *atom = priv->text.firstAtom(); - Atom *sectionLeft = 0; - - int delta = currentSection - priv->extra->section; - - while (atom != 0) { - if (atom->type() == Atom::SectionLeft && - atom->string().toInt() == delta) - sectionLeft = atom; - atom = atom->next(); - } - if (sectionLeft != 0) - (void) new Atom(sectionLeft, Atom::BaseName, baseName); - } -} - void DocParser::insertTarget(const QString &target, bool keyword) { if (targetMap.contains(target)) { @@ -2751,6 +2720,7 @@ QString DocParser::slashed(const QString& str) #define COMMAND_BRIEF Doc::alias("brief") #define COMMAND_QMLBRIEF Doc::alias("qmlbrief") +#if 0 Doc::Doc(const Location& start_loc, const Location& end_loc, const QString& source, @@ -2760,6 +2730,7 @@ Doc::Doc(const Location& start_loc, DocParser parser; parser.parse(source,priv,metaCommandSet,QSet<QString>()); } +#endif /*! Parse the qdoc comment \a source. Build up a list of all the topic @@ -2978,17 +2949,6 @@ Text Doc::legaleseText() const return body().subText(Atom::LegaleseLeft, Atom::LegaleseRight); } -const QString& Doc::baseName() const -{ - static QString null; - if (priv == 0 || priv->extra == 0) { - return null; - } - else { - return priv->extra->baseName; - } -} - Doc::Sections Doc::granularity() const { if (priv == 0 || priv->extra == 0) { @@ -3026,7 +2986,7 @@ const QSet<QString> &Doc::metaCommandsUsed() const */ const TopicList& Doc::topicsUsed() const { - return priv == 0 ? *nullTopicList() : priv->topics; + return priv == 0 ? *nullTopicList() : priv->topics_; } ArgList Doc::metaCommandArgs(const QString& metacommand) const diff --git a/src/tools/qdoc/doc.h b/src/tools/qdoc/doc.h index ca9787595f..bd3d623a05 100644 --- a/src/tools/qdoc/doc.h +++ b/src/tools/qdoc/doc.h @@ -71,7 +71,10 @@ struct Topic { QString topic; QString args; + Topic() { } Topic(QString& t, QString a) : topic(t), args(a) { } + bool isEmpty() const { return topic.isEmpty(); } + void clear() { topic.clear(); args.clear(); } }; typedef QList<Topic> TopicList; @@ -136,10 +139,6 @@ public: }; Doc() : priv(0) {} - Doc(const Location &start_loc, - const Location &end_loc, - const QString &source, - const QSet<QString> &metaCommandSet); Doc(const Location& start_loc, const Location& end_loc, const QString& source, @@ -165,7 +164,6 @@ public: Text briefText(bool inclusive = false) const; Text trimmedBriefText(const QString &className) const; Text legaleseText() const; - const QString& baseName() const; Sections granularity() const; const QSet<QString> ¶meterNames() const; const QStringList &enumItemNames() const; @@ -196,6 +194,7 @@ private: void detach(); DocPrivate *priv; }; +typedef QList<Doc> DocList; QT_END_NAMESPACE diff --git a/src/tools/qdoc/doc/config/qdoc.qdocconf b/src/tools/qdoc/doc/config/qdoc.qdocconf index a7fbb38463..a6ae18a675 100644 --- a/src/tools/qdoc/doc/config/qdoc.qdocconf +++ b/src/tools/qdoc/doc/config/qdoc.qdocconf @@ -70,3 +70,5 @@ depends += \ qtwebkitexamples \ qtxml \ qtxmlpatterns + +navigation.landingpage = "QDoc Manual" diff --git a/src/tools/qdoc/generator.cpp b/src/tools/qdoc/generator.cpp index 889f0f55ca..f8d4910c28 100644 --- a/src/tools/qdoc/generator.cpp +++ b/src/tools/qdoc/generator.cpp @@ -97,7 +97,9 @@ QStringList Generator::styleDirs; QStringList Generator::styleFiles; bool Generator::debugging_ = false; bool Generator::noLinkErrors_ = false; +bool Generator::redirectDocumentationToDevNull_ = false; Generator::Passes Generator::qdocPass_ = Both; +bool Generator::useOutputSubdirs_ = true; void Generator::setDebugSegfaultFlag(bool b) { @@ -263,14 +265,17 @@ void Generator::writeOutFileNames() void Generator::beginSubPage(const InnerNode* node, const QString& fileName) { QString path = outputDir() + QLatin1Char('/'); - if (!node->outputSubdirectory().isEmpty()) + if (Generator::useOutputSubdirs() && !node->outputSubdirectory().isEmpty()) path += node->outputSubdirectory() + QLatin1Char('/'); path += fileName; - Generator::debugSegfault("Writing: " + path); - outFileNames.insert(fileName,fileName); - QFile* outFile = new QFile(path); + + QFile* outFile = new QFile(redirectDocumentationToDevNull_ ? QStringLiteral("/dev/null") : path); + if (outFile->exists()) + node->location().error(tr("HTML file already exists; overwriting %1").arg(outFile->fileName())); if (!outFile->open(QFile::WriteOnly)) node->location().fatal(tr("Cannot open output file '%1'").arg(outFile->fileName())); + Generator::debugSegfault("Writing: " + path); + outFileNames.insert(fileName,fileName); QTextStream* out = new QTextStream(outFile); #ifndef QT_NO_TEXTCODEC @@ -299,14 +304,22 @@ QString Generator::fileBase(const Node *node) const node = node->relates(); else if (!node->isInnerNode()) node = node->parent(); - if (node->subType() == Node::QmlPropertyGroup) { + if (node->type() == Node::QmlPropertyGroup) { node = node->parent(); } - QString base = node->doc().baseName(); - if (!base.isEmpty()) - return base; + if (node->type() == Node::Document && node->subType() == Node::Collision) { + const NameCollisionNode* ncn = static_cast<const NameCollisionNode*>(node); + if (ncn->currentChild()) + return fileBase(ncn->currentChild()); + } + + if (node->hasBaseName()) { + //qDebug() << "RETURNING:" << node->baseName(); + return node->baseName(); + } + QString base; const Node *p = node; forever { @@ -375,6 +388,8 @@ QString Generator::fileBase(const Node *node) const } while (res.endsWith(QLatin1Char('-'))) res.chop(1); + Node* n = const_cast<Node*>(node); + n->setBaseName(res); return res; } @@ -407,7 +422,7 @@ QMap<QString, QString>& Generator::formattingRightMap() /*! Returns the full document location. */ -QString Generator::fullDocumentLocation(const Node *node, bool subdir) +QString Generator::fullDocumentLocation(const Node *node, bool useSubdir) { if (!node) return QString(); @@ -419,11 +434,11 @@ QString Generator::fullDocumentLocation(const Node *node, bool subdir) QString fdl; /* - If the output is being sent to subdirectories of the - output directory, and if the subdir parameter is set, - prepend the subdirectory name + '/' to the result. + If the useSubdir parameter is set, then the output is + being sent to subdirectories of the output directory. + Prepend the subdirectory name + '/' to the result. */ - if (subdir) { + if (useSubdir) { fdl = node->outputSubdirectory(); if (!fdl.isEmpty()) fdl.append(QLatin1Char('/')); @@ -467,7 +482,7 @@ QString Generator::fullDocumentLocation(const Node *node, bool subdir) parentName = fullDocumentLocation(node->relates()); } else if ((parentNode = node->parent())) { - if (parentNode->subType() == Node::QmlPropertyGroup) { + if (parentNode->type() == Node::QmlPropertyGroup) { parentNode = parentNode->parent(); parentName = fullDocumentLocation(parentNode); } @@ -933,6 +948,8 @@ void Generator::generateInnerNode(InnerNode* node) { if (!node->url().isNull()) return; + if (node->isIndexNode()) + return; if (node->type() == Node::Document) { DocNode* docNode = static_cast<DocNode*>(node); @@ -940,13 +957,13 @@ void Generator::generateInnerNode(InnerNode* node) return; if (docNode->subType() == Node::Image) return; - if (docNode->subType() == Node::QmlPropertyGroup) - return; if (docNode->subType() == Node::Page) { if (node->count() > 0) qDebug("PAGE %s HAS CHILDREN", qPrintable(docNode->title())); } } + else if (node->type() == Node::QmlPropertyGroup) + return; /* Obtain a code marker for the source file. @@ -1099,7 +1116,10 @@ void Generator::generateSince(const Node *node, CodeMarker *marker) if (project.isEmpty()) text << "version"; else - text << project; + text << Atom(Atom::Link, project) + << Atom(Atom::FormattingLeft, ATOM_FORMATTING_LINK) + << Atom(Atom::String, project) + << Atom(Atom::FormattingRight, ATOM_FORMATTING_LINK); text << " " << since[0]; } else { // Reconstruct the <project> <version> string. @@ -1474,7 +1494,12 @@ QString Generator::indent(int level, const QString& markedCode) void Generator::initialize(const Config &config) { + + if (config.getBool(QString("HTML.nosubdirs"))) + resetUseOutputSubdirs(); + outputFormats = config.getOutputFormats(); + redirectDocumentationToDevNull_ = config.getBool(CONFIG_REDIRECTDOCUMENTATIONTODEVNULL); if (!outputFormats.isEmpty()) { outDir_ = config.getOutputDir(); if (outDir_.isEmpty()) { @@ -1487,7 +1512,7 @@ void Generator::initialize(const Config &config) QDir dirInfo; if (dirInfo.exists(outDir_)) { - if (!runGenerateOnly()) { + if (!runGenerateOnly() && Generator::useOutputSubdirs()) { if (!Config::removeDirContents(outDir_)) config.lastLocation().error(tr("Cannot empty output directory '%1'").arg(outDir_)); } @@ -1907,8 +1932,6 @@ QString Generator::typeString(const Node *node) switch (node->subType()) { case Node::QmlClass: return "type"; - case Node::QmlPropertyGroup: - return "property group"; case Node::QmlBasicType: return "type"; default: @@ -1923,6 +1946,16 @@ QString Generator::typeString(const Node *node) return "function"; case Node::Property: return "property"; + case Node::QmlPropertyGroup: + return "property group"; + case Node::QmlProperty: + return "QML property"; + case Node::QmlSignal: + return "QML signal"; + case Node::QmlSignalHandler: + return "QML signal handler"; + case Node::QmlMethod: + return "QML method"; default: return "documentation"; } diff --git a/src/tools/qdoc/generator.h b/src/tools/qdoc/generator.h index 58e9073922..52d73e8dea 100644 --- a/src/tools/qdoc/generator.h +++ b/src/tools/qdoc/generator.h @@ -81,7 +81,7 @@ public: virtual void initializeGenerator(const Config &config); virtual void terminateGenerator(); - QString fullDocumentLocation(const Node *node, bool subdir = false); + QString fullDocumentLocation(const Node *node, bool useSubdir = false); const Config* config() { return config_; } static Generator *currentGenerator() { return currentGenerator_; } @@ -100,6 +100,8 @@ public: static bool runPrepareOnly() { return (qdocPass_ == Prepare); } static bool runGenerateOnly() { return (qdocPass_ == Generate); } static QString defaultModuleName() { return project; } + static void resetUseOutputSubdirs() { useOutputSubdirs_ = false; } + static bool useOutputSubdirs() { return useOutputSubdirs_; } protected: virtual void beginSubPage(const InnerNode* node, const QString& fileName); @@ -185,6 +187,17 @@ protected: QString tagFile_; QStack<QTextStream*> outStreamStack; + void appendFullName(Text& text, + const Node *apparentNode, + const Node *relative, + 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); + void appendSortedNames(Text& text, const ClassNode *classe, const QList<RelatedClass> &classes); + private: static Generator* currentGenerator_; static QStringList exampleDirs; @@ -206,18 +219,10 @@ private: static QStringList styleFiles; static bool debugging_; static bool noLinkErrors_; + static bool redirectDocumentationToDevNull_; static Passes qdocPass_; + static bool useOutputSubdirs_; - void appendFullName(Text& text, - const Node *apparentNode, - const Node *relative, - 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); - void appendSortedNames(Text& text, const ClassNode *classe, const QList<RelatedClass> &classes); void generateReimplementedFrom(const FunctionNode *func, CodeMarker *marker); QString amp; diff --git a/src/tools/qdoc/helpprojectwriter.cpp b/src/tools/qdoc/helpprojectwriter.cpp index 0cdb2de776..44292f84bb 100644 --- a/src/tools/qdoc/helpprojectwriter.cpp +++ b/src/tools/qdoc/helpprojectwriter.cpp @@ -135,6 +135,7 @@ void HelpProjectWriter::readSelectors(SubProject &subproject, const QStringList typeHash["qmlsignal"] = Node::QmlSignal; typeHash["qmlsignalhandler"] = Node::QmlSignalHandler; typeHash["qmlmethod"] = Node::QmlMethod; + typeHash["qmlpropertygroup"] = Node::QmlPropertyGroup; QHash<QString, Node::SubType> subTypeHash; subTypeHash["example"] = Node::Example; @@ -145,7 +146,6 @@ void HelpProjectWriter::readSelectors(SubProject &subproject, const QStringList subTypeHash["page"] = Node::Page; subTypeHash["externalpage"] = Node::ExternalPage; subTypeHash["qmlclass"] = Node::QmlClass; - subTypeHash["qmlpropertygroup"] = Node::QmlPropertyGroup; subTypeHash["qmlbasictype"] = Node::QmlBasicType; QSet<Node::SubType> allSubTypes = QSet<Node::SubType>::fromList(subTypeHash.values()); @@ -225,7 +225,7 @@ QStringList HelpProjectWriter::keywordDetails(const Node *node) const details << node->name(); details << node->name(); } - details << gen_->fullDocumentLocation(node,true); + details << gen_->fullDocumentLocation(node,Generator::useOutputSubdirs()); return details; } @@ -285,12 +285,12 @@ bool HelpProjectWriter::generateSection(HelpProject &project, case Node::Class: project.keywords.append(keywordDetails(node)); - project.files.insert(gen_->fullDocumentLocation(node,true)); + project.files.insert(gen_->fullDocumentLocation(node,Generator::useOutputSubdirs())); break; case Node::Namespace: project.keywords.append(keywordDetails(node)); - project.files.insert(gen_->fullDocumentLocation(node,true)); + project.files.insert(gen_->fullDocumentLocation(node,Generator::useOutputSubdirs())); break; case Node::Enum: @@ -310,7 +310,7 @@ bool HelpProjectWriter::generateSection(HelpProject &project, details << item.name(); // "name" details << item.name(); // "id" } - details << gen_->fullDocumentLocation(node,true); + details << gen_->fullDocumentLocation(node,Generator::useOutputSubdirs()); project.keywords.append(details); } } @@ -342,7 +342,7 @@ bool HelpProjectWriter::generateSection(HelpProject &project, if (node->relates()) { project.memberStatus[node->relates()].insert(node->status()); - project.files.insert(gen_->fullDocumentLocation(node->relates(),true)); + project.files.insert(gen_->fullDocumentLocation(node->relates(),Generator::useOutputSubdirs())); } else if (node->parent()) project.memberStatus[node->parent()].insert(node->status()); } @@ -356,7 +356,7 @@ bool HelpProjectWriter::generateSection(HelpProject &project, // Use the location of any associated enum node in preference // to that of the typedef. if (enumNode) - typedefDetails[2] = gen_->fullDocumentLocation(enumNode,true); + typedefDetails[2] = gen_->fullDocumentLocation(enumNode,Generator::useOutputSubdirs()); project.keywords.append(typedefDetails); } @@ -364,7 +364,7 @@ bool HelpProjectWriter::generateSection(HelpProject &project, case Node::Variable: { - QString location = gen_->fullDocumentLocation(node,true); + QString location = gen_->fullDocumentLocation(node,Generator::useOutputSubdirs()); project.files.insert(location.left(location.lastIndexOf(QLatin1Char('#')))); project.keywords.append(keywordDetails(node)); } @@ -385,18 +385,18 @@ bool HelpProjectWriter::generateSection(HelpProject &project, QStringList details; details << keyword->string() << keyword->string() - << gen_->fullDocumentLocation(node,true) + + << gen_->fullDocumentLocation(node,Generator::useOutputSubdirs()) + QLatin1Char('#') + Doc::canonicalTitle(keyword->string()); project.keywords.append(details); } else docNode->doc().location().warning( - tr("Bad keyword in %1").arg(gen_->fullDocumentLocation(node,true)) + tr("Bad keyword in %1").arg(gen_->fullDocumentLocation(node,Generator::useOutputSubdirs())) ); } } project.keywords.append(keywordDetails(node)); } - project.files.insert(gen_->fullDocumentLocation(node,true)); + project.files.insert(gen_->fullDocumentLocation(node,Generator::useOutputSubdirs())); } break; } @@ -422,6 +422,11 @@ bool HelpProjectWriter::generateSection(HelpProject &project, void HelpProjectWriter::generateSections(HelpProject &project, QXmlStreamWriter &writer, const Node *node) { + /* + Don't include index nodes in the help file. Or DITA map nodes. + */ + if (node->isIndexNode() || node->subType() == Node::DitaMap) + return; if (!generateSection(project, writer, node)) return; @@ -431,29 +436,40 @@ void HelpProjectWriter::generateSections(HelpProject &project, // Ensure that we don't visit nodes more than once. QMap<QString, const Node*> childMap; foreach (const Node *childNode, inner->childNodes()) { + if (childNode->isIndexNode()) + continue; + if (childNode->access() == Node::Private) continue; if (childNode->type() == Node::Document) { + childMap[static_cast<const DocNode *>(childNode)->fullTitle()] = childNode; + } + else if (childNode->type() == Node::QmlPropertyGroup) { /* Don't visit QML property group nodes, but visit their children, which are all QML property nodes. + + This is probably not correct anymore, + because The Qml Property Group is an + actual documented thing. */ - if (childNode->subType() == Node::QmlPropertyGroup) { - const InnerNode* inner = static_cast<const InnerNode*>(childNode); - foreach (const Node* n, inner->childNodes()) { - if (n->access() == Node::Private) - continue; - childMap[n->fullDocumentName()] = n; - } + const InnerNode* inner = static_cast<const InnerNode*>(childNode); + foreach (const Node* n, inner->childNodes()) { + if (n->access() == Node::Private) + continue; + childMap[n->fullDocumentName()] = n; } - else - childMap[static_cast<const DocNode *>(childNode)->fullTitle()] = childNode; } else { // Store member status of children project.memberStatus[node].insert(childNode->status()); + if (childNode->relates()) { + project.memberStatus[childNode->relates()].insert(childNode->status()); + project.files.insert(gen_->fullDocumentLocation(childNode->relates(), + Generator::useOutputSubdirs())); + } if (childNode->type() == Node::Function) { const FunctionNode *funcNode = static_cast<const FunctionNode *>(childNode); @@ -508,7 +524,7 @@ void HelpProjectWriter::writeSection(QXmlStreamWriter &writer, const QString &pa void HelpProjectWriter::addMembers(HelpProject &project, QXmlStreamWriter &writer, const Node *node, bool writeSections) { - QString href = gen_->fullDocumentLocation(node,true); + QString href = gen_->fullDocumentLocation(node,Generator::useOutputSubdirs()); href = href.left(href.size()-5); if (href.isEmpty()) return; @@ -546,7 +562,7 @@ void HelpProjectWriter::addMembers(HelpProject &project, QXmlStreamWriter &write void HelpProjectWriter::writeNode(HelpProject &project, QXmlStreamWriter &writer, const Node *node) { - QString href = gen_->fullDocumentLocation(node,true); + QString href = gen_->fullDocumentLocation(node,Generator::useOutputSubdirs()); QString objName = node->name(); switch (node->type()) { @@ -642,7 +658,7 @@ void HelpProjectWriter::generateProject(HelpProject &project) node = qdb_->findNode(QStringList("index.html")); QString indexPath; if (node) - indexPath = gen_->fullDocumentLocation(node,true); + indexPath = gen_->fullDocumentLocation(node,Generator::useOutputSubdirs()); else indexPath = "index.html"; writer.writeAttribute("ref", indexPath); @@ -685,7 +701,8 @@ void HelpProjectWriter::generateProject(HelpProject &project) const DocNode *page = qdb_->findDocNodeByTitle(atom->string()); writer.writeStartElement("section"); - QString indexPath = gen_->fullDocumentLocation(page,true); + QString indexPath = gen_->fullDocumentLocation(page, + Generator::useOutputSubdirs()); writer.writeAttribute("ref", indexPath); writer.writeAttribute("title", atom->string()); project.files.insert(indexPath); @@ -710,7 +727,7 @@ void HelpProjectWriter::generateProject(HelpProject &project) if (!name.isEmpty()) { writer.writeStartElement("section"); - QString indexPath = gen_->fullDocumentLocation(qdb_->findDocNodeByTitle(subproject.indexTitle),true); + QString indexPath = gen_->fullDocumentLocation(qdb_->findDocNodeByTitle(subproject.indexTitle),Generator::useOutputSubdirs()); writer.writeAttribute("ref", indexPath); writer.writeAttribute("title", subproject.title); project.files.insert(indexPath); diff --git a/src/tools/qdoc/htmlgenerator.cpp b/src/tools/qdoc/htmlgenerator.cpp index 7cb56974d5..f17e3adde8 100644 --- a/src/tools/qdoc/htmlgenerator.cpp +++ b/src/tools/qdoc/htmlgenerator.cpp @@ -166,9 +166,9 @@ void HtmlGenerator::initializeGenerator(const Config &config) pleaseGenerateMacRef = config.getBool(HtmlGenerator::format() + Config::dot + HTMLGENERATOR_GENERATEMACREFS); - noBreadCrumbs = config.getBool(HtmlGenerator::format() + + noNavigationBar = config.getBool(HtmlGenerator::format() + Config::dot + - HTMLGENERATOR_NOBREADCRUMBS); + HTMLGENERATOR_NONAVIGATIONBAR); project = config.getString(CONFIG_PROJECT); @@ -229,6 +229,25 @@ void HtmlGenerator::initializeGenerator(const Config &config) examplesPath = config.getString(CONFIG_EXAMPLESINSTALLPATH); if (!examplesPath.isEmpty()) examplesPath += QLatin1Char('/'); + + //retrieve the config for the navigation bar + homepage = config.getString(CONFIG_NAVIGATION + + Config::dot + + CONFIG_HOMEPAGE); + + landingpage = config.getString(CONFIG_NAVIGATION + + Config::dot + + CONFIG_LANDINGPAGE); + + cppclassespage = config.getString(CONFIG_NAVIGATION + + Config::dot + + CONFIG_CPPCLASSESPAGE); + + qmltypespage = config.getString(CONFIG_NAVIGATION + + Config::dot + + CONFIG_QMLTYPESPAGE); + + buildversion = config.getString(CONFIG_BUILDVERSION); } /*! @@ -1095,8 +1114,6 @@ void HtmlGenerator::generateClassLikeNode(InnerNode* inner, CodeMarker* marker) QList<Section> sections; QList<Section>::ConstIterator s; - ClassNode* classe = 0; - QString title; QString rawTitle; QString fullTitle; @@ -1106,7 +1123,6 @@ void HtmlGenerator::generateClassLikeNode(InnerNode* inner, CodeMarker* marker) title = rawTitle + " Namespace"; } else if (inner->type() == Node::Class) { - classe = static_cast<ClassNode*>(inner); rawTitle = inner->plainName(); fullTitle = inner->plainFullName(); title = rawTitle + " Class"; @@ -1121,16 +1137,9 @@ void HtmlGenerator::generateClassLikeNode(InnerNode* inner, CodeMarker* marker) generateTableOfContents(inner,marker,§ions); generateTitle(title, subtitleText, SmallSubTitle, inner, marker); generateBrief(inner, marker); - generateIncludes(inner, marker); + generateRequisites(inner, marker); generateStatus(inner, marker); - if (classe) { - generateInherits(classe, marker); - generateInheritedBy(classe, marker); - if (classe->qmlElement() != 0) - generateInstantiatedBy(classe,marker); - } generateThreadSafeness(inner, marker); - generateSince(inner, marker); out() << "<ul>\n"; @@ -1511,10 +1520,7 @@ void HtmlGenerator::generateDocNode(DocNode* dn, CodeMarker* marker) const_cast<DocNode*>(dn)->setCurrentChild(); ClassNode* cn = qml_cn->classNode(); generateBrief(qml_cn, marker); - generateQmlInherits(qml_cn, marker); - generateQmlInheritedBy(qml_cn, marker); - generateQmlInstantiates(qml_cn, marker); - generateSince(qml_cn, marker); + generateQmlRequisites(qml_cn, marker); QString allQmlMembersLink = generateAllQmlMembersFile(qml_cn, marker); if (!allQmlMembersLink.isEmpty()) { @@ -1616,129 +1622,67 @@ QString HtmlGenerator::fileExtension() const } /*! - Output breadcrumb list in the html file. + Output navigation list in the html file. */ -void HtmlGenerator::generateBreadCrumbs(const QString &title, +void HtmlGenerator::generateNavigationBar(const QString &title, const Node *node, CodeMarker *marker) { - if (noBreadCrumbs) + if (noNavigationBar) return; - Text breadcrumbs; + Text navigationbar; + + if (homepage == title) + return; + if (!homepage.isEmpty()) + navigationbar << Atom(Atom::ListItemLeft) + << Atom(Atom::AutoLink, homepage) + << Atom(Atom::ListItemRight); + if (!landingpage.isEmpty() && landingpage != title) + navigationbar << Atom(Atom::ListItemLeft) + << Atom(Atom::AutoLink, landingpage) + << Atom(Atom::ListItemRight); + if (node->type() == Node::Class) { const ClassNode *cn = static_cast<const ClassNode *>(node); QString name = node->moduleName(); - breadcrumbs << Atom(Atom::ListItemLeft) - << Atom(Atom::Link, QLatin1String("All Modules")) - << Atom(Atom::FormattingLeft, ATOM_FORMATTING_LINK) - << Atom(Atom::String, QLatin1String("Modules")) - << Atom(Atom::FormattingRight, ATOM_FORMATTING_LINK) - << Atom(Atom::ListItemRight); - if (!name.isEmpty()) - breadcrumbs << Atom(Atom::ListItemLeft) - << Atom(Atom::AutoLink, name) + + if (!cppclassespage.isEmpty()) + navigationbar << Atom(Atom::ListItemLeft) + << Atom(Atom::Link, cppclassespage) + << Atom(Atom::FormattingLeft, ATOM_FORMATTING_LINK) + << Atom(Atom::String, QLatin1String("C++ Classes")) + << Atom(Atom::FormattingRight, ATOM_FORMATTING_LINK) << Atom(Atom::ListItemRight); + if (!cn->name().isEmpty()) - breadcrumbs << Atom(Atom::ListItemLeft) + navigationbar << Atom(Atom::ListItemLeft) << Atom(Atom::String, protectEnc(cn->name())) << Atom(Atom::ListItemRight); } else if (node->type() == Node::Document) { - const DocNode* fn = static_cast<const DocNode*>(node); - if (node->subType() == Node::Module) { - breadcrumbs << Atom(Atom::ListItemLeft) - << Atom(Atom::Link, QLatin1String("All Modules")) + if (node->subType() == Node::QmlClass || node->subType() == Node::QmlBasicType) { + if (!qmltypespage.isEmpty()) + navigationbar << Atom(Atom::ListItemLeft) + << Atom(Atom::Link, qmltypespage) << Atom(Atom::FormattingLeft, ATOM_FORMATTING_LINK) - << Atom(Atom::String, QLatin1String("Modules")) + << Atom(Atom::String, QLatin1String("QML Types")) << Atom(Atom::FormattingRight, ATOM_FORMATTING_LINK) << Atom(Atom::ListItemRight); - QString name = node->name(); - if (!name.isEmpty()) - breadcrumbs << Atom(Atom::ListItemLeft) - << Atom(Atom::String, protectEnc(name)) - << Atom(Atom::ListItemRight); - } - else if (node->subType() == Node::Group) { - if (fn->name() == QString("modules")) - breadcrumbs << Atom(Atom::String, QLatin1String("Modules")); - else - breadcrumbs << Atom(Atom::ListItemLeft) - << Atom(Atom::String, protectEnc(title)) - << Atom(Atom::ListItemRight); - } - else if (node->subType() == Node::Page) { - if (fn->name() == QString("qdeclarativeexamples.html")) { - breadcrumbs << Atom(Atom::ListItemLeft) - << Atom(Atom::Link, QLatin1String("Qt Examples")) - << Atom(Atom::FormattingLeft, ATOM_FORMATTING_LINK) - << Atom(Atom::String, QLatin1String("Examples")) - << Atom(Atom::FormattingRight, ATOM_FORMATTING_LINK) - << Atom(Atom::ListItemRight); - breadcrumbs << Atom(Atom::ListItemLeft) - << Atom(Atom::AutoLink, QLatin1String("QML Examples & Demos")) - << Atom(Atom::ListItemRight); - } - else if (fn->name().startsWith("examples-")) { - breadcrumbs << Atom(Atom::ListItemLeft) - << Atom(Atom::Link, QLatin1String("Qt Examples")) - << Atom(Atom::FormattingLeft, ATOM_FORMATTING_LINK) - << Atom(Atom::String, QLatin1String("Examples")) - << Atom(Atom::FormattingRight, ATOM_FORMATTING_LINK) - << Atom(Atom::ListItemRight); - breadcrumbs << Atom(Atom::ListItemLeft) - << Atom(Atom::String, protectEnc(title)) - << Atom(Atom::ListItemRight); - } - else if (fn->name() == QString("namespaces.html")) - breadcrumbs << Atom(Atom::String, QLatin1String("Namespaces")); - else - breadcrumbs << Atom(Atom::ListItemLeft) - << Atom(Atom::String, protectEnc(title)) - << Atom(Atom::ListItemRight); - } - else if (node->subType() == Node::QmlClass) { - breadcrumbs << Atom(Atom::ListItemLeft) - << Atom(Atom::AutoLink, QLatin1String("Basic QML Types")) - << Atom(Atom::ListItemRight); - breadcrumbs << Atom(Atom::ListItemLeft) + + navigationbar << Atom(Atom::ListItemLeft) << Atom(Atom::String, protectEnc(title)) << Atom(Atom::ListItemRight); } - else if (node->subType() == Node::Example) { - breadcrumbs << Atom(Atom::ListItemLeft) - << Atom(Atom::Link, QLatin1String("Qt Examples")) - << Atom(Atom::FormattingLeft, ATOM_FORMATTING_LINK) - << Atom(Atom::String, QLatin1String("Examples")) - << Atom(Atom::FormattingRight, ATOM_FORMATTING_LINK) - << Atom(Atom::ListItemRight); - QStringList sl = fn->name().split('/'); - if (sl.contains("declarative")) - breadcrumbs << Atom(Atom::ListItemLeft) - << Atom(Atom::AutoLink, QLatin1String("QML Examples & Demos")) - << Atom(Atom::ListItemRight); - else { - QString name = protectEnc("examples-" + sl.at(0) + ".html"); // this generates an empty link - QString t = CodeParser::titleFromName(name); - } - breadcrumbs << Atom(Atom::ListItemLeft) - << Atom(Atom::String, protectEnc(title)) - << Atom(Atom::ListItemRight); + else { + navigationbar << Atom(Atom::ListItemLeft) + << Atom(Atom::String, protectEnc(title)) + << Atom(Atom::ListItemRight); } } - else if (node->type() == Node::Namespace) { - breadcrumbs << Atom(Atom::ListItemLeft) - << Atom(Atom::Link, QLatin1String("All Namespaces")) - << Atom(Atom::FormattingLeft, ATOM_FORMATTING_LINK) - << Atom(Atom::String, QLatin1String("Namespaces")) - << Atom(Atom::FormattingRight, ATOM_FORMATTING_LINK) - << Atom(Atom::ListItemRight); - breadcrumbs << Atom(Atom::ListItemLeft) - << Atom(Atom::String, protectEnc(title)) - << Atom(Atom::ListItemRight); - } - generateText(breadcrumbs, node, marker); + generateText(navigationbar, node, marker); } void HtmlGenerator::generateHeader(const QString& title, @@ -1782,7 +1726,8 @@ void HtmlGenerator::generateHeader(const QString& title, #endif out() << QString(postHeader).replace("\\" + COMMAND_VERSION, qdb_->version()); - generateBreadCrumbs(title,node,marker); + generateNavigationBar(title,node,marker); + out() << "<li id=\"buildversion\">\n" << buildversion << "</li>\n"; out() << QString(postPostHeader).replace("\\" + COMMAND_VERSION, qdb_->version()); navigationLinks.clear(); @@ -1881,6 +1826,271 @@ void HtmlGenerator::generateFooter(const Node *node) out() << "</html>\n"; } +/*! +Lists the required imports and includes in a table. +The number of rows is known, so this path is simpler than the generateSection() path. +*/ +void HtmlGenerator::generateRequisites(InnerNode *inner, CodeMarker *marker) +{ + QMap<QString, Text> requisites; + Text text; + + const QString headerText = "Header"; + const QString sinceText = "Since"; + const QString inheritedBytext = "Inherited By"; + const QString inheritsText = "Inherits"; + const QString instantiatedByText = "Instantiated By"; + const QString qtVariableText = "qmake"; + + //add the includes to the map + if (!inner->includes().isEmpty()) { + text.clear(); + text << formattingRightMap()[ATOM_FORMATTING_BOLD] + << formattingLeftMap()[ATOM_FORMATTING_TELETYPE] + << highlightedCode(indent(codeIndent, + marker->markedUpIncludes(inner->includes())), + inner) + << formattingRightMap()[ATOM_FORMATTING_TELETYPE]; + requisites.insert(headerText, text); + } + + //The order of the requisites matter + QStringList requisiteorder; + requisiteorder << headerText + << qtVariableText + << sinceText + << instantiatedByText + << inheritsText + << inheritedBytext; + + //add the since and project into the map + if (!inner->since().isEmpty()) { + text.clear(); + QStringList since = inner->since().split(QLatin1Char(' ')); + if (since.count() == 1) { + // Handle legacy use of \since <version>. + if (project.isEmpty()) + text << "version"; + else + text << Atom(Atom::Link, project) + << Atom(Atom::FormattingLeft, ATOM_FORMATTING_LINK) + << Atom(Atom::String, project) + << Atom(Atom::FormattingRight, ATOM_FORMATTING_LINK); + text << " " << since[0]; + } + else { + // Reconstruct the <project> <version> string. + text << " " << since.join(' '); + } + text << Atom::ParaRight; + requisites.insert(sinceText, text); + } + + //add the instantiated-by to the map if the class node is not internal + if (inner->type() == Node::Class) { + ClassNode* classe = static_cast<ClassNode*>(inner); + if (classe->qmlElement() != 0 && classe->status() != Node::Internal) { + text.clear(); + text << Atom(Atom::LinkNode, CodeMarker::stringForNode(classe->qmlElement())) + << Atom(Atom::FormattingLeft, ATOM_FORMATTING_LINK) + << Atom(Atom::String, classe->qmlElement()->name()) + << Atom(Atom::FormattingRight, ATOM_FORMATTING_LINK); + requisites.insert(instantiatedByText, text); + + } + + //add the inherits to the map + QList<RelatedClass>::ConstIterator r; + int index; + if (!classe->baseClasses().isEmpty()) { + text.clear(); + r = classe->baseClasses().constBegin(); + index = 0; + while (r != classe->baseClasses().constEnd()) { + text << Atom(Atom::LinkNode, CodeMarker::stringForNode((*r).node)) + << Atom(Atom::FormattingLeft, ATOM_FORMATTING_LINK) + << Atom(Atom::String, (*r).dataTypeWithTemplateArgs) + << Atom(Atom::FormattingRight, ATOM_FORMATTING_LINK); + + if ((*r).access == Node::Protected) { + text << " (protected)"; + } + else if ((*r).access == Node::Private) { + text << " (private)"; + } + text << separator(index++, classe->baseClasses().count()); + ++r; + } + text << Atom::ParaRight; + requisites.insert(inheritsText, text); + } + + //add the inherited-by to the map + if (!classe->derivedClasses().isEmpty()) { + text.clear(); + text << Atom::ParaLeft; + appendSortedNames(text, classe, classe->derivedClasses()); + text << Atom::ParaRight; + requisites.insert(inheritedBytext, text); + } + + //add the QT variable to the map + DocNode * moduleNode = qdb_->findModule(classe->moduleName()); + if (moduleNode && !moduleNode->qtVariable().isEmpty()) { + text.clear(); + text << Atom(Atom::FormattingLeft, ATOM_FORMATTING_TELETYPE) + << "QT += " + moduleNode->qtVariable() + << Atom(Atom::FormattingRight, ATOM_FORMATTING_TELETYPE); + requisites.insert(qtVariableText, text); + } + + } + + if (!requisites.isEmpty()) { + //generate the table + out() << "<table class=\"alignedsummary\">\n"; + + QStringList::ConstIterator i; + for (i = requisiteorder.begin(); i != requisiteorder.constEnd(); ++i) { + + if (requisites.contains(*i)) { + out() << "<tr>" + << "<td class=\"memItemLeft rightAlign topAlign\"> " + << *i << ":" + << "</td><td class=\"memItemRight bottomAlign\"> "; + + if (*i == headerText) + out() << requisites.value(*i).toString(); + else + generateText(requisites.value(*i), inner, marker); + out() << "</td></tr>"; + } + } + out() << "</table>"; + } +} + +/*! +Lists the required imports and includes in a table. +The number of rows is known, so this path is simpler than the generateSection() path. +*/ +void HtmlGenerator::generateQmlRequisites(QmlClassNode *qcn, CodeMarker *marker) +{ + if (!qcn) + return; + QMap<QString, Text> requisites; + Text text; + + const QString importText = "Import Statement:"; + const QString sinceText = "Since:"; + const QString inheritedBytext = "Inherited By:"; + const QString inheritsText = "Inherits:"; + const QString instantiatesText = "Instantiates:"; + + //The order of the requisites matter + QStringList requisiteorder; + requisiteorder << importText + << sinceText + << instantiatesText + << inheritsText + << inheritedBytext; + + //add the module name and version to the map + text.clear(); + text << formattingRightMap()[ATOM_FORMATTING_BOLD] + << formattingLeftMap()[ATOM_FORMATTING_TELETYPE] + << "import " + qcn->qmlModuleName() + " " + qcn->qmlModuleVersion() + << formattingRightMap()[ATOM_FORMATTING_TELETYPE]; + requisites.insert(importText, text); + + //add the since and project into the map + if (!qcn->since().isEmpty()) { + text.clear(); + QStringList since = qcn->since().split(QLatin1Char(' ')); + if (since.count() == 1) { + // Handle legacy use of \since <version>. + if (project.isEmpty()) + text << "version"; + else + text << Atom(Atom::Link, project) + << Atom(Atom::FormattingLeft, ATOM_FORMATTING_LINK) + << Atom(Atom::String, project) + << Atom(Atom::FormattingRight, ATOM_FORMATTING_LINK); + + text << " " << since[0]; + } + else { + // Reconstruct the <project> <version> string. + text << " " << since.join(' '); + } + text << Atom::ParaRight; + requisites.insert(sinceText, text); + } + + //add the instantiates to the map + ClassNode* cn = qcn->classNode(); + if (cn && (cn->status() != Node::Internal)) { + text.clear(); + text << Atom(Atom::LinkNode,CodeMarker::stringForNode(qcn)); + text << Atom(Atom::FormattingLeft, ATOM_FORMATTING_LINK); + 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); + requisites.insert(instantiatesText, text); + } + + //add the inherits to the map + const QmlClassNode* base = qcn->qmlBaseNode(); + while (base && base->isInternal()) { + base = base->qmlBaseNode(); + } + if (base) { + text.clear(); + text << Atom::ParaLeft + << Atom(Atom::LinkNode,CodeMarker::stringForNode(base)) + << Atom(Atom::FormattingLeft, ATOM_FORMATTING_LINK) + << Atom(Atom::String, base->name()) + << Atom(Atom::FormattingRight, ATOM_FORMATTING_LINK) + << Atom::ParaRight; + requisites.insert(inheritsText, text); + } + + //add the inherited-by to the map + NodeList subs; + QmlClassNode::subclasses(qcn->name(), subs); + if (!subs.isEmpty()) { + text.clear(); + text << Atom::ParaLeft; + appendSortedQmlNames(text, qcn, subs); + text << Atom::ParaRight; + requisites.insert(inheritedBytext, text); + } + + if (!requisites.isEmpty()) { + //generate the table + out() << "<table class=\"alignedsummary\">\n"; + + QStringList::ConstIterator i; + for (i = requisiteorder.begin(); i != requisiteorder.constEnd(); ++i) { + + if (requisites.contains(*i)) { + out() << "<tr>" + << "<td class=\"memItemLeft rightAlign topAlign\"> " + << *i + << "</td><td class=\"memItemRight bottomAlign\"> "; + + if (*i == importText) + out()<<requisites.value(*i).toString(); + else + generateText(requisites.value(*i), qcn, marker); + out() << "</td></tr>"; + } + } + out() << "</table>"; + } +} + void HtmlGenerator::generateBrief(const Node *node, CodeMarker *marker, const Node *relative) { @@ -2151,7 +2361,10 @@ QString HtmlGenerator::generateLowStatusMemberFile(InnerNode *inner, fileName = fileBase(inner) + "-obsolete." + fileExtension(); } if (status == CodeMarker::Obsolete) { - QString link = QString("../" + Generator::outputSubdir() + QLatin1Char('/')) + fileName; + QString link; + if (useOutputSubdirs() && !Generator::outputSubdir().isEmpty()) + link = QString("../" + Generator::outputSubdir() + QLatin1Char('/')); + link += fileName; inner->setObsoleteLink(link); } @@ -2160,21 +2373,22 @@ QString HtmlGenerator::generateLowStatusMemberFile(InnerNode *inner, generateTitle(title, Text(), SmallSubTitle, inner, marker); if (status == CodeMarker::Compat) { - out() << "<p><b>The following class members are part of the " + out() << "<p><b>The following members of class " + << "<a href=\"" << linkForNode(inner, 0) << "\">" + << protectEnc(inner->name()) << "</a>" + << "are part of the " "Qt compatibility layer.</b> We advise against " "using them in new code.</p>\n"; } else { - out() << "<p><b>The following class members are obsolete.</b> " + out() << "<p><b>The following members of class " + << "<a href=\"" << linkForNode(inner, 0) << "\">" + << protectEnc(inner->name()) << "</a>" + << " 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) << "\">" - << protectEnc(inner->name()) - << " class reference</a></li></ul></p>\n"; - for (i = 0; i < sections.size(); ++i) { out() << "<h2>" << protectEnc(sections.at(i).name) << "</h2>\n"; generateSectionList(sections.at(i), inner, marker, CodeMarker::Summary); @@ -2492,8 +2706,10 @@ void HtmlGenerator::generateCompactList(ListType listType, } else if (listType == Obsolete) { QString fileName = fileBase(it.value()) + "-obsolete." + fileExtension(); - QString link = QString("../" + it.value()->outputSubdirectory() + - QLatin1Char('/')) + fileName; + QString link; + if (useOutputSubdirs()) + link = QString("../" + it.value()->outputSubdirectory() + QLatin1Char('/')); + link += fileName; out() << "<a href=\"" << link << "\">"; } @@ -3308,8 +3524,8 @@ QString HtmlGenerator::refForNode(const Node *node) } break; case Node::Document: - if (node->subType() != Node::QmlPropertyGroup) - break; + break; + case Node::QmlPropertyGroup: case Node::QmlProperty: case Node::Property: ref = node->name() + "-prop"; @@ -3372,7 +3588,7 @@ QString HtmlGenerator::linkForNode(const Node *node, const Node *relative) } QString link = fn; - if (!node->isInnerNode() || node->subType() == Node::QmlPropertyGroup) { + if (!node->isInnerNode() || node->type() == Node::QmlPropertyGroup) { QString ref = refForNode(node); if (relative && fn == fileName(relative) && ref == refForNode(relative)) return QString(); @@ -3387,7 +3603,7 @@ QString HtmlGenerator::linkForNode(const Node *node, const Node *relative) back down into the other subdirectory. */ if (node && relative && (node != relative)) { - if (node->outputSubdirectory() != relative->outputSubdirectory()) + if (useOutputSubdirs() && node->outputSubdirectory() != relative->outputSubdirectory()) link.prepend(QString("../" + node->outputSubdirectory() + QLatin1Char('/'))); } return link; @@ -3778,6 +3994,22 @@ void HtmlGenerator::generateQmlSummary(const Section& section, while (m != section.members.constEnd()) { out() << "<li class=\"fn\">"; generateQmlItem(*m,relative,marker,true); + if ((*m)->type() == Node::QmlPropertyGroup) { + const QmlPropertyGroupNode* qpgn = static_cast<const QmlPropertyGroupNode*>(*m); + if (!qpgn->childNodes().isEmpty()) { + NodeList::ConstIterator p = qpgn->childNodes().constBegin(); + out() << "<ul>\n"; + while (p != qpgn->childNodes().constEnd()) { + if ((*p)->type() == Node::QmlProperty) { + out() << "<li class=\"fn\">"; + generateQmlItem(*p, relative, marker, true); + out() << "</li>\n"; + } + ++p; + } + out() << "</ul>\n"; + } + } out() << "</li>\n"; ++m; } @@ -3799,11 +4031,18 @@ void HtmlGenerator::generateDetailedQmlMember(Node *node, #endif generateExtractionMark(node, MemberMark); out() << "<div class=\"qmlitem\">"; - if (node->subType() == Node::QmlPropertyGroup) { - const QmlPropGroupNode* qpgn = static_cast<const QmlPropGroupNode*>(node); + if (node->type() == Node::QmlPropertyGroup) { + const QmlPropertyGroupNode* qpgn = static_cast<const QmlPropertyGroupNode*>(node); NodeList::ConstIterator p = qpgn->childNodes().constBegin(); out() << "<div class=\"qmlproto\">"; out() << "<table class=\"qmlname\">"; + + QString heading = qpgn->name() + " group"; + out() << "<tr valign=\"top\" class=\"even\">"; + out() << "<th class=\"centerAlign\"><p>"; + out() << "<a name=\"" + refForNode(qpgn) + "\"></a>"; + out() << "<b>" << heading << "</b>"; + out() << "</p></th></tr>"; while (p != qpgn->childNodes().constEnd()) { if ((*p)->type() == Node::QmlProperty) { qpn = static_cast<QmlPropertyNode*>(*p); @@ -3825,68 +4064,23 @@ void HtmlGenerator::generateDetailedQmlMember(Node *node, } else if (node->type() == Node::QmlProperty) { qpn = static_cast<QmlPropertyNode*>(node); - /* - If the QML property node has a single subproperty, - override, replace qpn with that override node and - proceed as normal. - */ - if (qpn->qmlPropNodes().size() == 1) { - Node* n = qpn->qmlPropNodes().at(0); - if (n->type() == Node::QmlProperty) - qpn = static_cast<QmlPropertyNode*>(n); - } - /* - Now qpn either has no overrides, or it has more - than 1. If it has none, proceed to output as nortmal. - */ - if (qpn->qmlPropNodes().isEmpty()) { - out() << "<div class=\"qmlproto\">"; - out() << "<table class=\"qmlname\">"; - out() << "<tr valign=\"top\" class=\"odd\">"; - out() << "<td class=\"tblQmlPropNode\"><p>"; - out() << "<a name=\"" + refForNode(qpn) + "\"></a>"; - if (!qpn->isReadOnlySet()) { - if (qpn->declarativeCppNode()) - qpn->setReadOnly(!qpn->isWritable(qdb_)); - } - if (qpn->isReadOnly()) - out() << "<span class=\"qmlreadonly\">read-only</span>"; - if (qpn->isDefault()) - out() << "<span class=\"qmldefault\">default</span>"; - generateQmlItem(qpn, relative, marker, false); - out() << "</p></td></tr>"; - out() << "</table>"; - out() << "</div>"; - } - else { - /* - The QML property node has multiple override nodes. - Process the whole list as we would for a QML property - group. - */ - NodeList::ConstIterator p = qpn->qmlPropNodes().constBegin(); - out() << "<div class=\"qmlproto\">"; - out() << "<table class=\"qmlname\">"; - while (p != qpn->qmlPropNodes().constEnd()) { - if ((*p)->type() == Node::QmlProperty) { - QmlPropertyNode* q = static_cast<QmlPropertyNode*>(*p); - out() << "<tr valign=\"top\" class=\"odd\">"; - out() << "<td class=\"tblQmlPropNode\"><p>"; - out() << "<a name=\"" + refForNode(q) + "\"></a>"; - if (!qpn->isReadOnlySet()) - qpn->setReadOnly(!qpn->isWritable(qdb_)); - if (qpn->isReadOnly()) - out() << "<span class=\"qmlreadonly\">read-only</span>"; - if (qpn->isDefault()) - out() << "<span class=\"qmldefault\">default</span>"; - generateQmlItem(q, relative, marker, false); - out() << "</p></td></tr>"; - } - ++p; - } - out() << "</table>"; - out() << "</div>"; - } + out() << "<div class=\"qmlproto\">"; + out() << "<table class=\"qmlname\">"; + out() << "<tr valign=\"top\" class=\"odd\">"; + out() << "<td class=\"tblQmlPropNode\"><p>"; + out() << "<a name=\"" + refForNode(qpn) + "\"></a>"; + if (!qpn->isReadOnlySet()) { + if (qpn->declarativeCppNode()) + qpn->setReadOnly(!qpn->isWritable(qdb_)); + } + if (qpn->isReadOnly()) + out() << "<span class=\"qmlreadonly\">read-only</span>"; + if (qpn->isDefault()) + out() << "<span class=\"qmldefault\">default</span>"; + generateQmlItem(qpn, relative, marker, false); + out() << "</p></td></tr>"; + out() << "</table>"; + out() << "</div>"; } else if (node->type() == Node::QmlSignal) { const FunctionNode* qsn = static_cast<const FunctionNode*>(node); @@ -4359,8 +4553,6 @@ void HtmlGenerator::reportOrphans(const InnerNode* parent) break; case Node::QmlClass: break; - case Node::QmlPropertyGroup: - break; case Node::QmlBasicType: break; case Node::QmlModule: @@ -4394,6 +4586,8 @@ void HtmlGenerator::reportOrphans(const InnerNode* parent) if (!related) child->location().warning(tr("Global variable, %1, %2").arg(child->name()).arg(message)); break; + case Node::QmlPropertyGroup: + break; case Node::QmlProperty: if (!related) child->location().warning(tr("Global QML property, %1, %2").arg(child->name()).arg(message)); diff --git a/src/tools/qdoc/htmlgenerator.h b/src/tools/qdoc/htmlgenerator.h index 0a6717461e..8cd8664dfc 100644 --- a/src/tools/qdoc/htmlgenerator.h +++ b/src/tools/qdoc/htmlgenerator.h @@ -127,7 +127,7 @@ private: }; const QPair<QString,QString> anchorForNode(const Node *node); - void generateBreadCrumbs(const QString& title, + void generateNavigationBar(const QString& title, const Node *node, CodeMarker *marker); void generateHeader(const QString& title, @@ -139,6 +139,10 @@ private: const Node *relative, CodeMarker *marker); void generateFooter(const Node *node = 0); + void generateRequisites(InnerNode *inner, + CodeMarker *marker); + void generateQmlRequisites(QmlClassNode *qcn, + CodeMarker *marker); void generateBrief(const Node *node, CodeMarker *marker, const Node *relative = 0); @@ -182,6 +186,7 @@ private: void generateQmlInstantiates(QmlClassNode* qcn, CodeMarker* marker); void generateInstantiatedBy(ClassNode* cn, CodeMarker* marker); + void generateRequisitesTable(const QStringList& requisitesOrder, QMap<QString, Text>& requisites); void generateSection(const NodeList& nl, const Node *relative, CodeMarker *marker, @@ -239,7 +244,7 @@ private: QString footer; QString address; bool pleaseGenerateMacRef; - bool noBreadCrumbs; + bool noNavigationBar; QString project; QString projectDescription; QString projectUrl; @@ -252,6 +257,12 @@ private: QStack<QXmlStreamWriter*> xmlWriterStack; static int id; QList<ManifestMetaFilter> manifestMetaContent; + QString homepage; + QString landingpage; + QString cppclassespage; + QString qmltypespage; + QString buildversion; + public: static bool debugging_on; static QString divNavTop; @@ -262,9 +273,10 @@ public: #define HTMLGENERATOR_GENERATEMACREFS "generatemacrefs" // ### document me #define HTMLGENERATOR_POSTHEADER "postheader" #define HTMLGENERATOR_POSTPOSTHEADER "postpostheader" -#define HTMLGENERATOR_NOBREADCRUMBS "nobreadcrumbs" +#define HTMLGENERATOR_NONAVIGATIONBAR "nonavigationbar" +#define HTMLGENERATOR_NOSUBDIRS "nosubdirs" + QT_END_NAMESPACE #endif - diff --git a/src/tools/qdoc/main.cpp b/src/tools/qdoc/main.cpp index 3ec121f795..912cdad7eb 100644 --- a/src/tools/qdoc/main.cpp +++ b/src/tools/qdoc/main.cpp @@ -95,6 +95,7 @@ bool creationTimeBefore(const QFileInfo &fi1, const QFileInfo &fi2) static bool highlighting = false; static bool showInternal = false; +static bool redirectDocumentationToDevNull = false; static bool noLinkErrors = false; static bool obsoleteLinks = false; static QStringList defines; @@ -139,6 +140,8 @@ static void printHelp() "Run qdoc to read the index files and generate the docs\n" " -showinternal " "Include content marked internal\n" + " -redirect-documentation-to-dev-null " + "Save all documentation content to /dev/null. Useful if someone is interested in qdoc errors only.\n" " -version " "Display version of qdoc and exit\n") ); } @@ -162,6 +165,15 @@ static void loadIndexFiles(Config& config) dependModules += config.getStringList(CONFIG_DEPENDS); + bool noOutputSubdirs = false; + QString singleOutputSubdir; + if (config.getBool(QString("HTML.nosubdirs"))) { + noOutputSubdirs = true; + singleOutputSubdir = config.getString("HTML.outputsubdir"); + if (singleOutputSubdir.isEmpty()) + singleOutputSubdir = "html"; + } + // Allow modules and third-party application/libraries to link // to the Qt docs without having to explicitly pass --indexdir. if (!indexDirs.contains(documentationPath)) @@ -196,8 +208,12 @@ static void loadIndexFiles(Config& config) QString indexToAdd; QList<QFileInfo> foundIndices; for (int j = 0; j < indexDirs.size(); j++) { - QString fileToLookFor = indexDirs[j] + QLatin1Char('/') + dependModules[i] + - QLatin1Char('/') + dependModules[i] + QLatin1String(".index"); + QString fileToLookFor = indexDirs[j] + QLatin1Char('/'); + if (noOutputSubdirs) + fileToLookFor += singleOutputSubdir + QLatin1Char('/'); + else + fileToLookFor += dependModules[i] + QLatin1Char('/'); + fileToLookFor += dependModules[i] + QLatin1String(".index"); if (QFile::exists(fileToLookFor)) { QFileInfo tempFileInfo(fileToLookFor); if (!foundIndices.contains(tempFileInfo)) @@ -257,6 +273,7 @@ static void processQdocconfFile(const QString &fileName) } config.setStringList(CONFIG_SYNTAXHIGHLIGHTING, QStringList(highlighting ? "true" : "false")); config.setStringList(CONFIG_SHOWINTERNAL, QStringList(showInternal ? "true" : "false")); + config.setStringList(CONFIG_REDIRECTDOCUMENTATIONTODEVNULL, QStringList(redirectDocumentationToDevNull ? "true" : "false")); config.setStringList(CONFIG_NOLINKERRORS, QStringList(noLinkErrors ? "true" : "false")); config.setStringList(CONFIG_OBSOLETELINKS, QStringList(obsoleteLinks ? "true" : "false")); @@ -573,6 +590,9 @@ int main(int argc, char **argv) else if (opt == "-showinternal") { showInternal = true; } + else if (opt == "-redirect-documentation-to-dev-null") { + redirectDocumentationToDevNull = true; + } else if (opt == "-no-examples") { Config::generateExamples = false; } diff --git a/src/tools/qdoc/node.cpp b/src/tools/qdoc/node.cpp index 2184e302ae..fd56c77742 100644 --- a/src/tools/qdoc/node.cpp +++ b/src/tools/qdoc/node.cpp @@ -151,11 +151,11 @@ QString Node::fullName(const Node* relative) const */ void Node::setDoc(const Doc& doc, bool replace) { - if (!d.isEmpty() && !replace) { + if (!doc_.isEmpty() && !replace) { doc.location().warning(tr("Overrides a previous doc")); - d.location().warning(tr("(The previous doc is here)")); + doc_.location().warning(tr("(The previous doc is here)")); } - d = doc; + doc_ = doc; } /*! @@ -311,6 +311,8 @@ QString Node::nodeTypeString(unsigned t) return "variable"; case QmlProperty: return "QML property"; + case QmlPropertyGroup: + return "QML property group"; case QmlSignal: return "QML signal"; case QmlSignalHandler: @@ -359,8 +361,6 @@ QString Node::nodeSubtypeString(unsigned t) return "external page"; case QmlClass: return "QML type"; - case QmlPropertyGroup: - return "QML property group"; case QmlBasicType: return "QML basic type"; case QmlModule: @@ -742,12 +742,12 @@ void InnerNode::getMemberClasses(NodeMap& out) Node *InnerNode::findChildNodeByName(const QString& name) { Node *node = childMap.value(name); - if (node && node->subType() != QmlPropertyGroup) + if (node && node->type() != QmlPropertyGroup) return node; if ((type() == Document) && (subType() == QmlClass)) { for (int i=0; i<children_.size(); ++i) { Node* n = children_.at(i); - if (n->subType() == QmlPropertyGroup) { + if (n->type() == QmlPropertyGroup) { node = static_cast<InnerNode*>(n)->findChildNodeByName(name); if (node) return node; @@ -771,7 +771,7 @@ void InnerNode::findNodes(const QString& name, QList<Node*>& n) if ((type() == Document) && (subType() == QmlClass)) { for (int i=0; i<children_.size(); ++i) { node = children_.at(i); - if (node->subType() == QmlPropertyGroup) { + if (node->type() == QmlPropertyGroup) { node = static_cast<InnerNode*>(node)->findChildNodeByName(name); if (node) { n.append(node); @@ -793,7 +793,7 @@ void InnerNode::findNodes(const QString& name, QList<Node*>& n) */ for (int i=0; i<nodes.size(); ++i) { node = nodes.at(i); - if (node->subType() != QmlPropertyGroup) + if (node->type() != QmlPropertyGroup) n.append(node); else { node = static_cast<InnerNode*>(node)->findChildNodeByName(name); @@ -829,14 +829,14 @@ Node* InnerNode::findChildNodeByName(const QString& name, bool qml) if (!node->isQmlNode()) return node; } - else if (node->isQmlNode() && (node->subType() != QmlPropertyGroup)) + else if (node->isQmlNode() && (node->type() != QmlPropertyGroup)) return node; } } if (qml && (type() == Document) && (subType() == QmlClass)) { for (int i=0; i<children_.size(); ++i) { Node* node = children_.at(i); - if (node->subType() == QmlPropertyGroup) { + if (node->type() == QmlPropertyGroup) { node = static_cast<InnerNode*>(node)->findChildNodeByName(name); if (node) return node; @@ -1371,6 +1371,26 @@ void InnerNode::removeRelated(Node *pseudoChild) } /*! + If this node has a child that is a QML property named \a n, + return the pointer to that child. + */ +QmlPropertyNode* InnerNode::hasQmlProperty(const QString& n) const +{ + foreach (Node* child, childNodes()) { + if (child->type() == Node::QmlProperty) { + if (child->name() == n) + return static_cast<QmlPropertyNode*>(child); + } + else if (child->type() == Node::QmlPropertyGroup) { + QmlPropertyNode* t = child->hasQmlProperty(n); + if (t) + return t; + } + } + return 0; +} + +/*! \class LeafNode */ @@ -1673,25 +1693,6 @@ QString DocNode::subTitle() const } /*! - Returns true if this QML type or property group contains a - property named \a name. - */ -bool DocNode::hasProperty(const QString& name) const -{ - foreach (Node* child, childNodes()) { - if (child->type() == Node::Document && child->subType() == Node::QmlPropertyGroup) { - if (child->hasProperty(name)) - return true; - } - else if (child->type() == Node::QmlProperty) { - if (child->hasProperty(name)) - return true; - } - } - return false; -} - -/*! The constructor calls the DocNode constructor with \a parent, \a name, and Node::Example. */ @@ -2273,8 +2274,8 @@ QmlBasicTypeNode::QmlBasicTypeNode(InnerNode *parent, Constructor for the Qml property group node. \a parent is always a QmlClassNode. */ -QmlPropGroupNode::QmlPropGroupNode(QmlClassNode* parent, const QString& name) - : DocNode(parent, name, QmlPropertyGroup, Node::ApiPage) +QmlPropertyGroupNode::QmlPropertyGroupNode(QmlClassNode* parent, const QString& name) + : InnerNode(QmlPropertyGroup, parent, name) { idNumber_ = -1; } @@ -2286,24 +2287,17 @@ QmlPropGroupNode::QmlPropGroupNode(QmlClassNode* parent, const QString& name) property group count and set the id number to the new value. */ -QString QmlPropGroupNode::idNumber() +QString QmlPropertyGroupNode::idNumber() { if (idNumber_ == -1) idNumber_ = incPropertyGroupCount(); return QString().setNum(idNumber_); } - /*! - Constructor for the QML property node, when the \a parent - is QML property group node. This constructor is only used - for creating QML property nodes for QML elements, i.e. - not for creating QML property nodes for QML components. - Hopefully, this constructor will become obsolete, so don't - use it unless one of the other two constructors can't be - used. + Constructor for the QML property node. */ -QmlPropertyNode::QmlPropertyNode(QmlPropGroupNode *parent, +QmlPropertyNode::QmlPropertyNode(InnerNode* parent, const QString& name, const QString& type, bool attached) @@ -2311,56 +2305,14 @@ QmlPropertyNode::QmlPropertyNode(QmlPropGroupNode *parent, type_(type), stored_(FlagValueDefault), designable_(FlagValueDefault), + isAlias_(false), isdefault_(false), attached_(attached), readOnly_(FlagValueDefault) { setPageType(ApiPage); -} - -/*! - Constructor for the QML property node, when the \a parent - is a QML class node. - */ -QmlPropertyNode::QmlPropertyNode(QmlClassNode *parent, - const QString& name, - const QString& type, - bool attached) - : LeafNode(QmlProperty, parent, name), - type_(type), - stored_(FlagValueDefault), - designable_(FlagValueDefault), - isdefault_(false), - attached_(attached), - readOnly_(FlagValueDefault) -{ - setPageType(ApiPage); -} - -/*! - Constructor for the QML property node, when the \a parent - is a QML property node. Strictly speaking, this is not the - way QML property nodes were originally meant to be built, - because this constructor has another QML property node as - its parent. But this constructor is useful for documenting - QML properties in QML components, i.e., when you override - the definition of a property with the \e{qmlproperty} - command. It actually uses the parent of \a parent as the - parent. - */ -QmlPropertyNode::QmlPropertyNode(QmlPropertyNode* parent, - const QString& name, - const QString& type, - bool attached) - : LeafNode(parent->parent(), QmlProperty, name), - type_(type), - stored_(FlagValueDefault), - designable_(FlagValueDefault), - isdefault_(false), - attached_(attached), - readOnly_(FlagValueDefault) -{ - setPageType(ApiPage); + if (type_ == QString("alias")) + isAlias_ = true; } /*! @@ -2450,23 +2402,6 @@ PropertyNode* QmlPropertyNode::correspondingProperty(QDocDatabase* qdb) return 0; } -/*! - Returns true if this QML type or property group contains a - property named \a name. - */ -bool QmlPropertyNode::hasProperty(const QString& n) const -{ - if (name() == n) - return true; - foreach (Node* child, qmlPropNodes()) { - if (child->type() == Node::QmlProperty) { - if (child->name() == n) - return true; - } - } - return false; -} - /*! \class NameCollisionNode An instance of this node is inserted in the tree @@ -2586,11 +2521,10 @@ QString Node::fullDocumentName() const const Node* n = this; do { - if (!n->name().isEmpty() && - ((n->type() != Node::Document) || (n->subType() != Node::QmlPropertyGroup))) + if (!n->name().isEmpty() && n->type() != Node::QmlPropertyGroup) pieces.insert(0, n->name()); - if ((n->type() == Node::Document) && (n->subType() != Node::QmlPropertyGroup)) { + if (n->type() == Node::Document) { if ((n->subType() == Node::QmlClass) && !n->qmlModuleName().isEmpty()) pieces.insert(0, n->qmlModuleIdentifier()); break; @@ -2806,12 +2740,6 @@ QString Node::idForNode() const case Node::QmlClass: str = "qml-class-" + name(); break; - case Node::QmlPropertyGroup: - { - Node* n = const_cast<Node*>(this); - str = "qml-propertygroup-" + n->name(); - } - break; case Node::Page: case Node::Group: case Node::Module: @@ -2852,6 +2780,12 @@ QString Node::idForNode() const case Node::QmlProperty: str = "qml-property-" + name(); break; + case Node::QmlPropertyGroup: + { + Node* n = const_cast<Node*>(this); + str = "qml-propertygroup-" + n->name(); + } + break; case Node::Property: str = "property-" + name(); break; diff --git a/src/tools/qdoc/node.h b/src/tools/qdoc/node.h index bc75df2992..9c8950d185 100644 --- a/src/tools/qdoc/node.h +++ b/src/tools/qdoc/node.h @@ -60,6 +60,7 @@ class InnerNode; class ExampleNode; class QmlClassNode; class QDocDatabase; +class QmlPropertyNode; typedef QList<Node*> NodeList; typedef QMap<QString, Node*> NodeMap; @@ -80,6 +81,7 @@ public: Function, Property, Variable, + QmlPropertyGroup, QmlProperty, QmlSignal, QmlSignalHandler, @@ -98,7 +100,6 @@ public: Page, ExternalPage, QmlClass, - QmlPropertyGroup, QmlBasicType, QmlModule, DitaMap, @@ -163,7 +164,10 @@ public: QString plainName() const; QString plainFullName(const Node* relative = 0) const; QString fullName(const Node* relative=0) const; + const QString& baseName() const { return baseName_; } + bool hasBaseName() const { return !baseName_.isEmpty(); } + void setBaseName(const QString& bn) { baseName_ = bn; } void setAccess(Access access) { access_ = access; } void setLocation(const Location& location) { loc = location; } void setDoc(const Doc& doc, bool replace = false); @@ -200,8 +204,11 @@ public: virtual bool isQmlPropertyGroup() const { return false; } virtual bool isCollisionNode() const { return false; } virtual bool isAttached() const { return false; } + virtual bool isAlias() const { return false; } virtual bool isGroup() const { return false; } virtual bool isWrapper() const; + virtual bool isReadOnly() const { return false; } + virtual bool isDefault() const { return false; } virtual void addMember(Node* ) { } virtual bool hasMembers() const { return false; } virtual bool hasNamespaces() const { return false; } @@ -209,10 +216,12 @@ public: virtual void setAbstract(bool ) { } virtual void setWrapper() { } virtual QString title() const { return QString(); } - virtual bool hasProperty(const QString& ) const { return false; } + virtual QmlPropertyNode* hasQmlProperty(const QString& ) const { return 0; } virtual void getMemberNamespaces(NodeMap& ) { } virtual void getMemberClasses(NodeMap& ) { } virtual bool isInternal() const; + virtual void setDataType(const QString& ) { } + virtual void setReadOnly(bool ) { } bool isIndexNode() const { return indexNodeFlag_; } bool wasSeen() const { return seen_; } Type type() const { return nodeType_; } @@ -231,7 +240,7 @@ public: Access access() const { return access_; } QString accessString() const; const Location& location() const { return loc; } - const Doc& doc() const { return d; } + const Doc& doc() const { return doc_; } Status status() const { return status_; } Status inheritedStatus() const; ThreadSafeness threadSafeness() const; @@ -294,8 +303,9 @@ private: InnerNode* relatesTo_; QString name_; Location loc; - Doc d; + Doc doc_; QMap<LinkType, QPair<QString, QString> > linkMap_; + QString baseName_; QString moduleName_; QString url_; QString since_; @@ -366,6 +376,7 @@ public: virtual void setCurrentChild(InnerNode* ) { } virtual void setOutputFileName(const QString& f) { outputFileName_ = f; } virtual QString outputFileName() const { return outputFileName_; } + virtual QmlPropertyNode* hasQmlProperty(const QString& ) const; void printChildren(const QString& title); void printMembers(const QString& title); @@ -444,7 +455,7 @@ public: virtual bool isClass() const { return true; } virtual bool isWrapper() const { return wrapper_; } virtual QString obsoleteLink() const { return obsoleteLink_; } - virtual void setObsoleteLink(const QString& t) { obsoleteLink_ = t; }; + virtual void setObsoleteLink(const QString& t) { obsoleteLink_ = t; } virtual void setWrapper() { wrapper_ = true; } void addBaseClass(Access access, @@ -486,9 +497,11 @@ public: PageType ptype); virtual ~DocNode() { } + void setQtVariable(const QString &variable) { qtVariable_ = variable; } void setTitle(const QString &title) { title_ = title; } void setSubTitle(const QString &subTitle) { subtitle_ = subTitle; } + QString qtVariable() const { return qtVariable_; } SubType subType() const { return nodeSubtype_; } virtual QString title() const; virtual QString fullTitle() const; @@ -497,13 +510,14 @@ public: virtual QString nameForLists() const { return title(); } virtual void setImageFileName(const QString& ) { } virtual bool isGroup() const { return (subType() == Node::Group); } - virtual bool isQmlPropertyGroup() const { return (nodeSubtype_ == QmlPropertyGroup); } - virtual bool hasProperty(const QString& ) const; protected: SubType nodeSubtype_; QString title_; QString subtitle_; + +private: + QString qtVariable_; }; class NameCollisionNode : public DocNode @@ -619,11 +633,11 @@ public: virtual bool isQmlNode() const { return true; } }; -class QmlPropGroupNode : public DocNode +class QmlPropertyGroupNode : public InnerNode { public: - QmlPropGroupNode(QmlClassNode* parent, const QString& name); - virtual ~QmlPropGroupNode() { } + QmlPropertyGroupNode(QmlClassNode* parent, const QString& name); + virtual ~QmlPropertyGroupNode() { } virtual bool isQmlNode() const { return true; } virtual bool isQtQuickNode() const { return parent()->isQtQuickNode(); } virtual QString qmlTypeName() const { return parent()->qmlTypeName(); } @@ -631,6 +645,7 @@ public: virtual QString qmlModuleVersion() const { return parent()->qmlModuleVersion(); } virtual QString qmlModuleIdentifier() const { return parent()->qmlModuleIdentifier(); } virtual QString idNumber(); + virtual bool isQmlPropertyGroup() const { return true; } const QString& element() const { return parent()->name(); } @@ -645,34 +660,27 @@ class QmlPropertyNode : public LeafNode Q_DECLARE_TR_FUNCTIONS(QDoc::QmlPropertyNode) public: - QmlPropertyNode(QmlClassNode *parent, - const QString& name, - const QString& type, - bool attached); - QmlPropertyNode(QmlPropGroupNode* parent, - const QString& name, - const QString& type, - bool attached); - QmlPropertyNode(QmlPropertyNode* parent, + QmlPropertyNode(InnerNode *parent, const QString& name, const QString& type, bool attached); virtual ~QmlPropertyNode() { } - void setDataType(const QString& dataType) { type_ = dataType; } + virtual void setDataType(const QString& dataType) { type_ = dataType; } void setStored(bool stored) { stored_ = toFlagValue(stored); } void setDesignable(bool designable) { designable_ = toFlagValue(designable); } - void setReadOnly(bool ro) { readOnly_ = toFlagValue(ro); } + virtual void setReadOnly(bool ro) { readOnly_ = toFlagValue(ro); } void setDefault() { isdefault_ = true; } const QString &dataType() const { return type_; } QString qualifiedDataType() const { return type_; } bool isReadOnlySet() const { return (readOnly_ != FlagValueDefault); } - bool isDefault() const { return isdefault_; } bool isStored() const { return fromFlagValue(stored_,true); } bool isDesignable() const { return fromFlagValue(designable_,false); } bool isWritable(QDocDatabase* qdb); - bool isReadOnly() const { return fromFlagValue(readOnly_,false); } + virtual bool isDefault() const { return isdefault_; } + virtual bool isReadOnly() const { return fromFlagValue(readOnly_,false); } + virtual bool isAlias() const { return isAlias_; } virtual bool isAttached() const { return attached_; } virtual bool isQmlNode() const { return true; } virtual bool isQtQuickNode() const { return parent()->isQtQuickNode(); } @@ -680,22 +688,19 @@ public: virtual QString qmlModuleName() const { return parent()->qmlModuleName(); } virtual QString qmlModuleVersion() const { return parent()->qmlModuleVersion(); } virtual QString qmlModuleIdentifier() const { return parent()->qmlModuleIdentifier(); } - virtual bool hasProperty(const QString& name) const; PropertyNode* correspondingProperty(QDocDatabase* qdb); - const QString& element() const { return static_cast<QmlPropGroupNode*>(parent())->element(); } - void appendQmlPropNode(QmlPropertyNode* p) { qmlPropNodes_.append(p); } - const NodeList& qmlPropNodes() const { return qmlPropNodes_; } + const QString& element() const { return static_cast<QmlPropertyGroupNode*>(parent())->element(); } private: QString type_; FlagValue stored_; FlagValue designable_; + bool isAlias_; bool isdefault_; bool attached_; FlagValue readOnly_; - NodeList qmlPropNodes_; }; class EnumItem @@ -892,7 +897,7 @@ public: PropertyNode(InnerNode* parent, const QString& name); virtual ~PropertyNode() { } - void setDataType(const QString& dataType) { type_ = dataType; } + virtual void setDataType(const QString& dataType) { type_ = dataType; } void addFunction(FunctionNode* function, FunctionRole role); void addSignal(FunctionNode* function, FunctionRole role); void setStored(bool stored) { stored_ = toFlagValue(stored); } diff --git a/src/tools/qdoc/puredocparser.cpp b/src/tools/qdoc/puredocparser.cpp index d11ef3a3c7..644fe05438 100644 --- a/src/tools/qdoc/puredocparser.cpp +++ b/src/tools/qdoc/puredocparser.cpp @@ -118,9 +118,9 @@ void PureDocParser::parseSourceFile(const Location& location, const QString& fil */ bool PureDocParser::processQdocComments() { - QSet<QString> topicCommandsAllowed = topicCommands(); - QSet<QString> otherMetacommandsAllowed = otherMetaCommands(); - QSet<QString> metacommandsAllowed = topicCommandsAllowed + otherMetacommandsAllowed; + const QSet<QString>& topicCommandsAllowed = topicCommands(); + const QSet<QString>& otherMetacommandsAllowed = otherMetaCommands(); + const QSet<QString>& metacommandsAllowed = topicCommandsAllowed + otherMetacommandsAllowed; while (tok != Tok_Eoi) { if (tok == Tok_Doc) { @@ -137,55 +137,68 @@ bool PureDocParser::processQdocComments() /* Doc parses the comment. */ - Doc doc(start_loc,end_loc,comment,metacommandsAllowed); + Doc doc(start_loc, end_loc, comment, metacommandsAllowed, topicCommandsAllowed); QString topic; - ArgList args; + bool isQmlPropertyTopic = false; - QSet<QString> topicCommandsUsed = topicCommandsAllowed & doc.metaCommandsUsed(); - - /* - There should be one topic command in the set, - or none. If the set is empty, then the comment - should be a function description. - */ - if (topicCommandsUsed.count() > 0) { - topic = *topicCommandsUsed.begin(); - args = doc.metaCommandArgs(topic); + const TopicList& topics = doc.topicsUsed(); + if (!topics.isEmpty()) { + topic = topics[0].topic; + if ((topic == COMMAND_QMLPROPERTY) || + (topic == COMMAND_QMLPROPERTYGROUP) || + (topic == COMMAND_QMLATTACHEDPROPERTY)) { + isQmlPropertyTopic = true; + } + } + if (isQmlPropertyTopic && topics.size() > 1) { + qDebug() << "MULTIPLE TOPICS:" << doc.location().fileName() << doc.location().lineNo(); + for (int i=0; i<topics.size(); ++i) { + qDebug() << " " << topics[i].topic << topics[i].args; + } } NodeList nodes; - QList<Doc> docs; + DocList docs; if (topic.isEmpty()) { doc.location().warning(tr("This qdoc comment contains no topic command " "(e.g., '\\%1', '\\%2').") .arg(COMMAND_MODULE).arg(COMMAND_PAGE)); } + else if (isQmlPropertyTopic) { + Doc nodeDoc = doc; + processQmlProperties(nodeDoc, nodes, docs); + } else { - /* - There is a topic command. Process it. - */ - if ((topic == COMMAND_QMLPROPERTY) || - (topic == COMMAND_QMLATTACHEDPROPERTY)) { + ArgList args; + QSet<QString> topicCommandsUsed = topicCommandsAllowed & doc.metaCommandsUsed(); + if (topicCommandsUsed.count() > 0) { + topic = *topicCommandsUsed.begin(); + args = doc.metaCommandArgs(topic); + } + if (topicCommandsUsed.count() > 1) { + QString topics; + QSet<QString>::ConstIterator t = topicCommandsUsed.constBegin(); + while (t != topicCommandsUsed.constEnd()) { + topics += " \\" + *t + ","; + ++t; + } + topics[topics.lastIndexOf(',')] = '.'; + int i = topics.lastIndexOf(','); + topics[i] = ' '; + topics.insert(i+1,"and"); + doc.location().warning(tr("Multiple topic commands found in comment: %1").arg(topics)); + } + ArgList::ConstIterator a = args.begin(); + while (a != args.end()) { Doc nodeDoc = doc; - Node* node = processTopicCommandGroup(nodeDoc,topic,args); + Node* node = processTopicCommand(nodeDoc,topic,*a); if (node != 0) { nodes.append(node); docs.append(nodeDoc); } - } - else { - ArgList::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; - } + ++a; } } diff --git a/src/tools/qdoc/qdocdatabase.cpp b/src/tools/qdoc/qdocdatabase.cpp index 7a3df4e4f2..a1e06c8020 100644 --- a/src/tools/qdoc/qdocdatabase.cpp +++ b/src/tools/qdoc/qdocdatabase.cpp @@ -612,7 +612,7 @@ void QDocDatabase::findAllObsoleteThings(const InnerNode* node) case Node::QmlMethod: if ((*c)->parent()) { Node* parent = (*c)->parent(); - if (parent->subType() == Node::QmlPropertyGroup && parent->parent()) + if (parent->type() == Node::QmlPropertyGroup && parent->parent()) parent = parent->parent(); if (parent && parent->subType() == Node::QmlClass && !parent->name().isEmpty()) name = parent->name() + "::" + name; diff --git a/src/tools/qdoc/qdocindexfiles.cpp b/src/tools/qdoc/qdocindexfiles.cpp index 5f2ebdfd07..aab5e4f9ae 100644 --- a/src/tools/qdoc/qdocindexfiles.cpp +++ b/src/tools/qdoc/qdocindexfiles.cpp @@ -217,8 +217,18 @@ void QDocIndexFiles::readIndexSection(const QDomElement& element, location = Location(name); node = qbtn; } - else if (element.nodeName() == "qmlproperty") { + else if (element.nodeName() == "qmlpropertygroup") { QmlClassNode* qcn = static_cast<QmlClassNode*>(parent); + QmlPropertyGroupNode* qpgn = new QmlPropertyGroupNode(qcn, name); + if (element.hasAttribute("location")) + name = element.attribute("location", QString()); + if (!indexUrl.isEmpty()) + location = Location(indexUrl + QLatin1Char('/') + name); + else if (!indexUrl.isNull()) + location = Location(name); + node = qpgn; + } + else if (element.nodeName() == "qmlproperty") { QString type = element.attribute("type"); bool attached = false; if (element.attribute("attached") == "true") @@ -226,7 +236,15 @@ void QDocIndexFiles::readIndexSection(const QDomElement& element, bool readonly = false; if (element.attribute("writable") == "false") readonly = true; - QmlPropertyNode* qpn = new QmlPropertyNode(qcn, name, type, attached); + QmlPropertyNode* qpn = 0; + if (parent->type() == Node::Document) { + QmlClassNode* qcn = static_cast<QmlClassNode*>(parent); + qpn = new QmlPropertyNode(qcn, name, type, attached); + } + else if (parent->type() == Node::QmlPropertyGroup) { + QmlPropertyGroupNode* qpgn = static_cast<QmlPropertyGroupNode*>(parent); + qpn = new QmlPropertyNode(qpgn, name, type, attached); + } qpn->setReadOnly(readonly); node = qpn; } @@ -281,10 +299,6 @@ void QDocIndexFiles::readIndexSection(const QDomElement& element, subtype = Node::QmlClass; ptype = Node::ApiPage; } - else if (element.attribute("subtype") == "qmlpropertygroup") { - subtype = Node::QmlPropertyGroup; - ptype = Node::ApiPage; - } else if (element.attribute("subtype") == "qmlbasictype") { subtype = Node::QmlBasicType; ptype = Node::ApiPage; @@ -501,7 +515,7 @@ void QDocIndexFiles::readIndexSection(const QDomElement& element, // Create some content for the node. QSet<QString> emptySet; - Doc doc(location, location, " ", emptySet); // placeholder + Doc doc(location, location, " ", emptySet, emptySet); // placeholder node->setDoc(doc); node->setIndexNodeFlag(); node->setOutputSubdirectory(project_.toLower()); @@ -644,6 +658,9 @@ bool QDocIndexFiles::generateIndexSection(QXmlStreamWriter& writer, case Node::QmlProperty: nodeName = "qmlproperty"; break; + case Node::QmlPropertyGroup: + nodeName = "qmlpropertygroup"; + break; case Node::QmlSignal: nodeName = "qmlsignal"; break; @@ -746,7 +763,9 @@ bool QDocIndexFiles::generateIndexSection(QXmlStreamWriter& writer, QString fullName = node->fullDocumentName(); if (fullName != objName) writer.writeAttribute("fullname", fullName); - QString href = node->outputSubdirectory(); + QString href; + if (Generator::useOutputSubdirs()) + href = node->outputSubdirectory(); if (!href.isEmpty()) href.append(QLatin1Char('/')); href.append(gen_->fullDocumentLocation(node)); @@ -927,6 +946,12 @@ bool QDocIndexFiles::generateIndexSection(QXmlStreamWriter& writer, writer.writeAttribute("brief", brief); } break; + case Node::QmlPropertyGroup: + { + if (!brief.isEmpty()) + writer.writeAttribute("brief", brief); + } + break; case Node::Property: { const PropertyNode* propertyNode = static_cast<const PropertyNode*>(node); @@ -1179,17 +1204,12 @@ void QDocIndexFiles::generateIndexSections(QXmlStreamWriter& writer, foreach (Node* child, cnodes) { /* - Don't generate anything for a QML property group node. - It is just a place holder for a collection of QML property - nodes. Recurse to its children, which are the QML property - nodes. - - Do the same thing for collision nodes - we want children - of collision nodes in the index, but leaving out the - parent collision page will make searching for nodes easier. + Don't generate anything for a collision node. We want + children of collision nodes in the index, but leaving + out the parent collision page will make searching for + nodes easier. */ - if (child->subType() == Node::QmlPropertyGroup || - child->subType() == Node::Collision) { + if (child->subType() == Node::Collision) { const InnerNode* pgn = static_cast<const InnerNode*>(child); foreach (Node* c, pgn->childNodes()) { generateIndexSections(writer, c, generateInternalNodes); diff --git a/src/tools/qdoc/qdoctagfiles.cpp b/src/tools/qdoc/qdoctagfiles.cpp index 1f6020fc09..a0054ea229 100644 --- a/src/tools/qdoc/qdoctagfiles.cpp +++ b/src/tools/qdoc/qdoctagfiles.cpp @@ -156,7 +156,7 @@ void QDocTagFiles::generateTagFileCompounds(QXmlStreamWriter& writer, const Inne if (node->type() == Node::Class) { writer.writeTextElement("name", node->fullDocumentName()); - writer.writeTextElement("filename", gen_->fullDocumentLocation(node,true)); + writer.writeTextElement("filename", gen_->fullDocumentLocation(node,Generator::useOutputSubdirs())); // Classes contain information about their base classes. const ClassNode* classNode = static_cast<const ClassNode*>(node); @@ -175,7 +175,7 @@ void QDocTagFiles::generateTagFileCompounds(QXmlStreamWriter& writer, const Inne } else { writer.writeTextElement("name", node->fullDocumentName()); - writer.writeTextElement("filename", gen_->fullDocumentLocation(node,true)); + writer.writeTextElement("filename", gen_->fullDocumentLocation(node,Generator::useOutputSubdirs())); // Recurse to write all members. generateTagFileMembers(writer, static_cast<const InnerNode*>(node)); @@ -291,7 +291,7 @@ void QDocTagFiles::generateTagFileMembers(QXmlStreamWriter& writer, const InnerN writer.writeTextElement("type", "virtual " + functionNode->returnType()); writer.writeTextElement("name", objName); - QStringList pieces = gen_->fullDocumentLocation(node,true).split(QLatin1Char('#')); + QStringList pieces = gen_->fullDocumentLocation(node,Generator::useOutputSubdirs()).split(QLatin1Char('#')); writer.writeTextElement("anchorfile", pieces[0]); writer.writeTextElement("anchor", pieces[1]); @@ -332,7 +332,7 @@ void QDocTagFiles::generateTagFileMembers(QXmlStreamWriter& writer, const InnerN const PropertyNode* propertyNode = static_cast<const PropertyNode*>(node); writer.writeAttribute("type", propertyNode->dataType()); writer.writeTextElement("name", objName); - QStringList pieces = gen_->fullDocumentLocation(node,true).split(QLatin1Char('#')); + QStringList pieces = gen_->fullDocumentLocation(node,Generator::useOutputSubdirs()).split(QLatin1Char('#')); writer.writeTextElement("anchorfile", pieces[0]); writer.writeTextElement("anchor", pieces[1]); writer.writeTextElement("arglist", QString()); @@ -366,7 +366,7 @@ void QDocTagFiles::generateTagFileMembers(QXmlStreamWriter& writer, const InnerN else writer.writeAttribute("type", QString()); writer.writeTextElement("name", objName); - QStringList pieces = gen_->fullDocumentLocation(node,true).split(QLatin1Char('#')); + QStringList pieces = gen_->fullDocumentLocation(node,Generator::useOutputSubdirs()).split(QLatin1Char('#')); writer.writeTextElement("anchorfile", pieces[0]); writer.writeTextElement("anchor", pieces[1]); writer.writeTextElement("arglist", QString()); diff --git a/src/tools/qdoc/qmlcodeparser.cpp b/src/tools/qdoc/qmlcodeparser.cpp index b9c0ad9218..28b9c3ec9b 100644 --- a/src/tools/qdoc/qmlcodeparser.cpp +++ b/src/tools/qdoc/qmlcodeparser.cpp @@ -70,6 +70,7 @@ QT_BEGIN_NAMESPACE #define COMMAND_QMLTYPE Doc::alias("qmltype") #define COMMAND_QMLMODULE Doc::alias("qmlmodule") #define COMMAND_QMLPROPERTY Doc::alias("qmlproperty") +#define COMMAND_QMLPROPERTYGROUP Doc::alias("qmlpropertygroup") #define COMMAND_QMLATTACHEDPROPERTY Doc::alias("qmlattachedproperty") #define COMMAND_QMLINHERITS Doc::alias("inherits") #define COMMAND_QMLINSTANTIATES Doc::alias("instantiates") @@ -166,9 +167,9 @@ void QmlCodeParser::parseSourceFile(const Location& location, const QString& fil extractPragmas(newCode); lexer->setCode(newCode, 1); - QSet<QString> topicCommandsAllowed = topicCommands(); - QSet<QString> otherMetacommandsAllowed = otherMetaCommands(); - QSet<QString> metacommandsAllowed = topicCommandsAllowed + otherMetacommandsAllowed; + const QSet<QString>& topicCommandsAllowed = topicCommands(); + const QSet<QString>& otherMetacommandsAllowed = otherMetaCommands(); + const QSet<QString>& metacommandsAllowed = topicCommandsAllowed + otherMetacommandsAllowed; if (parser->parse()) { QQmlJS::AST::UiProgram *ast = parser->ast(); @@ -195,42 +196,52 @@ void QmlCodeParser::doneParsingSourceFiles() { } +static QSet<QString> topicCommands_; /*! Returns the set of strings representing the topic commands. */ -QSet<QString> QmlCodeParser::topicCommands() +const QSet<QString>& QmlCodeParser::topicCommands() { - return QSet<QString>() << COMMAND_VARIABLE - << COMMAND_QMLCLASS - << COMMAND_QMLTYPE - << COMMAND_QMLPROPERTY - << COMMAND_QMLATTACHEDPROPERTY - << COMMAND_QMLSIGNAL - << COMMAND_QMLATTACHEDSIGNAL - << COMMAND_QMLMETHOD - << COMMAND_QMLATTACHEDMETHOD - << COMMAND_QMLBASICTYPE; + if (topicCommands_.isEmpty()) { + topicCommands_ << COMMAND_VARIABLE + << COMMAND_QMLCLASS + << COMMAND_QMLTYPE + << COMMAND_QMLPROPERTY + << COMMAND_QMLPROPERTYGROUP + << COMMAND_QMLATTACHEDPROPERTY + << COMMAND_QMLSIGNAL + << COMMAND_QMLATTACHEDSIGNAL + << COMMAND_QMLMETHOD + << COMMAND_QMLATTACHEDMETHOD + << COMMAND_QMLBASICTYPE; + } + return topicCommands_; } +static QSet<QString> otherMetaCommands_; /*! Returns the set of strings representing the common metacommands plus some other metacommands. */ -QSet<QString> QmlCodeParser::otherMetaCommands() +const QSet<QString>& QmlCodeParser::otherMetaCommands() { - return commonMetaCommands() << COMMAND_STARTPAGE - << COMMAND_QMLINHERITS - << COMMAND_QMLDEFAULT - << COMMAND_QMLREADONLY - << COMMAND_DEPRECATED - << COMMAND_INGROUP - << COMMAND_INTERNAL - << COMMAND_OBSOLETE - << COMMAND_PRELIMINARY - << COMMAND_SINCE - << COMMAND_QMLABSTRACT - << COMMAND_INQMLMODULE - << COMMAND_WRAPPER; + if (otherMetaCommands_.isEmpty()) { + otherMetaCommands_ = commonMetaCommands(); + otherMetaCommands_ << COMMAND_STARTPAGE + << COMMAND_QMLINHERITS + << COMMAND_QMLDEFAULT + << COMMAND_QMLREADONLY + << COMMAND_DEPRECATED + << COMMAND_INGROUP + << COMMAND_INTERNAL + << COMMAND_OBSOLETE + << COMMAND_PRELIMINARY + << COMMAND_SINCE + << COMMAND_QMLABSTRACT + << COMMAND_INQMLMODULE + << COMMAND_WRAPPER; + } + return otherMetaCommands_; } /*! diff --git a/src/tools/qdoc/qmlcodeparser.h b/src/tools/qdoc/qmlcodeparser.h index 5bdcfbfbbf..71b4660fe7 100644 --- a/src/tools/qdoc/qmlcodeparser.h +++ b/src/tools/qdoc/qmlcodeparser.h @@ -79,8 +79,8 @@ public: void extractPragmas(QString &script); protected: - virtual QSet<QString> topicCommands(); - virtual QSet<QString> otherMetaCommands(); + const QSet<QString>& topicCommands(); + const QSet<QString>& otherMetaCommands(); private: QQmlJS::Engine engine; diff --git a/src/tools/qdoc/qmlvisitor.cpp b/src/tools/qdoc/qmlvisitor.cpp index 86b86c8f34..c049857717 100644 --- a/src/tools/qdoc/qmlvisitor.cpp +++ b/src/tools/qdoc/qmlvisitor.cpp @@ -67,6 +67,7 @@ QT_BEGIN_NAMESPACE #define COMMAND_QMLTYPE Doc::alias(QLatin1String("qmltype")) #define COMMAND_QMLMODULE Doc::alias(QLatin1String("qmlmodule")) #define COMMAND_QMLPROPERTY Doc::alias(QLatin1String("qmlproperty")) +#define COMMAND_QMLPROPERTYGROUP Doc::alias(QLatin1String("qmlpropertygroup")) #define COMMAND_QMLATTACHEDPROPERTY Doc::alias(QLatin1String("qmlattachedproperty")) #define COMMAND_QMLINHERITS Doc::alias(QLatin1String("inherits")) #define COMMAND_QMLINSTANTIATES Doc::alias(QLatin1String("instantiates")) @@ -85,17 +86,17 @@ QT_BEGIN_NAMESPACE QmlDocVisitor::QmlDocVisitor(const QString &filePath, const QString &code, QQmlJS::Engine *engine, - QSet<QString> &commands, - QSet<QString> &topics) + const QSet<QString> &commands, + const QSet<QString> &topics) : nestingLevel(0) { lastEndOffset = 0; - this->filePath = filePath; + this->filePath_ = filePath; this->name = QFileInfo(filePath).baseName(); document = code; this->engine = engine; - this->commands = commands; - this->topics = topics; + this->commands_ = commands; + this->topics_ = topics; current = QDocDatabase::qdocDB()->treeRoot(); } @@ -141,13 +142,89 @@ QQmlJS::AST::SourceLocation QmlDocVisitor::precedingComment(quint32 offset) cons return QQmlJS::AST::SourceLocation(); } +#if 0 + ArgList args; + QSet<QString>::iterator i = metacommands.begin(); + while (i != metacommands.end()) { + if (topics_.contains(*i)) { + topic = *i; + break; + } + ++i; + } + if (!topic.isEmpty()) { + args = doc.metaCommandArgs(topic); + if ((topic == COMMAND_QMLCLASS) || (topic == COMMAND_QMLTYPE)) { + // do nothing. + } + else if (topic == COMMAND_QMLPROPERTY) { + if (node->type() == Node::QmlProperty) { + QmlPropertyNode* qpn = static_cast<QmlPropertyNode*>(node); + qpn->setReadOnly(0); + if (qpn->dataType() == "alias") { + QStringList part = args[0].first.split(QLatin1Char(' ')); + qpn->setDataType(part[0]); + } + } + } + else if (topic == COMMAND_QMLPROPERTYGROUP) { + // zzz ? + } + else if (topic == COMMAND_QMLMODULE) { + } + else if (topic == COMMAND_QMLATTACHEDPROPERTY) { + if (node->type() == Node::QmlProperty) { + QmlPropertyNode* qpn = static_cast<QmlPropertyNode*>(node); + qpn->setReadOnly(0); + } + } + else if (topic == COMMAND_QMLSIGNAL) { + } + else if (topic == COMMAND_QMLATTACHEDSIGNAL) { + } + else if (topic == COMMAND_QMLMETHOD) { + } + else if (topic == COMMAND_QMLATTACHEDMETHOD) { + } + else if (topic == COMMAND_QMLBASICTYPE) { + } + } + + if (node->type() == Node::QmlProperty) { + QmlPropertyNode* qpn = static_cast<QmlPropertyNode*>(node); + for (int i=0; i<topicsUsed.size(); ++i) { + if (topicsUsed.at(i).topic == "qmlproperty") { + /* + A \qmlproperty command would be used in a QML file + to document the underlying property for a property + alias. + */ + QmlPropArgs qpa; + if (splitQmlPropertyArg(doc, topicsUsed.at(i).args, qpa)) { + QmlPropertyNode* n = parent->hasQmlPropertyNode(qpa.name_); + if (n == 0) + n = new QmlPropertyNode(qpn, qpa.name_, qpa.type_, false); + n->setLocation(doc.location()); + n->setReadOnly(qpn->isReadOnly()); + if (qpn->isDefault()) + n->setDefault(); + } + else + qDebug() << " FAILED TO PARSE QML PROPERTY:" + << topicsUsed.at(i).topic << topicsUsed.at(i).args; + } + } + } + +#endif + /*! Finds the nearest unused qdoc comment above the QML entity represented by the \a node and processes the qdoc commands - in that comment. The proceesed documentation is stored in + in that comment. The processed documentation is stored in the \a node. - If a qdoc comment is found about \a location, true is returned. + If a qdoc comment is found for \a location, true is returned. If a comment is not found there, false is returned. */ bool QmlDocVisitor::applyDocumentation(QQmlJS::AST::SourceLocation location, Node* node) @@ -156,23 +233,66 @@ bool QmlDocVisitor::applyDocumentation(QQmlJS::AST::SourceLocation location, Nod if (loc.isValid()) { QString source = document.mid(loc.offset, loc.length); - Location start(filePath); + Location start(filePath_); start.setLineNo(loc.startLine); start.setColumnNo(loc.startColumn); - Location finish(filePath); + Location finish(filePath_); finish.setLineNo(loc.startLine); finish.setColumnNo(loc.startColumn); - Doc doc(start, finish, source.mid(1), commands, topics); + Doc doc(start, finish, source.mid(1), commands_, topics_); + const TopicList& topicsUsed = doc.topicsUsed(); + NodeList nodes; + Node* nodePassedIn = node; + InnerNode* parent = nodePassedIn->parent(); node->setDoc(doc); - applyMetacommands(loc, node, doc); + nodes.append(node); + if (topicsUsed.size() > 0) { + for (int i=0; i<topicsUsed.size(); ++i) { + if (topicsUsed.at(i).topic == QString("qmlpropertygroup")) { + qDebug() << "PROPERTY GROUP COMMAND SEEN:" << topicsUsed.at(i).args << filePath_; + break; + } + } + for (int i=0; i<topicsUsed.size(); ++i) { + QString topic = topicsUsed.at(i).topic; + QString args = topicsUsed.at(i).args; + if ((topic == COMMAND_QMLPROPERTY) || (topic == COMMAND_QMLATTACHEDPROPERTY)) { + QmlPropArgs qpa; + if (splitQmlPropertyArg(doc, args, qpa)) { + if (qpa.name_ == nodePassedIn->name()) { + if (nodePassedIn->isAlias()) + nodePassedIn->setDataType(qpa.type_); + } + else { + bool isAttached = (topic == COMMAND_QMLATTACHEDPROPERTY); + QmlPropertyNode* n = parent->hasQmlProperty(qpa.name_); + if (n == 0) + n = new QmlPropertyNode(parent, qpa.name_, qpa.type_, isAttached); + n->setLocation(doc.location()); + n->setDoc(doc); + n->setReadOnly(nodePassedIn->isReadOnly()); + if (nodePassedIn->isDefault()) + n->setDefault(); + if (isAttached) + n->setReadOnly(0); + nodes.append(n); + } + } + else + qDebug() << " FAILED TO PARSE QML PROPERTY:" << topic << args; + } + } + } + for (int i=0; i<nodes.size(); ++i) + applyMetacommands(loc, nodes.at(i), doc); usedComments.insert(loc.offset); if (doc.isEmpty()) { return false; } return true; } - Location codeLoc(filePath); + Location codeLoc(filePath_); codeLoc.setLineNo(location.startLine); node->setLocation(codeLoc); return false; @@ -237,80 +357,13 @@ void QmlDocVisitor::applyMetacommands(QQmlJS::AST::SourceLocation, Doc& doc) { QDocDatabase* qdb = QDocDatabase::qdocDB(); - - const TopicList& topicsUsed = doc.topicsUsed(); - if (topicsUsed.size() > 0) { - if (node->type() == Node::QmlProperty) { - QmlPropertyNode* qpn = static_cast<QmlPropertyNode*>(node); - for (int i=0; i<topicsUsed.size(); ++i) { - if (topicsUsed.at(i).topic == "qmlproperty") { - QmlPropArgs qpa; - if (splitQmlPropertyArg(doc, topicsUsed.at(i).args, qpa)) { - QmlPropertyNode* n = new QmlPropertyNode(qpn, qpa.name_, qpa.type_, false); - n->setLocation(doc.location()); - qpn->appendQmlPropNode(n); - n->setReadOnly(qpn->isReadOnly()); - if (qpn->isDefault()) - n->setDefault(); - } - else - qDebug() << " FAILED TO PARSE QML PROPERTY:" - << topicsUsed.at(i).topic << topicsUsed.at(i).args; - } - } - } - } QSet<QString> metacommands = doc.metaCommandsUsed(); if (metacommands.count() > 0) { - QString topic; - ArgList args; + metacommands.subtract(topics_); QSet<QString>::iterator i = metacommands.begin(); while (i != metacommands.end()) { - if (topics.contains(*i)) { - topic = *i; - break; - } - ++i; - } - if (!topic.isEmpty()) { - args = doc.metaCommandArgs(topic); - if ((topic == COMMAND_QMLCLASS) || (topic == COMMAND_QMLTYPE)) { - // do nothing. - } - else if (topic == COMMAND_QMLPROPERTY) { - if (node->type() == Node::QmlProperty) { - QmlPropertyNode* qpn = static_cast<QmlPropertyNode*>(node); - qpn->setReadOnly(0); - if (qpn->dataType() == "alias") { - QStringList part = args[0].first.split(QLatin1Char(' ')); - qpn->setDataType(part[0]); - } - } - } - else if (topic == COMMAND_QMLMODULE) { - } - else if (topic == COMMAND_QMLATTACHEDPROPERTY) { - if (node->type() == Node::QmlProperty) { - QmlPropertyNode* qpn = static_cast<QmlPropertyNode*>(node); - qpn->setReadOnly(0); - } - } - else if (topic == COMMAND_QMLSIGNAL) { - } - else if (topic == COMMAND_QMLATTACHEDSIGNAL) { - } - else if (topic == COMMAND_QMLMETHOD) { - } - else if (topic == COMMAND_QMLATTACHEDMETHOD) { - } - else if (topic == COMMAND_QMLBASICTYPE) { - } - } - metacommands.subtract(topics); - i = metacommands.begin(); - while (i != metacommands.end()) { QString command = *i; - args = doc.metaCommandArgs(command); + ArgList args = doc.metaCommandArgs(command); if (command == COMMAND_QMLABSTRACT) { if ((node->type() == Node::Document) && (node->subType() == Node::QmlClass)) { node->setAbstract(true); @@ -528,7 +581,9 @@ bool QmlDocVisitor::visit(QQmlJS::AST::UiPublicMember *member) QmlClassNode *qmlClass = static_cast<QmlClassNode *>(current); if (qmlClass) { QString name = member->name.toString(); - QmlPropertyNode *qmlPropNode = new QmlPropertyNode(qmlClass, name, type, false); + QmlPropertyNode* qmlPropNode = qmlClass->hasQmlProperty(name); + if (qmlPropNode == 0) + qmlPropNode = new QmlPropertyNode(qmlClass, name, type, false); qmlPropNode->setReadOnly(member->isReadonlyMember); if (member->isDefaultMember) qmlPropNode->setDefault(); diff --git a/src/tools/qdoc/qmlvisitor.h b/src/tools/qdoc/qmlvisitor.h index 2c3ff341d6..cdb7ae7391 100644 --- a/src/tools/qdoc/qmlvisitor.h +++ b/src/tools/qdoc/qmlvisitor.h @@ -45,7 +45,6 @@ #include <qstring.h> #include "qqmljsastvisitor_p.h" #include "node.h" -#include "tree.h" QT_BEGIN_NAMESPACE @@ -72,8 +71,8 @@ public: QmlDocVisitor(const QString &filePath, const QString &code, QQmlJS::Engine *engine, - QSet<QString> &commands, - QSet<QString> &topics); + const QSet<QString> &commands, + const QSet<QString> &topics); virtual ~QmlDocVisitor(); bool visit(QQmlJS::AST::UiImportList *imports); @@ -113,12 +112,12 @@ private: QQmlJS::Engine *engine; quint32 lastEndOffset; quint32 nestingLevel; - QString filePath; + QString filePath_; QString name; QString document; ImportList importList; - QSet<QString> commands; - QSet<QString> topics; + QSet<QString> commands_; + QSet<QString> topics_; QSet<quint32> usedComments; InnerNode *current; }; diff --git a/src/tools/qdoc/tree.cpp b/src/tools/qdoc/tree.cpp index 553c569ae9..8c5ecdcfe9 100644 --- a/src/tools/qdoc/tree.cpp +++ b/src/tools/qdoc/tree.cpp @@ -169,7 +169,7 @@ const Node* Tree::findNode(const QStringList& path, if (node && i == path.size() && (!(findFlags & NonFunction) || node->type() != Node::Function || ((FunctionNode*)node)->metaness() == FunctionNode::MacroWithoutParams)) { - if ((node != self) && (node->subType() != Node::QmlPropertyGroup)) { + if ((node != self) && (node->type() != Node::QmlPropertyGroup)) { if (node->subType() == Node::Collision) { node = node->applyModuleIdentifier(start); } diff --git a/src/tools/uic/main.cpp b/src/tools/uic/main.cpp index f5a1301666..baafb8ec92 100644 --- a/src/tools/uic/main.cpp +++ b/src/tools/uic/main.cpp @@ -106,13 +106,6 @@ int runUic(int argc, char *argv[]) return 1; } driver.option().postfix = QLatin1String(argv[arg]); - } else if (opt == QLatin1String("-3")) { - ++arg; - if (!argv[arg]) { - showHelp(argv[0]); - return 1; - } - driver.option().uic3 = QFile::decodeName(argv[arg]); } else if (opt == QLatin1String("-tr") || opt == QLatin1String("-translate")) { ++arg; if (!argv[arg]) { diff --git a/src/tools/uic/option.h b/src/tools/uic/option.h index 141eb4806a..14ed422d63 100644 --- a/src/tools/uic/option.h +++ b/src/tools/uic/option.h @@ -73,7 +73,6 @@ struct Option QString prefix; QString postfix; QString translateFunction; - QString uic3; #ifdef QT_UIC_JAVA_GENERATOR QString javaPackage; QString javaOutputDirectory; |