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 <jerome.pasion@digia.com>
This commit is contained in:
Martin Smith 2013-07-10 13:47:47 +02:00 committed by The Qt Project
parent b06304e164
commit 2eb28f51ce
22 changed files with 685 additions and 674 deletions

View File

@ -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()) {

View File

@ -199,29 +199,33 @@ 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_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<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) {

View File

@ -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,

View File

@ -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) {

View File

@ -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_;
}
/*!
@ -642,6 +647,35 @@ Node* CppCodeParser::processTopicCommand(const Doc& doc,
return 0;
}
/*!
A QML property group argument has the form...
<QML-module>::<element>::<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 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; 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, 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());
}
++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));
}
else {
QmlPropertyNode* qmlPropNode = new QmlPropertyNode(qmlPropGroup,
property,
type,
attached);
qmlPropNode->setLocation(doc.startLocation());
}
}
++argsIter;
/*
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());
}
}
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, element, property)) {
qmlClass = qdb_->findQmlType(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 {
qpn = new QmlPropertyNode(qmlClass, property, type, attached);
qpn->setLocation(doc.startLocation());
nodes.append(qpn);
docs.append(doc);
}
}
}
}
}
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_;
}
/*!
@ -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;
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.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;
}
}

View File

@ -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")

View File

@ -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<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:

View File

@ -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<QString>());
}
#endif
/*!
Parse the qdoc comment \a source. Build up a list of all the topic
@ -3026,7 +3028,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

View File

@ -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,
@ -196,6 +195,7 @@ private:
void detach();
DocPrivate *priv;
};
typedef QList<Doc> DocList;
QT_END_NAMESPACE

View File

@ -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";
}

View File

@ -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());
@ -435,21 +435,24 @@ void HelpProjectWriter::generateSections(HelpProject &project,
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

View File

@ -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() << "<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;
}
@ -3757,11 +3773,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 = "Property Group: " + qpgn->name();
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);
@ -3783,68 +3806,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);
@ -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));

View File

@ -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;
@ -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<QmlPropertyNode*>(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<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;

View File

@ -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,
@ -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<LinkType, QPair<QString, QString> > 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<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 +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); }

View File

@ -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;
}
}

View File

@ -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;

View File

@ -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;
@ -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<const PropertyNode*>(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<const InnerNode*>(child);
foreach (Node* c, pgn->childNodes()) {
generateIndexSections(writer, c, generateInternalNodes);

View File

@ -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_;
}
/*!

View File

@ -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;

View File

@ -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,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; i<topicsUsed.size(); ++i) {
if (topicsUsed.at(i).topic == QString("qmlpropertygroup")) {
pgc_idx = i;
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 +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<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 +583,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();

View File

@ -71,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);
@ -112,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;
};

View File

@ -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);
}