From 2eb28f51ce4150fa03b2ddde8c39b502ae57d18a Mon Sep 17 00:00:00 2001 From: Martin Smith Date: Wed, 10 Jul 2013 13:47:47 +0200 Subject: qdoc: Implement better handling of QML property groups The \qmlpropertygroup command is added, and qdoc is taught to generate better output for it. The format is, e.g.: \qmlpropertygroup QtQuick2::Item::anchors \qmlproperty AnchorLine QtQuick2::Item::anchors.top \qmlproperty AnchorLine QtQuick2::Item::anchors.bottom \qmlproperty AnchorLine QtQuick2::Item::anchors.left \qmlproperty AnchorLine QtQuick2::Item::anchors.right \qmlproperty AnchorLine QtQuick2::Item::anchors.horizontalCenter \qmlproperty AnchorLine QtQuick2::Item::anchors.verticalCenter \qmlproperty AnchorLine QtQuick2::Item::anchors.baseline \qmlproperty Item QtQuick2::Item::anchors.fill \qmlproperty Item QtQuick2::Item::anchors.centerIn \qmlproperty real QtQuick2::Item::anchors.margins \qmlproperty real QtQuick2::Item::anchors.topMargin \qmlproperty real QtQuick2::Item::anchors.bottomMargin \qmlproperty real QtQuick2::Item::anchors.leftMargin \qmlproperty real QtQuick2::Item::anchors.rightMargin \qmlproperty real QtQuick2::Item::anchors.horizontalCenterOffset \qmlproperty real QtQuick2::Item::anchors.verticalCenterOffset \qmlproperty real QtQuick2::Item::anchors.baselineOffset \qmlproperty bool QtQuick2::Item::anchors.alignWhenCentered Task-number: QTBUG-32341 Change-Id: I4b06a3a061b23680e663e8d4e82ac9863ffd4ecb Reviewed-by: Jerome Pasion --- src/tools/qdoc/codemarker.cpp | 2 +- src/tools/qdoc/codeparser.cpp | 46 ++--- src/tools/qdoc/codeparser.h | 2 +- src/tools/qdoc/cppcodemarker.cpp | 59 +----- src/tools/qdoc/cppcodeparser.cpp | 335 +++++++++++++++++++++-------------- src/tools/qdoc/cppcodeparser.h | 13 +- src/tools/qdoc/ditaxmlgenerator.cpp | 66 ++----- src/tools/qdoc/doc.cpp | 10 +- src/tools/qdoc/doc.h | 8 +- src/tools/qdoc/generator.cpp | 20 ++- src/tools/qdoc/helpprojectwriter.cpp | 23 +-- src/tools/qdoc/htmlgenerator.cpp | 116 +++++------- src/tools/qdoc/node.cpp | 160 +++++------------ src/tools/qdoc/node.h | 52 +++--- src/tools/qdoc/puredocparser.cpp | 81 +++++---- src/tools/qdoc/qdocdatabase.cpp | 2 +- src/tools/qdoc/qdocindexfiles.cpp | 52 ++++-- src/tools/qdoc/qmlcodeparser.cpp | 67 ++++--- src/tools/qdoc/qmlcodeparser.h | 4 +- src/tools/qdoc/qmlvisitor.cpp | 221 ++++++++++++++--------- src/tools/qdoc/qmlvisitor.h | 10 +- src/tools/qdoc/tree.cpp | 2 +- 22 files changed, 681 insertions(+), 670 deletions(-) (limited to 'src') 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..97a3d20263 100644 --- a/src/tools/qdoc/codeparser.cpp +++ b/src/tools/qdoc/codeparser.cpp @@ -199,29 +199,33 @@ CodeParser *CodeParser::parserForSourceFile(const QString &filePath) return 0; } +static QSet commonMetaCommands_; /*! Returns the set of strings representing the common metacommands. */ -QSet CodeParser::commonMetaCommands() +const QSet& CodeParser::commonMetaCommands() { - return QSet() << 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_REENTRANT + << COMMAND_SINCE + << COMMAND_SUBTITLE + << COMMAND_THREADSAFE + << COMMAND_TITLE + << COMMAND_WRAPPER; + } + return commonMetaCommands_; } /*! @@ -269,8 +273,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(node); + if (node->type() == Node::QmlPropertyGroup) { + const QmlPropertyGroupNode* qpgn = static_cast(node); NodeList::ConstIterator p = qpgn->childNodes().constBegin(); while (p != qpgn->childNodes().constEnd()) { if ((*p)->type() == Node::QmlProperty) { 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 commonMetaCommands(); + const QSet& commonMetaCommands(); void processCommonMetaCommand(const Location& location, const QString& command, const ArgLocPair& arg, 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
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(*c); - NodeList::ConstIterator p = qpgn->childNodes().constBegin(); - while (p != qpgn->childNodes().constEnd()) { - if ((*p)->type() == Node::QmlProperty) { - const QmlPropertyNode* pn = static_cast(*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(*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(*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
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(*c); - NodeList::ConstIterator C = pgn->childNodes().constBegin(); - while (C != pgn->childNodes().constEnd()) { - if ((*C)->type() == Node::QmlProperty) { - const QmlPropertyNode* pn = static_cast(*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(*c); @@ -1278,8 +1237,8 @@ QList
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(*c); + if ((*c)->type() == Node::QmlPropertyGroup) { + const QmlPropertyGroupNode* qpgn = static_cast(*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 d0f3ab3667..30b26264f1 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 topicCommands_; /*! Returns the set of strings reopresenting the topic commands. */ -QSet CppCodeParser::topicCommands() +const QSet& CppCodeParser::topicCommands() { - return QSet() << 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_; } /*! @@ -642,6 +647,35 @@ Node* CppCodeParser::processTopicCommand(const Doc& doc, return 0; } +/*! + A QML property group argument has the form... + + :::: + + This function splits the argument into those parts. + A is the QML equivalent of a C++ namespace. + So this function splits \a arg on "::" and stores the + parts in \a module, \a element, 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& element, + QString& name) +{ + QStringList colonSplit = arg.split("::"); + if (colonSplit.size() == 3) { + module = colonSplit[0]; + element = 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... @@ -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 element; + QString property; + QmlPropertyNode* qpn = 0; + QmlClassNode* qmlClass = 0; + QmlPropertyGroupNode* qpgn = 0; + + Topic qmlPropertyGroupTopic; + const TopicList& topics = doc.topicsUsed(); + for (int i=0; ihasProperty(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, element, property)) { + int i = property.indexOf('.'); + if (i != -1) { + property = property.left(i); + qmlPropertyGroupTopic.args = module + "::" + element + "::" + 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, element, property)) { + qmlClass = qdb_->findQmlType(module, element); + 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; ifindQmlType(module, element); + 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 otherMetaCommands_; /*! Returns the set of strings representing the common metacommands plus some other metacommands. */ -QSet CppCodeParser::otherMetaCommands() +const QSet& 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_; } /*! @@ -961,8 +1034,8 @@ void CppCodeParser::processOtherMetaCommand(const Doc& doc, QmlPropertyNode* qpn = static_cast(node); qpn->setDefault(); } - else if (node->type() == Node::Document && node->subType() == Node::QmlPropertyGroup) { - QmlPropGroupNode* qpgn = static_cast(node); + else if (node->type() == Node::QmlPropertyGroup) { + QmlPropertyGroupNode* qpgn = static_cast(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(node); qpn->setReadOnly(1); } - else if (node->type() == Node::Document && node->subType() == Node::QmlPropertyGroup) { - QmlPropGroupNode* qpgn = static_cast(node); + else if (node->type() == Node::QmlPropertyGroup) { + QmlPropertyGroupNode* qpgn = static_cast(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 topicCommandsAllowed = topicCommands(); - QSet otherMetacommandsAllowed = otherMetaCommands(); - QSet metacommandsAllowed = topicCommandsAllowed + - otherMetacommandsAllowed; + const QSet& topicCommandsAllowed = topicCommands(); + const QSet& otherMetacommandsAllowed = otherMetaCommands(); + const QSet& 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 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 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& topicCommandsUsed = topicCommandsAllowed & doc.metaCommandsUsed(); + if (topicCommandsUsed.count() > 0) { + topic = *topicCommandsUsed.constBegin(); + args = doc.metaCommandArgs(topic); + } + if (topicCommandsUsed.count() > 1) { + QString topics; + QSet::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::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; } } diff --git a/src/tools/qdoc/cppcodeparser.h b/src/tools/qdoc/cppcodeparser.h index 957142712b..d23cc25d33 100644 --- a/src/tools/qdoc/cppcodeparser.h +++ b/src/tools/qdoc/cppcodeparser.h @@ -84,13 +84,16 @@ public: virtual void doneParsingSourceFiles(); protected: - virtual QSet topicCommands(); + const QSet& topicCommands(); + const QSet& 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 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") diff --git a/src/tools/qdoc/ditaxmlgenerator.cpp b/src/tools/qdoc/ditaxmlgenerator.cpp index af8ac505f8..fcd1dd33c2 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(); @@ -4079,8 +4079,8 @@ void DitaXmlGenerator::generateDetailedQmlMember(Node* node, QString marked; QmlPropertyNode* qpn = 0; - if (node->subType() == Node::QmlPropertyGroup) { - const QmlPropGroupNode* qpgn = static_cast(node); + if (node->type() == Node::QmlPropertyGroup) { + const QmlPropertyGroupNode* qpgn = static_cast(node); NodeList::ConstIterator p = qpgn->childNodes().constBegin(); if (qpgn->childNodes().size() == 1) { qpn = static_cast(*p); @@ -4114,50 +4114,10 @@ void DitaXmlGenerator::generateDetailedQmlMember(Node* node, } else if (node->type() == Node::QmlProperty) { qpn = static_cast(node); - if (qpn->qmlPropNodes().isEmpty()) { - startQmlProperty(qpn,relative,marker); - writeApiDesc(node, marker, node->title()); - writeEndTag(); // - writeEndTag(); // - } - else if (qpn->qmlPropNodes().size() == 1) { - Node* n = qpn->qmlPropNodes().at(0); - if (n->type() == Node::QmlProperty) { - qpn = static_cast(n); - startQmlProperty(qpn,relative,marker); - writeApiDesc(node, marker, node->title()); - writeEndTag(); // - writeEndTag(); // - } - } - 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(); // - writeStartTag(DT_qmlPropertyGroupDetail); - writeApiDesc(node, marker, node->title()); - writeEndTag(); // - NodeList::ConstIterator p = qpn->qmlPropNodes().constBegin(); - while (p != qpn->qmlPropNodes().constEnd()) { - if ((*p)->type() == Node::QmlProperty) { - QmlPropertyNode* q = static_cast(*p); - startQmlProperty(q,relative,marker); - writeEndTag(); // - writeEndTag(); // - } - ++p; - } - writeEndTag(); // title()); + writeEndTag(); // + writeEndTag(); // } 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 12056502d5..ff9b9900bf 100644 --- a/src/tools/qdoc/doc.cpp +++ b/src/tools/qdoc/doc.cpp @@ -376,7 +376,7 @@ public: bool hasLegalese : 1; bool hasSectioningUnits : 1; DocPrivateExtra *extra; - TopicList topics; + TopicList topics_; DitaRefList ditamap_; }; @@ -571,7 +571,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; @@ -1404,7 +1404,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)) { @@ -2751,6 +2751,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 +2761,7 @@ Doc::Doc(const Location& start_loc, DocParser parser; parser.parse(source,priv,metaCommandSet,QSet()); } +#endif /*! Parse the qdoc comment \a source. Build up a list of all the topic @@ -3026,7 +3028,7 @@ const QSet &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..23fc4c5b8b 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 TopicList; @@ -136,10 +139,6 @@ public: }; Doc() : priv(0) {} - Doc(const Location &start_loc, - const Location &end_loc, - const QString &source, - const QSet &metaCommandSet); Doc(const Location& start_loc, const Location& end_loc, const QString& source, @@ -196,6 +195,7 @@ private: void detach(); DocPrivate *priv; }; +typedef QList DocList; QT_END_NAMESPACE diff --git a/src/tools/qdoc/generator.cpp b/src/tools/qdoc/generator.cpp index 6f11f666bd..7568a519bb 100644 --- a/src/tools/qdoc/generator.cpp +++ b/src/tools/qdoc/generator.cpp @@ -301,7 +301,7 @@ 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(); } @@ -469,7 +469,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); } @@ -942,13 +942,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. @@ -1910,8 +1910,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: @@ -1926,6 +1924,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/helpprojectwriter.cpp b/src/tools/qdoc/helpprojectwriter.cpp index 0cdb2de776..9e67007eba 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 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 allSubTypes = QSet::fromList(subTypeHash.values()); @@ -435,21 +435,24 @@ void HelpProjectWriter::generateSections(HelpProject &project, continue; if (childNode->type() == Node::Document) { + childMap[static_cast(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(childNode); - foreach (const Node* n, inner->childNodes()) { - if (n->access() == Node::Private) - continue; - childMap[n->fullDocumentName()] = n; - } + const InnerNode* inner = static_cast(childNode); + foreach (const Node* n, inner->childNodes()) { + if (n->access() == Node::Private) + continue; + childMap[n->fullDocumentName()] = n; } - else - childMap[static_cast(childNode)->fullTitle()] = childNode; } else { // Store member status of children diff --git a/src/tools/qdoc/htmlgenerator.cpp b/src/tools/qdoc/htmlgenerator.cpp index 8afc1c749a..387ce066bb 100644 --- a/src/tools/qdoc/htmlgenerator.cpp +++ b/src/tools/qdoc/htmlgenerator.cpp @@ -3266,8 +3266,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"; @@ -3330,7 +3330,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(); @@ -3736,6 +3736,22 @@ void HtmlGenerator::generateQmlSummary(const Section& section, while (m != section.members.constEnd()) { out() << "
  • "; generateQmlItem(*m,relative,marker,true); + if ((*m)->type() == Node::QmlPropertyGroup) { + const QmlPropertyGroupNode* qpgn = static_cast(*m); + if (!qpgn->childNodes().isEmpty()) { + NodeList::ConstIterator p = qpgn->childNodes().constBegin(); + out() << "
      \n"; + while (p != qpgn->childNodes().constEnd()) { + if ((*p)->type() == Node::QmlProperty) { + out() << "
    • "; + generateQmlItem(*p, relative, marker, true); + out() << "
    • \n"; + } + ++p; + } + out() << "
    \n"; + } + } out() << "
  • \n"; ++m; } @@ -3757,11 +3773,18 @@ void HtmlGenerator::generateDetailedQmlMember(Node *node, #endif generateExtractionMark(node, MemberMark); out() << "
    "; - if (node->subType() == Node::QmlPropertyGroup) { - const QmlPropGroupNode* qpgn = static_cast(node); + if (node->type() == Node::QmlPropertyGroup) { + const QmlPropertyGroupNode* qpgn = static_cast(node); NodeList::ConstIterator p = qpgn->childNodes().constBegin(); out() << "
    "; out() << ""; + + QString heading = "Property Group: " + qpgn->name(); + out() << ""; + out() << ""; while (p != qpgn->childNodes().constEnd()) { if ((*p)->type() == Node::QmlProperty) { qpn = static_cast(*p); @@ -3783,68 +3806,23 @@ void HtmlGenerator::generateDetailedQmlMember(Node *node, } else if (node->type() == Node::QmlProperty) { qpn = static_cast(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(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() << "
    "; - out() << "

    "; + out() << ""; + out() << "" << heading << ""; + out() << "

    "; - out() << ""; - out() << ""; - out() << "

    "; - out() << ""; - if (!qpn->isReadOnlySet()) { - if (qpn->declarativeCppNode()) - qpn->setReadOnly(!qpn->isWritable(qdb_)); - } - if (qpn->isReadOnly()) - out() << "read-only"; - if (qpn->isDefault()) - out() << "default"; - generateQmlItem(qpn, relative, marker, false); - out() << "

    "; - out() << "
    "; - } - 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() << "
    "; - out() << ""; - while (p != qpn->qmlPropNodes().constEnd()) { - if ((*p)->type() == Node::QmlProperty) { - QmlPropertyNode* q = static_cast(*p); - out() << ""; - out() << ""; - } - ++p; - } - out() << "

    "; - out() << ""; - if (!qpn->isReadOnlySet()) - qpn->setReadOnly(!qpn->isWritable(qdb_)); - if (qpn->isReadOnly()) - out() << "read-only"; - if (qpn->isDefault()) - out() << "default"; - generateQmlItem(q, relative, marker, false); - out() << "

    "; - out() << "
    "; - } + out() << "
    "; + out() << ""; + out() << ""; + out() << ""; + out() << "

    "; + out() << ""; + if (!qpn->isReadOnlySet()) { + if (qpn->declarativeCppNode()) + qpn->setReadOnly(!qpn->isWritable(qdb_)); + } + if (qpn->isReadOnly()) + out() << "read-only"; + if (qpn->isDefault()) + out() << "default"; + generateQmlItem(qpn, relative, marker, false); + out() << "

    "; + out() << "
    "; } else if (node->type() == Node::QmlSignal) { const FunctionNode* qsn = static_cast(node); @@ -4317,8 +4295,6 @@ void HtmlGenerator::reportOrphans(const InnerNode* parent) break; case Node::QmlClass: break; - case Node::QmlPropertyGroup: - break; case Node::QmlBasicType: break; case Node::QmlModule: @@ -4352,6 +4328,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/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; isubType() == QmlPropertyGroup) { + if (n->type() == QmlPropertyGroup) { node = static_cast(n)->findChildNodeByName(name); if (node) return node; @@ -771,7 +771,7 @@ void InnerNode::findNodes(const QString& name, QList& n) if ((type() == Document) && (subType() == QmlClass)) { for (int i=0; isubType() == QmlPropertyGroup) { + if (node->type() == QmlPropertyGroup) { node = static_cast(node)->findChildNodeByName(name); if (node) { n.append(node); @@ -793,7 +793,7 @@ void InnerNode::findNodes(const QString& name, QList& n) */ for (int i=0; isubType() != QmlPropertyGroup) + if (node->type() != QmlPropertyGroup) n.append(node); else { node = static_cast(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; isubType() == QmlPropertyGroup) { + if (node->type() == QmlPropertyGroup) { node = static_cast(node)->findChildNodeByName(name); if (node) return node; @@ -1370,6 +1370,26 @@ void InnerNode::removeRelated(Node *pseudoChild) related_.removeAll(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(child); + } + else if (child->type() == Node::QmlPropertyGroup) { + QmlPropertyNode* t = child->hasQmlProperty(n); + if (t) + return t; + } + } + return 0; +} + /*! \class LeafNode */ @@ -1672,25 +1692,6 @@ QString DocNode::subTitle() const return QString(); } -/*! - 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(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(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..d5aa4a0cd4 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 NodeList; typedef QMap 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, @@ -200,8 +201,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 +213,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 +237,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,7 +300,7 @@ private: InnerNode* relatesTo_; QString name_; Location loc; - Doc d; + Doc doc_; QMap > linkMap_; QString moduleName_; QString url_; @@ -366,6 +372,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); @@ -497,8 +504,6 @@ 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_; @@ -619,11 +624,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 +636,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 +651,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 +679,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(parent())->element(); } - void appendQmlPropNode(QmlPropertyNode* p) { qmlPropNodes_.append(p); } - const NodeList& qmlPropNodes() const { return qmlPropNodes_; } + const QString& element() const { return static_cast(parent())->element(); } private: QString type_; FlagValue stored_; FlagValue designable_; + bool isAlias_; bool isdefault_; bool attached_; FlagValue readOnly_; - NodeList qmlPropNodes_; }; class EnumItem @@ -892,7 +888,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 topicCommandsAllowed = topicCommands(); - QSet otherMetacommandsAllowed = otherMetaCommands(); - QSet metacommandsAllowed = topicCommandsAllowed + otherMetacommandsAllowed; + const QSet& topicCommandsAllowed = topicCommands(); + const QSet& otherMetacommandsAllowed = otherMetaCommands(); + const QSet& 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 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 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 topicCommandsUsed = topicCommandsAllowed & doc.metaCommandsUsed(); + if (topicCommandsUsed.count() > 0) { + topic = *topicCommandsUsed.begin(); + args = doc.metaCommandArgs(topic); + } + if (topicCommandsUsed.count() > 1) { + QString topics; + QSet::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..4faa8ec8fc 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(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(parent); + qpn = new QmlPropertyNode(qcn, name, type, attached); + } + else if (parent->type() == Node::QmlPropertyGroup) { + QmlPropertyGroupNode* qpgn = static_cast(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 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; @@ -927,6 +944,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(node); @@ -1179,17 +1202,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(child); foreach (Node* c, pgn->childNodes()) { generateIndexSections(writer, c, generateInternalNodes); 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 topicCommandsAllowed = topicCommands(); - QSet otherMetacommandsAllowed = otherMetaCommands(); - QSet metacommandsAllowed = topicCommandsAllowed + otherMetacommandsAllowed; + const QSet& topicCommandsAllowed = topicCommands(); + const QSet& otherMetacommandsAllowed = otherMetaCommands(); + const QSet& metacommandsAllowed = topicCommandsAllowed + otherMetacommandsAllowed; if (parser->parse()) { QQmlJS::AST::UiProgram *ast = parser->ast(); @@ -195,42 +196,52 @@ void QmlCodeParser::doneParsingSourceFiles() { } +static QSet topicCommands_; /*! Returns the set of strings representing the topic commands. */ -QSet QmlCodeParser::topicCommands() +const QSet& QmlCodeParser::topicCommands() { - return QSet() << 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 otherMetaCommands_; /*! Returns the set of strings representing the common metacommands plus some other metacommands. */ -QSet QmlCodeParser::otherMetaCommands() +const QSet& 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 topicCommands(); - virtual QSet otherMetaCommands(); + const QSet& topicCommands(); + const QSet& otherMetaCommands(); private: QQmlJS::Engine engine; diff --git a/src/tools/qdoc/qmlvisitor.cpp b/src/tools/qdoc/qmlvisitor.cpp index 86b86c8f34..5f1851ae70 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 &commands, - QSet &topics) + const QSet &commands, + const QSet &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::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(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(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(node); + for (int i=0; ihasQmlPropertyNode(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,68 @@ 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(); + int pgc_idx = -1; node->setDoc(doc); - applyMetacommands(loc, node, doc); + nodes.append(node); + if (topicsUsed.size() > 0) { + for (int i=0; iname()) { + 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; isetLocation(codeLoc); return false; @@ -237,80 +359,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(node); - for (int i=0; isetLocation(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 metacommands = doc.metaCommandsUsed(); if (metacommands.count() > 0) { - QString topic; - ArgList args; + metacommands.subtract(topics_); QSet::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(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(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 +583,9 @@ bool QmlDocVisitor::visit(QQmlJS::AST::UiPublicMember *member) QmlClassNode *qmlClass = static_cast(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 b59fbb0cbb..cdb7ae7391 100644 --- a/src/tools/qdoc/qmlvisitor.h +++ b/src/tools/qdoc/qmlvisitor.h @@ -71,8 +71,8 @@ public: QmlDocVisitor(const QString &filePath, const QString &code, QQmlJS::Engine *engine, - QSet &commands, - QSet &topics); + const QSet &commands, + const QSet &topics); virtual ~QmlDocVisitor(); bool visit(QQmlJS::AST::UiImportList *imports); @@ -112,12 +112,12 @@ private: QQmlJS::Engine *engine; quint32 lastEndOffset; quint32 nestingLevel; - QString filePath; + QString filePath_; QString name; QString document; ImportList importList; - QSet commands; - QSet topics; + QSet commands_; + QSet topics_; QSet 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); } -- cgit v1.2.3