From 0eaa3466077839b0cef2ad6c326d80f398eccae7 Mon Sep 17 00:00:00 2001
From: Aaron Kennedy
Date: Wed, 29 Jul 2009 17:09:54 +1000
Subject: Merge QML specific qdoc changes
Reviewed-by: Martin Smith
---
tools/qdoc3/codemarker.cpp | 81 ++++--
tools/qdoc3/codemarker.h | 12 +-
tools/qdoc3/command.cpp | 44 ++--
tools/qdoc3/cppcodemarker.cpp | 141 +++++++++-
tools/qdoc3/cppcodemarker.h | 5 +
tools/qdoc3/cppcodeparser.cpp | 282 ++++++++++++++++----
tools/qdoc3/cppcodeparser.h | 15 ++
tools/qdoc3/generator.cpp | 143 ++++++----
tools/qdoc3/generator.h | 5 +-
tools/qdoc3/helpprojectwriter.cpp | 35 +--
tools/qdoc3/htmlgenerator.cpp | 533 ++++++++++++++++++++++++++++++++------
tools/qdoc3/htmlgenerator.h | 23 +-
tools/qdoc3/jambiapiparser.cpp | 5 +-
tools/qdoc3/node.cpp | 106 +++++++-
tools/qdoc3/node.h | 131 ++++++++--
tools/qdoc3/pagegenerator.cpp | 59 +++--
tools/qdoc3/test/classic.css | 49 ++++
tools/qdoc3/tree.cpp | 52 ++--
tools/qdoc3/webxmlgenerator.cpp | 4 +-
19 files changed, 1413 insertions(+), 312 deletions(-)
diff --git a/tools/qdoc3/codemarker.cpp b/tools/qdoc3/codemarker.cpp
index e95153d..4c018d1 100644
--- a/tools/qdoc3/codemarker.cpp
+++ b/tools/qdoc3/codemarker.cpp
@@ -168,7 +168,8 @@ const Node *CodeMarker::nodeForString(const QString& string)
{
if (sizeof(const Node *) == sizeof(uint)) {
return reinterpret_cast(string.toUInt());
- } else {
+ }
+ else {
return reinterpret_cast(string.toULongLong());
}
}
@@ -177,7 +178,8 @@ QString CodeMarker::stringForNode(const Node *node)
{
if (sizeof(const Node *) == sizeof(ulong)) {
return QString::number(reinterpret_cast(node));
- } else {
+ }
+ else {
return QString::number(reinterpret_cast(node));
}
}
@@ -220,7 +222,8 @@ QString CodeMarker::typified(const QString &string)
|| ch.digitValue() >= 0 || ch == QLatin1Char('_')
|| ch == QLatin1Char(':')) {
pendingWord += ch;
- } else {
+ }
+ else {
if (!pendingWord.isEmpty()) {
bool isProbablyType = (pendingWord != QLatin1String("const"));
if (isProbablyType)
@@ -251,7 +254,7 @@ QString CodeMarker::typified(const QString &string)
return result;
}
-QString CodeMarker::taggedNode(const Node *node)
+QString CodeMarker::taggedNode(const Node* node)
{
QString tag;
@@ -276,10 +279,34 @@ QString CodeMarker::taggedNode(const Node *node)
break;
default:
tag = QLatin1String("@unknown");
+ break;
+ }
+ return QLatin1Char('<') + tag + QLatin1Char('>') + protect(node->name())
+ + QLatin1String("") + tag + QLatin1Char('>');
+}
+
+#ifdef QDOC_QML
+QString CodeMarker::taggedQmlNode(const Node* node)
+{
+ QString tag;
+ switch (node->type()) {
+ case Node::QmlProperty:
+ tag = QLatin1String("@property");
+ break;
+ case Node::QmlSignal:
+ tag = QLatin1String("@signal");
+ break;
+ case Node::QmlMethod:
+ tag = QLatin1String("@method");
+ break;
+ default:
+ tag = QLatin1String("@unknown");
+ break;
}
return QLatin1Char('<') + tag + QLatin1Char('>') + protect(node->name())
+ QLatin1String("") + tag + QLatin1Char('>');
}
+#endif
QString CodeMarker::linkTag(const Node *node, const QString& body)
{
@@ -308,9 +335,11 @@ QString CodeMarker::sortName(const Node *node)
QString sortNo;
if (func->metaness() == FunctionNode::Ctor) {
sortNo = QLatin1String("C");
- } else if (func->metaness() == FunctionNode::Dtor) {
+ }
+ else if (func->metaness() == FunctionNode::Dtor) {
sortNo = QLatin1String("D");
- } else {
+ }
+ else {
if (nodeName.startsWith(QLatin1String("operator"))
&& nodeName.length() > 8
&& !nodeName[8].isLetterOrNumber())
@@ -336,9 +365,14 @@ void CodeMarker::insert(FastSection &fastSection,
SynopsisStyle style,
Status status)
{
- bool inheritedMember = (!node->relates() &&
- (node->parent() != (const InnerNode *)fastSection.innerNode));
bool irrelevant = false;
+ bool inheritedMember = false;
+ if (!node->relates()) {
+ if (node->parent() != (const InnerNode*)fastSection.innerNode) {
+ if (node->type() != Node::QmlProperty)
+ inheritedMember = true;
+ }
+ }
if (node->access() == Node::Private) {
irrelevant = true;
@@ -462,7 +496,8 @@ QStringList CodeMarker::macRefsForNode(const Node *node)
#if 0
if (!classe->templateStuff().isEmpty()) {
result += QLatin1String("tmplt/");
- } else
+ }
+ else
#endif
{
result += QLatin1String("cl/");
@@ -499,14 +534,18 @@ QStringList CodeMarker::macRefsForNode(const Node *node)
result += QLatin1String("macro/");
isMacro = true;
#if 0
- } else if (!func->templateStuff().isEmpty()) {
+ }
+ else if (!func->templateStuff().isEmpty()) {
result += QLatin1String("ftmplt/");
#endif
- } else if (func->isStatic()) {
+ }
+ else if (func->isStatic()) {
result += QLatin1String("clm/");
- } else if (!func->parent()->name().isEmpty()) {
+ }
+ else if (!func->parent()->name().isEmpty()) {
result += QLatin1String("instm/");
- } else {
+ }
+ else {
result += QLatin1String("func/");
}
@@ -520,7 +559,8 @@ QStringList CodeMarker::macRefsForNode(const Node *node)
result += "/" + QLatin1String(QMetaObject::normalizedSignature(func->returnType().toLatin1().constData())) + "/(";
const QList ¶ms = func->parameters();
for (int i = 0; i < params.count(); ++i) {
- QString type = params.at(i).leftType() + params.at(i).rightType();
+ QString type = params.at(i).leftType() +
+ params.at(i).rightType();
type = QLatin1String(QMetaObject::normalizedSignature(type.toLatin1().constData()));
if (i != 0)
result += ",";
@@ -563,10 +603,21 @@ QString CodeMarker::macName(const Node *node, const QString &name)
if (node->name().isEmpty()) {
return QLatin1Char('/') + myName;
- } else {
+ }
+ else {
return plainFullName(node) + QLatin1Char('/') + myName;
}
}
+#ifdef QDOC_QML
+/*!
+ Get the list of documentation sections for the children of
+ the specified QmlClassNode.
+ */
+QList CodeMarker::qmlSections(const QmlClassNode* , SynopsisStyle )
+{
+ return QList();
+}
+#endif
QT_END_NAMESPACE
diff --git a/tools/qdoc3/codemarker.h b/tools/qdoc3/codemarker.h
index 67b1064..91dc8b0 100644
--- a/tools/qdoc3/codemarker.h
+++ b/tools/qdoc3/codemarker.h
@@ -121,6 +121,9 @@ class CodeMarker
virtual QString markedUpSynopsis(const Node *node,
const Node *relative,
SynopsisStyle style) = 0;
+#ifdef QDOC_QML
+ virtual QString markedUpQmlItem(const Node* , bool) { return QString(); }
+#endif
virtual QString markedUpName(const Node *node) = 0;
virtual QString markedUpFullName(const Node *node,
const Node *relative = 0) = 0;
@@ -132,6 +135,10 @@ class CodeMarker
virtual QList sections(const InnerNode *inner,
SynopsisStyle style,
Status status) = 0;
+#ifdef QDOC_QML
+ virtual QList qmlSections(const QmlClassNode* qmlClassNode,
+ SynopsisStyle style);
+#endif
virtual const Node *resolveTarget(const QString& target,
const Tree *tree,
const Node *relative) = 0;
@@ -151,7 +158,10 @@ class CodeMarker
virtual QString sortName(const Node *node);
QString protect(const QString &string);
QString typified(const QString &string);
- QString taggedNode(const Node *node);
+ QString taggedNode(const Node* node);
+#ifdef QDOC_QML
+ QString taggedQmlNode(const Node* node);
+#endif
QString linkTag(const Node *node, const QString& body);
void insert(FastSection &fastSection,
Node *node,
diff --git a/tools/qdoc3/command.cpp b/tools/qdoc3/command.cpp
index e51e235..bce262b 100644
--- a/tools/qdoc3/command.cpp
+++ b/tools/qdoc3/command.cpp
@@ -49,44 +49,46 @@
QT_BEGIN_NAMESPACE
-void executeCommand( const Location& location, const QString& format,
- const QStringList& args )
+void executeCommand(const Location& location,
+ const QString& format,
+ const QStringList& args)
{
QString actualCommand;
- for ( int i = 0; i < (int) format.length(); i++ ) {
+ for (int i = 0; i < (int) format.length(); i++) {
int ch = format[i].unicode();
- if ( ch > 0 && ch < 8 ) {
+ if (ch > 0 && ch < 8) {
actualCommand += args[ch - 1];
- } else {
+ }
+ else {
actualCommand += format[i];
}
}
QString toolName = actualCommand;
- int space = toolName.indexOf( QLatin1Char(' ') );
- if ( space != -1 )
- toolName.truncate( space );
+ int space = toolName.indexOf(QLatin1Char(' '));
+ if (space != -1)
+ toolName.truncate(space);
QProcess process;
process.start(QLatin1String("sh"),
- QStringList() << QLatin1String("-c") << actualCommand );
+ QStringList() << QLatin1String("-c") << actualCommand);
process.waitForFinished();
if (process.exitCode() == 127)
- location.fatal( tr("Couldn't launch the '%1' tool")
- .arg(toolName),
- tr("Make sure the tool is installed and in the"
- " path.") );
+ location.fatal(tr("Couldn't launch the '%1' tool")
+ .arg(toolName),
+ tr("Make sure the tool is installed and in the"
+ " path."));
QString errors = QString::fromLocal8Bit(process.readAllStandardError());
- while ( errors.endsWith(QLatin1Char('\n')) )
- errors.truncate( errors.length() - 1 );
- if ( !errors.isEmpty() )
- location.fatal( tr("The '%1' tool encountered some problems")
- .arg(toolName),
- tr("The tool was invoked like this:\n%1\n"
- "It emitted these errors:\n%2")
- .arg(actualCommand).arg(errors) );
+ while (errors.endsWith(QLatin1Char('\n')))
+ errors.truncate(errors.length() - 1);
+ if (!errors.isEmpty())
+ location.fatal(tr("The '%1' tool encountered some problems")
+ .arg(toolName),
+ tr("The tool was invoked like this:\n%1\n"
+ "It emitted these errors:\n%2")
+ .arg(actualCommand).arg(errors));
}
QT_END_NAMESPACE
diff --git a/tools/qdoc3/cppcodemarker.cpp b/tools/qdoc3/cppcodemarker.cpp
index f807609..0f8d1b7 100644
--- a/tools/qdoc3/cppcodemarker.cpp
+++ b/tools/qdoc3/cppcodemarker.cpp
@@ -284,7 +284,7 @@ QString CppCodeMarker::markedUpSynopsis(const Node *node,
}
else {
for (int i = 0; i < documentedItems.size(); ++i) {
- if (i < MaxEnumValues - 2 || i == documentedItems.size() - 1) {
+ if (i < MaxEnumValues-2 || i == documentedItems.size()-1) {
if (i != 0)
synopsis += ", ";
synopsis += documentedItems.at(i);
@@ -345,6 +345,43 @@ QString CppCodeMarker::markedUpSynopsis(const Node *node,
return synopsis + extra;
}
+#ifdef QDOC_QML
+/*!
+ */
+QString CppCodeMarker::markedUpQmlItem(const Node* node, bool summary)
+{
+ QString name = taggedQmlNode(node);
+ if (summary) {
+ name = linkTag(node,name);
+ }
+ name = "<@name>" + name + "@name>";
+ QString synopsis = name;
+ if (node->type() == Node::QmlProperty) {
+ const QmlPropertyNode* pn = static_cast(node);
+ synopsis += " : " + typified(pn->dataType());
+ }
+
+ QString extra;
+ if (summary) {
+ if (node->status() == Node::Preliminary) {
+ extra += " (preliminary)";
+ }
+ else if (node->status() == Node::Deprecated) {
+ extra += " (deprecated)";
+ }
+ else if (node->status() == Node::Obsolete) {
+ extra += " (obsolete)";
+ }
+ }
+
+ if (!extra.isEmpty()) {
+ extra.prepend("<@extra>");
+ extra.append("@extra>");
+ }
+ return synopsis + extra;
+}
+#endif
+
QString CppCodeMarker::markedUpName(const Node *node)
{
QString name = linkTag(node, taggedNode(node));
@@ -537,7 +574,7 @@ QList CppCodeMarker::sections(const InnerNode *inner,
else if (isStatic) {
if ((*c)->type() != Node::Variable
|| !(*c)->doc().isEmpty())
- insert(staticPublicMembers, *c, style, status);
+ insert(staticPublicMembers,*c,style,status);
}
else if ((*c)->type() == Node::Property) {
insert(properties, *c, style, status);
@@ -561,11 +598,11 @@ QList CppCodeMarker::sections(const InnerNode *inner,
else if (isStatic) {
if ((*c)->type() != Node::Variable
|| !(*c)->doc().isEmpty())
- insert(staticProtectedMembers, *c, style, status);
+ insert(staticProtectedMembers,*c,style,status);
}
else if ((*c)->type() == Node::Variable) {
if (!(*c)->doc().isEmpty())
- insert(protectedVariables, *c, style, status);
+ insert(protectedVariables,*c,style,status);
}
else if ((*c)->type() == Node::Function) {
if (!insertReimpFunc(protectedFunctions,*c,status))
@@ -582,14 +619,14 @@ QList CppCodeMarker::sections(const InnerNode *inner,
else if (isStatic) {
if ((*c)->type() != Node::Variable
|| !(*c)->doc().isEmpty())
- insert(staticPrivateMembers, *c, style, status);
+ insert(staticPrivateMembers,*c,style,status);
}
else if ((*c)->type() == Node::Function) {
if (!insertReimpFunc(privateFunctions,*c,status))
insert(privateFunctions, *c, style, status);
}
else {
- insert(privateTypes, *c, style, status);
+ insert(privateTypes,*c,style,status);
}
}
++c;
@@ -706,17 +743,23 @@ QList CppCodeMarker::sections(const InnerNode *inner,
"Namespaces",
"namespace",
"namespaces");
- FastSection classes(inner, "Classes", "class", "classes");
+ FastSection classes(inner,
+ "Classes",
+ "class",
+ "classes");
FastSection types(inner,
- style == Summary ? "Types" : "Type Documentation",
+ style == Summary ?
+ "Types" : "Type Documentation",
"type",
"types");
FastSection functions(inner,
- style == Summary ? "Functions" : "Function Documentation",
+ style == Summary ?
+ "Functions" : "Function Documentation",
"function",
"functions");
FastSection macros(inner,
- style == Summary ? "Macros" : "Macro Documentation",
+ style == Summary ?
+ "Macros" : "Macro Documentation",
"macro",
"macros");
@@ -1051,4 +1094,82 @@ QString CppCodeMarker::addMarkUp(const QString& protectedCode,
return result;
}
+#ifdef QDOC_QML
+/*!
+ This function is for documenting QML properties. It returns
+ the list of documentation sections for the children of the
+ \a qmlClassNode.
+
+ Currently, it only handles QML property groups.
+ */
+QList CppCodeMarker::qmlSections(const QmlClassNode* qmlClassNode,
+ SynopsisStyle style)
+{
+ QList sections;
+ if (qmlClassNode) {
+ if (style == Summary) {
+ FastSection qmlproperties(qmlClassNode,
+ "QML Properties",
+ "property",
+ "properties");
+ FastSection qmlsignals(qmlClassNode,
+ "QML Signals",
+ "signal",
+ "signals");
+ FastSection qmlmethods(qmlClassNode,
+ "QML Methods",
+ "method",
+ "methods");
+
+ NodeList::ConstIterator c = qmlClassNode->childNodes().begin();
+ while (c != qmlClassNode->childNodes().end()) {
+ if ((*c)->subType() == Node::QmlPropertyGroup) {
+ const QmlPropGroupNode* qpgn = static_cast(*c);
+ NodeList::ConstIterator p = qpgn->childNodes().begin();
+ while (p != qpgn->childNodes().end()) {
+ if ((*p)->type() == Node::QmlProperty) {
+ insert(qmlproperties,*p,style,Okay);
+ }
+ ++p;
+ }
+ }
+ else if ((*c)->type() == Node::QmlSignal) {
+ insert(qmlsignals,*c,style,Okay);
+ }
+ else if ((*c)->type() == Node::QmlMethod) {
+ insert(qmlmethods,*c,style,Okay);
+ }
+ ++c;
+ }
+ append(sections,qmlproperties);
+ append(sections,qmlsignals);
+ append(sections,qmlmethods);
+ }
+ else if (style == Detailed) {
+ FastSection qmlproperties(qmlClassNode,"QML Property Documentation");
+ FastSection qmlsignals(qmlClassNode,"QML Signal Documentation");
+ FastSection qmlmethods(qmlClassNode,"QML Method Documentation");
+ NodeList::ConstIterator c = qmlClassNode->childNodes().begin();
+ while (c != qmlClassNode->childNodes().end()) {
+ if ((*c)->subType() == Node::QmlPropertyGroup) {
+ insert(qmlproperties,*c,style,Okay);
+ }
+ else if ((*c)->type() == Node::QmlSignal) {
+ insert(qmlsignals,*c,style,Okay);
+ }
+ else if ((*c)->type() == Node::QmlMethod) {
+ insert(qmlmethods,*c,style,Okay);
+ }
+ ++c;
+ }
+ append(sections,qmlproperties);
+ append(sections,qmlsignals);
+ append(sections,qmlmethods);
+ }
+ }
+
+ return sections;
+}
+#endif
+
QT_END_NAMESPACE
diff --git a/tools/qdoc3/cppcodemarker.h b/tools/qdoc3/cppcodemarker.h
index 2967dfe..fa3cb78 100644
--- a/tools/qdoc3/cppcodemarker.h
+++ b/tools/qdoc3/cppcodemarker.h
@@ -67,6 +67,9 @@ class CppCodeMarker : public CodeMarker
QString markedUpSynopsis(const Node *node,
const Node *relative,
SynopsisStyle style);
+#ifdef QDOC_QML
+ QString markedUpQmlItem(const Node *node, bool summary);
+#endif
QString markedUpName(const Node *node);
QString markedUpFullName(const Node *node, const Node *relative);
QString markedUpEnumValue(const QString &enumValue, const Node *relative);
@@ -76,6 +79,8 @@ class CppCodeMarker : public CodeMarker
QList sections(const InnerNode *innerNode,
SynopsisStyle style,
Status status);
+ QList qmlSections(const QmlClassNode* qmlClassNode,
+ SynopsisStyle style);
const Node *resolveTarget(const QString& target,
const Tree *tree,
const Node *relative);
diff --git a/tools/qdoc3/cppcodeparser.cpp b/tools/qdoc3/cppcodeparser.cpp
index dd10c1c..4563f65 100644
--- a/tools/qdoc3/cppcodeparser.cpp
+++ b/tools/qdoc3/cppcodeparser.cpp
@@ -87,6 +87,10 @@ QT_BEGIN_NAMESPACE
#ifdef QDOC_QML
#define COMMAND_QMLCLASS Doc::alias("qmlclass")
#define COMMAND_QMLPROPERTY Doc::alias("qmlproperty")
+#define COMMAND_QMLINHERITS Doc::alias("inherits")
+#define COMMAND_QMLSIGNAL Doc::alias("qmlsignal")
+#define COMMAND_QMLMETHOD Doc::alias("qmlmethod")
+#define COMMAND_QMLDEFAULT Doc::alias("default")
#endif
QStringList CppCodeParser::exampleFiles;
@@ -109,7 +113,8 @@ static void extractPageLinkAndDesc(const QString &arg,
if (arg.contains(".html") && spaceAt != -1) {
*link = arg.left(spaceAt).trimmed();
*desc = arg.mid(spaceAt).trimmed();
- } else {
+ }
+ else {
*link = arg;
*desc = arg;
}
@@ -202,11 +207,6 @@ void CppCodeParser::initializeParser(const Config &config)
nodeTypeMap.insert(COMMAND_PROPERTY, Node::Property);
nodeTypeMap.insert(COMMAND_VARIABLE, Node::Variable);
-#ifdef QDOC_QML
- // nodeTypeMap.insert(COMMAND_QMLCLASS, Node::Class);
- nodeTypeMap.insert(COMMAND_QMLPROPERTY, Node::Property);
-#endif
-
exampleFiles = config.getStringList(CONFIG_EXAMPLES);
exampleDirs = config.getStringList(CONFIG_EXAMPLEDIRS);
QStringList exampleFilePatterns = config.getStringList(
@@ -477,13 +477,15 @@ QSet CppCodeParser::topicCommands()
<< COMMAND_PROPERTY
<< COMMAND_SERVICE
<< COMMAND_TYPEDEF
-#ifdef QDOC_QML
+#ifdef QDOC_QML
<< COMMAND_VARIABLE
<< COMMAND_QMLCLASS
- << COMMAND_QMLPROPERTY;
-#else
+ << COMMAND_QMLPROPERTY
+ << COMMAND_QMLSIGNAL
+ << COMMAND_QMLMETHOD;
+#else
<< COMMAND_VARIABLE;
-#endif
+#endif
}
/*!
@@ -587,7 +589,7 @@ Node *CppCodeParser::processTopicCommand(const Doc& doc,
The command was neither "fn" nor "macro" .
*/
// ### split(" ") hack is there to support header file syntax
- QStringList paths = arg.split(" ");
+ QStringList paths = arg.split(" ");
QStringList path = paths[0].split("::");
Node *node = 0;
if (!usedNamespaces.isEmpty()) {
@@ -627,49 +629,169 @@ Node *CppCodeParser::processTopicCommand(const Doc& doc,
}
}
+ if (command == COMMAND_CLASS) {
+ if (paths.size() > 1) {
+ if (!paths[1].endsWith(".h")) {
+ ClassNode*cnode = static_cast(node);
+ cnode->setQmlElement(paths[1]);
+ }
+ }
+ }
return node;
}
else if (command == COMMAND_EXAMPLE) {
- FakeNode *fake = new FakeNode(tre->root(), arg, FakeNode::Example);
+ FakeNode *fake = new FakeNode(tre->root(), arg, Node::Example);
createExampleFileNodes(fake);
return fake;
}
else if (command == COMMAND_EXTERNALPAGE) {
- return new FakeNode(tre->root(), arg, FakeNode::ExternalPage);
+ return new FakeNode(tre->root(), arg, Node::ExternalPage);
}
else if (command == COMMAND_FILE) {
- return new FakeNode(tre->root(), arg, FakeNode::File);
+ return new FakeNode(tre->root(), arg, Node::File);
}
else if (command == COMMAND_GROUP) {
- return new FakeNode(tre->root(), arg, FakeNode::Group);
+ return new FakeNode(tre->root(), arg, Node::Group);
}
else if (command == COMMAND_HEADERFILE) {
- return new FakeNode(tre->root(), arg, FakeNode::HeaderFile);
+ return new FakeNode(tre->root(), arg, Node::HeaderFile);
}
else if (command == COMMAND_MODULE) {
- return new FakeNode(tre->root(), arg, FakeNode::Module);
+ return new FakeNode(tre->root(), arg, Node::Module);
}
else if (command == COMMAND_PAGE) {
- return new FakeNode(tre->root(), arg, FakeNode::Page);
+ return new FakeNode(tre->root(), arg, Node::Page);
}
-#ifdef QDOC_QML
+#ifdef QDOC_QML
else if (command == COMMAND_QMLCLASS) {
const ClassNode* classNode = 0;
- QStringList names = arg.split(" ");
- //qDebug() << "QMLCLASS" << names;
+ QStringList names = arg.split(" ");
if (names.size() > 1) {
Node* n = tre->findNode(names[1].split("::"),Node::Class);
- if (n) {
+ if (n)
classNode = static_cast(n);
- //qDebug() << "FOUND IT!" << classNode->name();
+ }
+ return new QmlClassNode(tre->root(), names[0], classNode);
+ }
+ else if ((command == COMMAND_QMLSIGNAL) ||
+ (command == COMMAND_QMLMETHOD)) {
+ QString element;
+ QString name;
+ QmlClassNode* qmlClass = 0;
+ if (splitQmlArg(doc,arg,element,name)) {
+ Node* n = tre->findNode(QStringList(element),Node::Fake);
+ if (n && n->subType() == Node::QmlClass) {
+ qmlClass = static_cast(n);
+ if (command == COMMAND_QMLSIGNAL)
+ return new QmlSignalNode(qmlClass,name);
+ else
+ return new QmlMethodNode(qmlClass,name);
}
}
- return new QmlNode(tre->root(), names[0], classNode);
}
-#endif
+#endif
return 0;
}
+#ifdef QDOC_QML
+
+/*!
+ A QML property argument has the form...
+
+ ::
+
+ This function splits the argument into those three
+ parts, sets \a type, \a element, and \a property,
+ and returns true. If any of the parts isn't found,
+ a debug message is output and false is returned.
+ */
+bool CppCodeParser::splitQmlPropertyArg(const Doc& doc,
+ const QString& arg,
+ QString& type,
+ QString& element,
+ QString& property)
+{
+ QStringList blankSplit = arg.split(" ");
+ if (blankSplit.size() > 1) {
+ type = blankSplit[0];
+ QStringList colonSplit(blankSplit[1].split("::"));
+ if (colonSplit.size() > 1) {
+ element = colonSplit[0];
+ property = colonSplit[1];
+ return true;
+ }
+ else
+ doc.location().warning(tr("Missing QML element name or property name"));
+ }
+ else
+ doc.location().warning(tr("Missing QML property type or property path"));
+ return false;
+}
+
+/*!
+ A QML signal or method argument has the form...
+
+ ::
+
+ This function splits the argument into those two
+ parts, sets \a element, and \a name, and returns
+ true. If either of the parts isn't found, a debug
+ message is output and false is returned.
+ */
+bool CppCodeParser::splitQmlArg(const Doc& doc,
+ const QString& arg,
+ QString& element,
+ QString& name)
+{
+ QStringList colonSplit(arg.split("::"));
+ if (colonSplit.size() > 1) {
+ element = colonSplit[0];
+ name = colonSplit[1];
+ return true;
+ }
+ else
+ doc.location().warning(tr("Missing QML element name or signal/method name"));
+ return false;
+}
+
+/*!
+ Process the topic \a command group with arguments \a args.
+
+ Currently, this function is called only for \e{qmlproperty}.
+ */
+Node *CppCodeParser::processTopicCommandGroup(const Doc& doc,
+ const QString& command,
+ const QStringList& args)
+{
+ QmlPropGroupNode* qmlPropGroup = 0;
+ if (command == COMMAND_QMLPROPERTY) {
+ QString type;
+ QString element;
+ QString property;
+ QStringList::ConstIterator arg = args.begin();
+ if (splitQmlPropertyArg(doc,(*arg),type,element,property)) {
+ Node* n = tre->findNode(QStringList(element),Node::Fake);
+ if (n && n->subType() == Node::QmlClass) {
+ QmlClassNode* qmlClass = static_cast(n);
+ if (qmlClass)
+ qmlPropGroup = new QmlPropGroupNode(qmlClass,property);
+ }
+ }
+ if (qmlPropGroup) {
+ new QmlPropertyNode(qmlPropGroup,property,type);
+ ++arg;
+ while (arg != args.end()) {
+ if (splitQmlPropertyArg(doc,(*arg),type,element,property)) {
+ new QmlPropertyNode(qmlPropGroup,property,type);
+ }
+ ++arg;
+ }
+ }
+ }
+ return qmlPropGroup;
+}
+#endif
+
/*!
Returns the set of strings representing the common metacommands
plus some other metacommands.
@@ -684,7 +806,13 @@ QSet CppCodeParser::otherMetaCommands()
<< COMMAND_NEXTPAGE
<< COMMAND_PREVIOUSPAGE
<< COMMAND_INDEXPAGE
+#ifdef QDOC_QML
+ << COMMAND_STARTPAGE
+ << COMMAND_QMLINHERITS
+ << COMMAND_QMLDEFAULT;
+#else
<< COMMAND_STARTPAGE;
+#endif
}
/*!
@@ -759,14 +887,19 @@ void CppCodeParser::processOtherMetaCommand(const Doc& doc,
else if (command == COMMAND_RELATES) {
InnerNode *pseudoParent;
if (arg.startsWith("<") || arg.startsWith("\"")) {
- pseudoParent = static_cast(tre->findNode(QStringList(arg), Node::Fake));
+ pseudoParent =
+ static_cast(tre->findNode(QStringList(arg),
+ Node::Fake));
}
else {
QStringList newPath = arg.split("::");
- pseudoParent = static_cast(tre->findNode(QStringList(newPath), Node::Class));
+ pseudoParent =
+ static_cast(tre->findNode(QStringList(newPath),
+ Node::Class));
if (!pseudoParent)
- pseudoParent = static_cast(tre->findNode(QStringList(newPath),
- Node::Namespace));
+ pseudoParent =
+ static_cast(tre->findNode(QStringList(newPath),
+ Node::Namespace));
}
if (!pseudoParent) {
doc.location().warning(tr("Cannot find '%1' in '\\%2'")
@@ -791,6 +924,15 @@ void CppCodeParser::processOtherMetaCommand(const Doc& doc,
else if (command == COMMAND_STARTPAGE) {
setLink(node, Node::StartLink, arg);
}
+#ifdef QDOC_QML
+ else if (command == COMMAND_QMLINHERITS) {
+ setLink(node, Node::InheritsLink, arg);
+ }
+ else if (command == COMMAND_QMLDEFAULT) {
+ QmlPropGroupNode* qpgn = static_cast(node);
+ qpgn->setDefault();
+ }
+#endif
else {
processCommonMetaCommand(doc.location(),command,arg,node,tre);
}
@@ -870,9 +1012,8 @@ bool CppCodeParser::match(int target)
readToken();
return true;
}
- else {
+ else
return false;
- }
}
/*!
@@ -907,11 +1048,14 @@ bool CppCodeParser::matchTemplateAngles(CodeChunk *dataType)
do {
if (tok == Tok_LeftAngle) {
leftAngleDepth++;
- } else if (tok == Tok_RightAngle) {
+ }
+ else if (tok == Tok_RightAngle) {
leftAngleDepth--;
- } else if (tok == Tok_LeftParen || tok == Tok_LeftBrace) {
+ }
+ else if (tok == Tok_LeftParen || tok == Tok_LeftBrace) {
++parenAndBraceDepth;
- } else if (tok == Tok_RightParen || tok == Tok_RightBrace) {
+ }
+ else if (tok == Tok_RightParen || tok == Tok_RightBrace) {
if (--parenAndBraceDepth < 0)
return false;
}
@@ -974,7 +1118,8 @@ bool CppCodeParser::matchDataType(CodeChunk *dataType, QString *var)
dataType->append(previousLexeme());
else
return false;
- } else if (match(Tok_int) || match(Tok_char) || match(Tok_double)) {
+ }
+ else if (match(Tok_int) || match(Tok_char) || match(Tok_double)) {
dataType->append(previousLexeme());
}
@@ -1074,8 +1219,10 @@ bool CppCodeParser::matchParameter(FunctionNode *func)
readToken();
}
}
- func->addParameter(Parameter(dataType.toString(), "", name,
- defaultValue.toString())); // ###
+ func->addParameter(Parameter(dataType.toString(),
+ "",
+ name,
+ defaultValue.toString())); // ###
return true;
}
@@ -1123,7 +1270,8 @@ bool CppCodeParser::matchFunctionDecl(InnerNode *parent,
compat = true;
if (tok == Tok_operator &&
- (returnType.toString().isEmpty() || returnType.toString().endsWith("::"))) {
+ (returnType.toString().isEmpty() ||
+ returnType.toString().endsWith("::"))) {
// 'QString::operator const char *()'
parentPath = returnType.toString().split(sep);
parentPath.removeAll(QString());
@@ -1159,11 +1307,10 @@ bool CppCodeParser::matchFunctionDecl(InnerNode *parent,
name = previousLexeme();
matchTemplateAngles();
- if (match(Tok_Gulbrandsen)) {
+ if (match(Tok_Gulbrandsen))
parentPath.append(name);
- } else {
+ else
break;
- }
}
if (tok == Tok_operator) {
@@ -1176,7 +1323,9 @@ bool CppCodeParser::matchFunctionDecl(InnerNode *parent,
break;
}
}
- if (parent && (tok == Tok_Semicolon || tok == Tok_LeftBracket || tok == Tok_Colon)
+ if (parent && (tok == Tok_Semicolon ||
+ tok == Tok_LeftBracket ||
+ tok == Tok_Colon)
&& access != Node::Private) {
if (tok == Tok_LeftBracket) {
returnType.appendHotspot();
@@ -1190,7 +1339,8 @@ bool CppCodeParser::matchFunctionDecl(InnerNode *parent,
}
if (tok != Tok_Semicolon)
return false;
- } else if (tok == Tok_Colon) {
+ }
+ else if (tok == Tok_Colon) {
returnType.appendHotspot();
while (tok != Tok_Semicolon && tok != Tok_Eoi) {
@@ -1382,7 +1532,7 @@ bool CppCodeParser::matchNamespaceDecl(InnerNode *parent)
QString namespaceName = previousLexeme();
NamespaceNode *namespasse = 0;
if (parent)
- namespasse = static_cast(parent->findNode(namespaceName, Node::Namespace));
+ namespasse = static_cast(parent->findNode(namespaceName, Node::Namespace));
if (!namespasse) {
namespasse = new NamespaceNode(parent, namespaceName);
namespasse->setAccess(access);
@@ -1448,7 +1598,8 @@ bool CppCodeParser::matchEnumItem(InnerNode *parent, EnumNode *enume)
if (strVal.isEmpty()) {
if (enume->items().isEmpty()) {
strVal = "0";
- } else {
+ }
+ else {
QString last = enume->items().last().value();
bool ok;
int n = last.toInt(&ok);
@@ -1458,15 +1609,16 @@ bool CppCodeParser::matchEnumItem(InnerNode *parent, EnumNode *enume)
strVal = last.left(2) + QString::number(n + 1, 16);
else
strVal = "0" + QString::number(n + 1, 8);
- } else {
- strVal = QString::number(n + 1);
}
+ else
+ strVal = QString::number(n + 1);
}
}
}
enume->addItem(EnumItem(name, strVal));
- } else {
+ }
+ else {
VariableNode *var = new VariableNode(parent, name);
var->setAccess(access);
var->setLocation(location());
@@ -1554,7 +1706,8 @@ bool CppCodeParser::matchProperty(InnerNode *parent)
if (match(Tok_Ident)) {
value = previousLexeme();
- } else if (match(Tok_LeftParen)) {
+ }
+ else if (match(Tok_LeftParen)) {
int depth = 1;
while (tok != Tok_Eoi) {
if (tok == Tok_LeftParen) {
@@ -1807,6 +1960,28 @@ bool CppCodeParser::matchDocsAndStuff()
/*
There is a topic command. Process it.
*/
+#ifdef QDOC_QML
+ if (topic == COMMAND_QMLPROPERTY) {
+ Doc nodeDoc = doc;
+ Node *node = processTopicCommandGroup(nodeDoc,topic,args);
+ if (node != 0) {
+ nodes.append(node);
+ docs.append(nodeDoc);
+ }
+ }
+ else {
+ QStringList::ConstIterator a = args.begin();
+ while (a != args.end()) {
+ Doc nodeDoc = doc;
+ Node *node = processTopicCommand(nodeDoc,topic,*a);
+ if (node != 0) {
+ nodes.append(node);
+ docs.append(nodeDoc);
+ }
+ ++a;
+ }
+ }
+#else
QStringList::ConstIterator a = args.begin();
while (a != args.end()) {
Doc nodeDoc = doc;
@@ -1817,6 +1992,7 @@ bool CppCodeParser::matchDocsAndStuff()
}
++a;
}
+#endif
}
NodeList::Iterator n = nodes.begin();
@@ -1824,7 +2000,8 @@ bool CppCodeParser::matchDocsAndStuff()
while (n != nodes.end()) {
processOtherMetaCommands(*d, *n);
(*n)->setDoc(*d);
- if ((*n)->isInnerNode() && ((InnerNode *)*n)->includes().isEmpty()) {
+ if ((*n)->isInnerNode() &&
+ ((InnerNode *)*n)->includes().isEmpty()) {
InnerNode *m = static_cast(*n);
while (m->parent() != tre->root())
m = m->parent();
@@ -1912,7 +2089,8 @@ void CppCodeParser::parseQiteratorDotH(const Location &location,
mutableSequentialIteratorDefinition = lines[1];
associativeIteratorDefinition = lines[2];
mutableAssociativeIteratorDefinition = lines[3];
- } else {
+ }
+ else {
location.warning(tr("The qiterator.h hack failed"));
}
}
@@ -1994,7 +2172,7 @@ void CppCodeParser::createExampleFileNodes(FakeNode *fake)
foreach (const QString &exampleFile, exampleFiles)
(void) new FakeNode(fake,
exampleFile.mid(sizeOfBoringPartOfName),
- FakeNode::File);
+ Node::File);
}
QT_END_NAMESPACE
diff --git a/tools/qdoc3/cppcodeparser.h b/tools/qdoc3/cppcodeparser.h
index 1f41318..cbb0149 100644
--- a/tools/qdoc3/cppcodeparser.h
+++ b/tools/qdoc3/cppcodeparser.h
@@ -90,6 +90,21 @@ class CppCodeParser : public CodeParser
virtual Node *processTopicCommand(const Doc& doc,
const QString& command,
const QString& arg);
+#ifdef QDOC_QML
+ // might need to implement this in QsCodeParser as well.
+ virtual Node *processTopicCommandGroup(const Doc& doc,
+ const QString& command,
+ const QStringList& args);
+ bool splitQmlPropertyArg(const Doc& doc,
+ const QString& arg,
+ QString& type,
+ QString& element,
+ QString& property);
+ bool splitQmlArg(const Doc& doc,
+ const QString& arg,
+ QString& element,
+ QString& name);
+#endif
virtual QSet otherMetaCommands();
virtual void processOtherMetaCommand(const Doc& doc,
const QString& command,
diff --git a/tools/qdoc3/generator.cpp b/tools/qdoc3/generator.cpp
index e97b7f2..e92f53b 100644
--- a/tools/qdoc3/generator.cpp
+++ b/tools/qdoc3/generator.cpp
@@ -42,7 +42,7 @@
/*
generator.cpp
*/
-
+#include
#include
#include
#include "codemarker.h"
@@ -77,7 +77,11 @@ static void singularPlural(Text& text, const NodeList& nodes)
}
Generator::Generator()
- : amp("&"), lt("<"), gt(">"), quot("""), tag("?@[^>]*>")
+ : amp("&"),
+ lt("<"),
+ gt(">"),
+ quot("""),
+ tag("?@[^>]*>")
{
generators.prepend(this);
}
@@ -125,7 +129,8 @@ void Generator::initialize(const Config &config)
QSet formats = config.subVars(imagesDotFileExtensions);
QSet::ConstIterator f = formats.begin();
while (f != formats.end()) {
- imgFileExts[*f] = config.getStringList(imagesDotFileExtensions + Config::dot + *f);
+ imgFileExts[*f] = config.getStringList(imagesDotFileExtensions +
+ Config::dot + *f);
++f;
}
@@ -133,16 +138,22 @@ void Generator::initialize(const Config &config)
while (g != generators.end()) {
if (outputFormats.contains((*g)->format())) {
(*g)->initializeGenerator(config);
- QStringList extraImages = config.getStringList(CONFIG_EXTRAIMAGES + Config::dot
- + (*g)->format());
+ QStringList extraImages = config.getStringList(CONFIG_EXTRAIMAGES +
+ Config::dot +
+ (*g)->format());
QStringList::ConstIterator e = extraImages.begin();
while (e != extraImages.end()) {
QString userFriendlyFilePath;
- QString filePath = Config::findFile(config.lastLocation(), imageFiles, imageDirs, *e,
- imgFileExts[(*g)->format()], userFriendlyFilePath);
+ QString filePath = Config::findFile(config.lastLocation(),
+ imageFiles, imageDirs, *e,
+ imgFileExts[(*g)->format()],
+ userFriendlyFilePath);
if (!filePath.isEmpty())
- Config::copyFile(config.lastLocation(), filePath, userFriendlyFilePath,
- (*g)->outputDir() + "/images");
+ Config::copyFile(config.lastLocation(),
+ filePath,
+ userFriendlyFilePath,
+ (*g)->outputDir() +
+ "/images");
++e;
}
}
@@ -158,20 +169,23 @@ void Generator::initialize(const Config &config)
QSet formats = config.subVars(formattingDotName);
QSet::ConstIterator f = formats.begin();
while (f != formats.end()) {
- QString def = config.getString(formattingDotName + Config::dot +
- *f);
+ QString def = config.getString(formattingDotName +
+ Config::dot + *f);
if (!def.isEmpty()) {
int numParams = Config::numParams(def);
int numOccs = def.count("\1");
if (numParams != 1) {
- config.lastLocation().warning(tr("Formatting '%1' must have exactly one"
- " parameter (found %2)")
- .arg(*n).arg(numParams));
+ config.lastLocation().warning(tr("Formatting '%1' must "
+ "have exactly one "
+ "parameter (found %2)")
+ .arg(*n).arg(numParams));
}
else if (numOccs > 1) {
- config.lastLocation().fatal(tr("Formatting '%1' must contain exactly one"
- " occurrence of '\\1' (found %2)")
+ config.lastLocation().fatal(tr("Formatting '%1' must "
+ "contain exactly one "
+ "occurrence of '\\1' "
+ "(found %2)")
.arg(*n).arg(numOccs));
}
else {
@@ -262,9 +276,14 @@ bool Generator::generateText(const Text& text,
}
#ifdef QDOC_QML
+/*!
+ Extract sections of markup text surrounded by \e qmltext
+ and \e endqmltext and output them.
+ */
bool Generator::generateQmlText(const Text& text,
const Node *relative,
- CodeMarker *marker)
+ CodeMarker *marker,
+ const QString& qmlName)
{
const Atom* atom = text.firstAtom();
if (atom == 0)
@@ -301,9 +320,9 @@ void Generator::generateBody(const Node *node, CodeMarker *marker)
}
else if (node->type() == Node::Fake) {
const FakeNode *fake = static_cast(node);
- if (fake->subType() == FakeNode::Example)
+ if (fake->subType() == Node::Example)
generateExampleFiles(fake, marker);
- else if (fake->subType() == FakeNode::File)
+ else if (fake->subType() == Node::File)
quiet = true;
}
@@ -395,7 +414,8 @@ void Generator::generateBody(const Node *node, CodeMarker *marker)
FunctionNode *primaryFunc =
func->parent()->findFunctionNode(func->name());
if (primaryFunc) {
- foreach (const Parameter ¶m, primaryFunc->parameters()) {
+ foreach (const Parameter ¶m,
+ primaryFunc->parameters()) {
if (param.name() == *a) {
needWarning = false;
break;
@@ -405,7 +425,8 @@ void Generator::generateBody(const Node *node, CodeMarker *marker)
}
if (needWarning && !func->isReimp())
node->doc().location().warning(
- tr("Undocumented parameter '%1' in %2").arg(*a).arg(marker->plainFullName(node)));
+ tr("Undocumented parameter '%1' in %2")
+ .arg(*a).arg(marker->plainFullName(node)));
}
++a;
}
@@ -427,7 +448,7 @@ void Generator::generateBody(const Node *node, CodeMarker *marker)
if (node->type() == Node::Fake) {
const FakeNode *fake = static_cast(node);
- if (fake->subType() == FakeNode::File) {
+ if (fake->subType() == Node::File) {
Text text;
Quoter quoter;
Doc::quoteFromFile(fake->doc().location(), quoter, fake->name());
@@ -474,7 +495,8 @@ void Generator::generateInherits(const ClassNode *classe, CodeMarker *marker)
if ((*r).access == Node::Protected) {
text << " (protected)";
- } else if ((*r).access == Node::Private) {
+ }
+ else if ((*r).access == Node::Private) {
text << " (private)";
}
text << separator(index++, classe->baseClasses().count());
@@ -485,6 +507,15 @@ void Generator::generateInherits(const ClassNode *classe, CodeMarker *marker)
}
}
+#ifdef QDOC_QML
+/*!
+ */
+void Generator::generateQmlInherits(const QmlClassNode* , CodeMarker* )
+{
+ // stub.
+}
+#endif
+
void Generator::generateInheritedBy(const ClassNode *classe,
CodeMarker *marker)
{
@@ -512,18 +543,21 @@ void Generator::generateExampleFiles(const FakeNode *fake, CodeMarker *marker)
QString exampleFile = child->name();
openedList.next();
text << Atom(Atom::ListItemNumber, openedList.numberString())
- << Atom(Atom::ListItemLeft, openedList.styleString()) << Atom::ParaLeft
+ << Atom(Atom::ListItemLeft, openedList.styleString())
+ << Atom::ParaLeft
<< Atom(Atom::Link, exampleFile)
<< Atom(Atom::FormattingLeft, ATOM_FORMATTING_LINK)
<< exampleFile
<< Atom(Atom::FormattingRight, ATOM_FORMATTING_LINK)
- << Atom::ParaRight << Atom(Atom::ListItemRight, openedList.styleString());
+ << Atom::ParaRight
+ << Atom(Atom::ListItemRight, openedList.styleString());
}
text << Atom(Atom::ListRight, openedList.styleString());
generateText(text, fake, marker);
}
-void Generator::generateModuleWarning(const ClassNode *classe, CodeMarker *marker)
+void Generator::generateModuleWarning(const ClassNode *classe,
+ CodeMarker *marker)
{
QString module = classe->moduleName();
if (!module.isEmpty()) {
@@ -544,8 +578,10 @@ void Generator::generateModuleWarning(const ClassNode *classe, CodeMarker *marke
<< Atom(Atom::FormattingRight, ATOM_FORMATTING_BOLD)
<< Atom::ParaRight;
}
- else if (module == "Qt3Support" && Tokenizer::isTrue("defined(opensourceedition)")) {
- text << Atom::ParaLeft << Atom(Atom::FormattingLeft, ATOM_FORMATTING_BOLD)
+ else if (module == "Qt3Support" &&
+ Tokenizer::isTrue("defined(opensourceedition)")) {
+ text << Atom::ParaLeft
+ << Atom(Atom::FormattingLeft, ATOM_FORMATTING_BOLD)
<< "Note to Qt Desktop Light Edition users:"
<< Atom(Atom::FormattingRight, ATOM_FORMATTING_BOLD)
<< " This class is only available in the "
@@ -573,10 +609,12 @@ QString Generator::indent(int level, const QString& markedCode)
if (markedCode.at(i - 1) == QLatin1Char('>'))
break;
}
- } else {
+ }
+ else {
if (markedCode.at(i) == QLatin1Char('\n')) {
column = 0;
- } else {
+ }
+ else {
if (column == 0) {
for (int j = 0; j < level; j++)
t += QLatin1Char(' ');
@@ -645,7 +683,7 @@ void Generator::setImageFileExtensions(const QStringList& extensions)
void Generator::unknownAtom(const Atom *atom)
{
Location::internalError(tr("unknown atom type '%1' in %2 generator")
- .arg(atom->typeString()).arg(format()));
+ .arg(atom->typeString()).arg(format()));
}
bool Generator::matchAhead(const Atom *atom, Atom::Type expectedAtomType)
@@ -674,7 +712,8 @@ void Generator::supplementAlsoList(const Node *node, QList &alsoList)
alternateFunc = func->parent()->findFunctionNode(alternateName);
}
}
- } else if (!func->name().isEmpty()) {
+ }
+ else if (!func->name().isEmpty()) {
alternateName = "set";
alternateName += func->name()[0].toUpper();
alternateName += func->name().mid(1);
@@ -730,9 +769,13 @@ void Generator::generateStatus(const Node *node, CodeMarker *marker)
case Node::Main:
break;
case Node::Preliminary:
- text << Atom::ParaLeft << Atom(Atom::FormattingLeft, ATOM_FORMATTING_BOLD) << "This "
- << typeString(node) << " is under development and is subject to change."
- << Atom(Atom::FormattingRight, ATOM_FORMATTING_BOLD) << Atom::ParaRight;
+ text << Atom::ParaLeft
+ << Atom(Atom::FormattingLeft, ATOM_FORMATTING_BOLD)
+ << "This "
+ << typeString(node)
+ << " is under development and is subject to change."
+ << Atom(Atom::FormattingRight, ATOM_FORMATTING_BOLD)
+ << Atom::ParaRight;
break;
case Node::Deprecated:
text << Atom::ParaLeft;
@@ -750,16 +793,21 @@ void Generator::generateStatus(const Node *node, CodeMarker *marker)
text << "This " << typeString(node) << " is obsolete.";
if (node->isInnerNode())
text << Atom(Atom::FormattingRight, ATOM_FORMATTING_BOLD);
- text << " It is provided to keep old source code working. We strongly advise against "
+ text << " It is provided to keep old source code working. "
+ << "We strongly advise against "
<< "using it in new code." << Atom::ParaRight;
break;
case Node::Compat:
// reimplemented in HtmlGenerator subclass
if (node->isInnerNode()) {
- text << Atom::ParaLeft << Atom(Atom::FormattingLeft, ATOM_FORMATTING_BOLD) << "This "
- << typeString(node) << " is part of the Qt 3 compatibility layer."
+ text << Atom::ParaLeft
+ << Atom(Atom::FormattingLeft, ATOM_FORMATTING_BOLD)
+ << "This "
+ << typeString(node)
+ << " is part of the Qt 3 compatibility layer."
<< Atom(Atom::FormattingRight, ATOM_FORMATTING_BOLD)
- << " It is provided to keep old source code working. We strongly advise against "
+ << " It is provided to keep old source code working. "
+ << "We strongly advise against "
<< "using it in new code. See "
<< Atom(Atom::AutoLink, "Porting to Qt 4")
<< " for more information."
@@ -915,7 +963,9 @@ void Generator::generateSince(const Node *node, CodeMarker *marker)
{
if (!node->since().isEmpty()) {
Text text;
- text << Atom::ParaLeft << "This " << typeString(node)
+ text << Atom::ParaLeft
+ << "This "
+ << typeString(node)
<< " was introduced in ";
if (project.isEmpty())
text << "version";
@@ -945,7 +995,8 @@ void Generator::generateReimplementedFrom(const FunctionNode *func,
{
if (func->reimplementedFrom() != 0) {
const FunctionNode *from = func->reimplementedFrom();
- if (from->access() != Node::Private && from->parent()->access() != Node::Private) {
+ if (from->access() != Node::Private &&
+ from->parent()->access() != Node::Private) {
Text text;
text << Atom::ParaLeft << "Reimplemented from ";
QString fullName = from->parent()->name() + "::" + from->name() + "()";
@@ -987,8 +1038,8 @@ const Atom *Generator::generateAtomList(const Atom *atom,
if (atom->type() == Atom::FormatEndif) {
if (generate && numAtoms0 == numAtoms) {
- relative->location().warning(tr("Output format %1 not handled").
- arg(format()));
+ relative->location().warning(tr("Output format %1 not handled")
+ .arg(format()));
Atom unhandledFormatAtom(Atom::UnhandledFormat, format());
generateAtomList(&unhandledFormatAtom,
relative,
@@ -999,7 +1050,8 @@ const Atom *Generator::generateAtomList(const Atom *atom,
atom = atom->next();
}
}
- else if (atom->type() == Atom::FormatElse || atom->type() == Atom::FormatEndif) {
+ else if (atom->type() == Atom::FormatElse ||
+ atom->type() == Atom::FormatEndif) {
return atom;
}
else {
@@ -1067,7 +1119,8 @@ void Generator::appendSortedNames(Text& text,
r = classes.begin();
while (r != classes.end()) {
- if ((*r).node->access() == Node::Public && (*r).node->status() != Node::Internal
+ if ((*r).node->access() == Node::Public &&
+ (*r).node->status() != Node::Internal
&& !(*r).node->doc().isEmpty()) {
Text className;
appendFullName(className, (*r).node, classe, marker);
diff --git a/tools/qdoc3/generator.h b/tools/qdoc3/generator.h
index cdc4c29..8e3c57e 100644
--- a/tools/qdoc3/generator.h
+++ b/tools/qdoc3/generator.h
@@ -99,7 +99,10 @@ class Generator
#ifdef QDOC_QML
virtual bool generateQmlText(const Text& text,
const Node *relative,
- CodeMarker *marker);
+ CodeMarker *marker,
+ const QString& qmlName);
+ virtual void generateQmlInherits(const QmlClassNode* cn,
+ CodeMarker* marker);
#endif
virtual void generateBody(const Node *node, CodeMarker *marker);
virtual void generateAlsoList(const Node *node, CodeMarker *marker);
diff --git a/tools/qdoc3/helpprojectwriter.cpp b/tools/qdoc3/helpprojectwriter.cpp
index cf7c618..f862e55 100644
--- a/tools/qdoc3/helpprojectwriter.cpp
+++ b/tools/qdoc3/helpprojectwriter.cpp
@@ -118,16 +118,19 @@ void HelpProjectWriter::readSelectors(SubProject &subproject, const QStringList
typeHash["variable"] = Node::Variable;
typeHash["target"] = Node::Target;
- QHash subTypeHash;
- subTypeHash["example"] = FakeNode::Example;
- subTypeHash["headerfile"] = FakeNode::HeaderFile;
- subTypeHash["file"] = FakeNode::File;
- subTypeHash["group"] = FakeNode::Group;
- subTypeHash["module"] = FakeNode::Module;
- subTypeHash["page"] = FakeNode::Page;
- subTypeHash["externalpage"] = FakeNode::ExternalPage;
-
- QSet allSubTypes = QSet::fromList(subTypeHash.values());
+ QHash subTypeHash;
+ subTypeHash["example"] = Node::Example;
+ subTypeHash["headerfile"] = Node::HeaderFile;
+ subTypeHash["file"] = Node::File;
+ subTypeHash["group"] = Node::Group;
+ subTypeHash["module"] = Node::Module;
+ subTypeHash["page"] = Node::Page;
+ subTypeHash["externalpage"] = Node::ExternalPage;
+#ifdef QDOC_QML
+ subTypeHash["qmlclass"] = Node::QmlClass;
+#endif
+
+ QSet allSubTypes = QSet::fromList(subTypeHash.values());
foreach (const QString &selector, selectors) {
QStringList pieces = selector.split(":");
@@ -139,7 +142,7 @@ void HelpProjectWriter::readSelectors(SubProject &subproject, const QStringList
QString lower = pieces[0].toLower();
pieces = pieces[1].split(",");
if (typeHash.contains(lower)) {
- QSet subTypes;
+ QSet subTypes;
for (int i = 0; i < pieces.size(); ++i) {
QString lower = pieces[i].toLower();
if (subTypeHash.contains(lower))
@@ -235,7 +238,7 @@ bool HelpProjectWriter::generateSection(HelpProject &project,
// mask.
const FakeNode *fakeNode = static_cast(node);
if (subproject.selectors[node->type()].contains(fakeNode->subType()) &&
- fakeNode->subType() != FakeNode::ExternalPage &&
+ fakeNode->subType() != Node::ExternalPage &&
!fakeNode->fullTitle().isEmpty())
project.subprojects[name].nodes[objName] = node;
@@ -324,10 +327,10 @@ bool HelpProjectWriter::generateSection(HelpProject &project,
// attributes.
case Node::Fake: {
const FakeNode *fakeNode = static_cast(node);
- if (fakeNode->subType() != FakeNode::ExternalPage &&
+ if (fakeNode->subType() != Node::ExternalPage &&
!fakeNode->fullTitle().isEmpty()) {
- if (fakeNode->subType() != FakeNode::File) {
+ if (fakeNode->subType() != Node::File) {
if (fakeNode->doc().hasKeywords()) {
foreach (const Atom *keyword, fakeNode->doc().keywords()) {
if (!keyword->string().isEmpty()) {
@@ -485,7 +488,7 @@ void HelpProjectWriter::writeNode(HelpProject &project, QXmlStreamWriter &writer
writer.writeAttribute("title", fakeNode->fullTitle());
// qDebug() << "Title:" << fakeNode->fullTitle();
- if (fakeNode->subType() == FakeNode::HeaderFile) {
+ if (fakeNode->subType() == Node::HeaderFile) {
// Write subsections for all members, obsolete members and Qt 3
// members.
@@ -609,7 +612,7 @@ void HelpProjectWriter::generateProject(HelpProject &project)
while (nextPage) {
writeNode(project, writer, nextPage);
nextTitle = nextPage->links().value(Node::NextLink).first;
- if (nextTitle.isEmpty())
+ if(nextTitle.isEmpty())
break;
nextPage = const_cast(tree->findFakeNodeByTitle(nextTitle));
}
diff --git a/tools/qdoc3/htmlgenerator.cpp b/tools/qdoc3/htmlgenerator.cpp
index f92391e..b1f8167 100644
--- a/tools/qdoc3/htmlgenerator.cpp
+++ b/tools/qdoc3/htmlgenerator.cpp
@@ -223,11 +223,21 @@ void HtmlGenerator::initializeGenerator(const Config &config)
i++;
}
- style = config.getString(HtmlGenerator::format() + Config::dot + HTMLGENERATOR_STYLE);
- postHeader = config.getString(HtmlGenerator::format() + Config::dot + HTMLGENERATOR_POSTHEADER);
- footer = config.getString(HtmlGenerator::format() + Config::dot + HTMLGENERATOR_FOOTER);
- address = config.getString(HtmlGenerator::format() + Config::dot + HTMLGENERATOR_ADDRESS);
- pleaseGenerateMacRef = config.getBool(HtmlGenerator::format() + Config::dot + HTMLGENERATOR_GENERATEMACREFS);
+ style = config.getString(HtmlGenerator::format() +
+ Config::dot +
+ HTMLGENERATOR_STYLE);
+ postHeader = config.getString(HtmlGenerator::format() +
+ Config::dot +
+ HTMLGENERATOR_POSTHEADER);
+ footer = config.getString(HtmlGenerator::format() +
+ Config::dot +
+ HTMLGENERATOR_FOOTER);
+ address = config.getString(HtmlGenerator::format() +
+ Config::dot +
+ HTMLGENERATOR_ADDRESS);
+ pleaseGenerateMacRef = config.getBool(HtmlGenerator::format() +
+ Config::dot +
+ HTMLGENERATOR_GENERATEMACREFS);
project = config.getString(CONFIG_PROJECT);
@@ -241,10 +251,16 @@ void HtmlGenerator::initializeGenerator(const Config &config)
QSet::ConstIterator edition = editionNames.begin();
while (edition != editionNames.end()) {
QString editionName = *edition;
- QStringList editionModules = config.getStringList(
- CONFIG_EDITION + Config::dot + editionName + Config::dot + "modules");
- QStringList editionGroups = config.getStringList(
- CONFIG_EDITION + Config::dot + editionName + Config::dot + "groups");
+ QStringList editionModules = config.getStringList(CONFIG_EDITION +
+ Config::dot +
+ editionName +
+ Config::dot +
+ "modules");
+ QStringList editionGroups = config.getStringList(CONFIG_EDITION +
+ Config::dot +
+ editionName +
+ Config::dot +
+ "groups");
if (!editionModules.isEmpty())
editionModuleMap[editionName] = editionModules;
@@ -256,11 +272,17 @@ void HtmlGenerator::initializeGenerator(const Config &config)
slow = config.getBool(CONFIG_SLOW);
- stylesheets = config.getStringList(HtmlGenerator::format() + Config::dot + HTMLGENERATOR_STYLESHEETS);
- customHeadElements = config.getStringList(HtmlGenerator::format() + Config::dot + HTMLGENERATOR_CUSTOMHEADELEMENTS);
+ stylesheets = config.getStringList(HtmlGenerator::format() +
+ Config::dot +
+ HTMLGENERATOR_STYLESHEETS);
+ customHeadElements = config.getStringList(HtmlGenerator::format() +
+ Config::dot +
+ HTMLGENERATOR_CUSTOMHEADELEMENTS);
codeIndent = config.getInt(CONFIG_CODEINDENT);
- helpProjectWriter = new HelpProjectWriter(config, project.toLower() + ".qhp");
+ helpProjectWriter = new HelpProjectWriter(config,
+ project.toLower() +
+ ".qhp");
}
void HtmlGenerator::terminateGenerator()
@@ -304,9 +326,9 @@ void HtmlGenerator::generateTree(const Tree *tree, CodeMarker *marker)
findAllFunctions(tree->root());
findAllLegaleseTexts(tree->root());
findAllNamespaces(tree->root());
-#ifdef ZZZ_QDOC_QML
+#ifdef ZZZ_QDOC_QML
findAllQmlClasses(tree->root());
-#endif
+#endif
PageGenerator::generateTree(tree, marker);
@@ -410,7 +432,8 @@ int HtmlGenerator::generateAtom(const Atom *atom,
QString str;
atom = atom->next();
while (atom != 0 && atom->type() != Atom::BriefRight) {
- if (atom->type() == Atom::String || atom->type() == Atom::AutoLink)
+ if (atom->type() == Atom::String ||
+ atom->type() == Atom::AutoLink)
str += atom->string();
skipAhead++;
atom = atom->next();
@@ -453,14 +476,14 @@ int HtmlGenerator::generateAtom(const Atom *atom,
marker,relative))
<< "\n";
break;
-#ifdef QDOC_QML
+#ifdef QDOC_QML
case Atom::Qml:
out() << ""
<< trimmedTrailing(highlightedCode(indent(codeIndent,atom->string()),
marker,relative))
<< "
\n";
break;
-#endif
+#endif
case Atom::CodeNew:
out() << "you can rewrite it as
\n"
<< ""
@@ -976,7 +999,7 @@ int HtmlGenerator::generateAtom(const Atom *atom,
case Atom::EndQmlText:
// don't do anything with these. They are just tags.
break;
-#endif
+#endif
default:
unknownAtom(atom);
}
@@ -1042,6 +1065,12 @@ void HtmlGenerator::generateClassLikeNode(const InnerNode *inner,
generateHeader(title, inner, marker, true);
generateTitle(title, subtitleText, SmallSubTitle, inner, marker);
+#ifdef QDOC_QML
+ if (classe && !classe->qmlElement().isEmpty()) {
+ generateInstantiatedBy(classe,marker);
+ }
+#endif
+
generateBrief(inner, marker);
generateIncludes(inner, marker);
generateStatus(inner, marker);
@@ -1225,16 +1254,19 @@ void HtmlGenerator::generateFakeNode(const FakeNode *fake, CodeMarker *marker)
QList::const_iterator s;
QString htmlTitle = fake->fullTitle();
- if (fake->subType() == FakeNode::File && !fake->subTitle().isEmpty()) {
+ if (fake->subType() == Node::File && !fake->subTitle().isEmpty()) {
subTitleSize = SmallSubTitle;
htmlTitle += " (" + fake->subTitle() + ")";
}
generateHeader(htmlTitle, fake, marker, true);
- generateTitle(fake->fullTitle(), Text() << fake->subTitle(), subTitleSize,
- fake, marker);
+ generateTitle(fake->fullTitle(),
+ Text() << fake->subTitle(),
+ subTitleSize,
+ fake,
+ marker);
- if (fake->subType() == FakeNode::Module) {
+ if (fake->subType() == Node::Module) {
// Generate brief text and status for modules.
generateBrief(fake, marker);
generateStatus(fake, marker);
@@ -1248,7 +1280,7 @@ void HtmlGenerator::generateFakeNode(const FakeNode *fake, CodeMarker *marker)
generateAnnotatedList(fake, marker, moduleClassMap[fake->name()]);
}
}
- else if (fake->subType() == FakeNode::HeaderFile) {
+ else if (fake->subType() == Node::HeaderFile) {
// Generate brief text and status for modules.
generateBrief(fake, marker);
generateStatus(fake, marker);
@@ -1295,7 +1327,49 @@ void HtmlGenerator::generateFakeNode(const FakeNode *fake, CodeMarker *marker)
appendDcfSubSection(&fakeSection, compatSection);
}
}
+#ifdef QDOC_QML
+ else if (fake->subType() == Node::QmlClass) {
+ const QmlClassNode* qml_cn = static_cast(fake);
+ const ClassNode* cn = qml_cn->classNode();
+ generateQmlInherits(qml_cn, marker);
+ generateQmlInstantiates(qml_cn, marker);
+ generateBrief(qml_cn, marker);
+ sections = marker->qmlSections(qml_cn,CodeMarker::Summary);
+ s = sections.begin();
+ while (s != sections.end()) {
+ out() << "\n";
+ out() << "" << protect((*s).name) << "
\n";
+ generateQmlSummary(*s,fake,marker);
+ ++s;
+ }
+ out() << "\n";
+ out() << "" << "Detailed Description" << "
\n";
+ generateBody(fake, marker);
+ if (cn)
+ generateQmlText(cn->doc().body(), cn, marker, fake->name());
+ generateAlsoList(fake, marker);
+ out() << "
\n";
+
+ sections = marker->qmlSections(qml_cn,CodeMarker::Detailed);
+ s = sections.begin();
+ while (s != sections.end()) {
+ out() << "" << protect((*s).name) << "
\n";
+ NodeList::ConstIterator m = (*s).members.begin();
+ while (m != (*s).members.end()) {
+ generateDetailedQmlMember(*m, fake, marker);
+ out() << "
\n";
+ fakeSection.keywords += qMakePair((*m)->name(),
+ linkForNode(*m,0));
+ ++m;
+ }
+ ++s;
+ }
+ generateFooter(fake);
+ return;
+ }
+#endif
+
sections = marker->sections(fake, CodeMarker::Summary, CodeMarker::Okay);
s = sections.begin();
while (s != sections.end()) {
@@ -1306,24 +1380,12 @@ void HtmlGenerator::generateFakeNode(const FakeNode *fake, CodeMarker *marker)
}
Text brief = fake->doc().briefText();
- if (fake->subType() == FakeNode::Module && !brief.isEmpty()) {
+ if (fake->subType() == Node::Module && !brief.isEmpty()) {
out() << "\n";
out() << "" << "Detailed Description" << "
\n";
}
generateBody(fake, marker);
-#ifdef QDOC_QML
- if (fake->subType() == FakeNode::QmlClass) {
- //qDebug() << "generateFakeNode(): QML CLASS" << fake->name();
- const QmlNode* qmlNode = static_cast(fake);
- const ClassNode* cn = qmlNode->classNode();
- if (cn) {
- //qDebug() << " CPP CLASS" << cn->name();
- generateQmlText(cn->doc().body(), cn, marker);
- }
- }
-#endif
-
generateAlsoList(fake, marker);
if (!fake->groupMembers().isEmpty()) {
@@ -1353,10 +1415,10 @@ void HtmlGenerator::generateFakeNode(const FakeNode *fake, CodeMarker *marker)
}
generateFooter(fake);
- if (fake->subType() == FakeNode::Example) {
+ if (fake->subType() == Node::Example) {
appendDcfSubSection(&dcfExamplesRoot, fakeSection);
}
- else if (fake->subType() != FakeNode::File) {
+ else if (fake->subType() != Node::File) {
QString contentsPage = fake->links().value(Node::ContentsLink).first;
if (contentsPage == "Qt Designer Manual") {
@@ -1643,7 +1705,10 @@ void HtmlGenerator::generateTableOfContents(const Node *node,
columnSize = 0;
}
out() << "";
- out() << "";
generateAtomList(headingText.firstAtom(), node, marker, true, numAtoms);
out() << "\n";
@@ -1693,7 +1758,8 @@ void HtmlGenerator::generateNavigationBar(const NavigationBar& bar,
}
#endif
-QString HtmlGenerator::generateListOfAllMemberFile(const InnerNode *inner, CodeMarker *marker)
+QString HtmlGenerator::generateListOfAllMemberFile(const InnerNode *inner,
+ CodeMarker *marker)
{
QList sections;
QList::ConstIterator s;
@@ -1744,7 +1810,8 @@ QString HtmlGenerator::generateLowStatusMemberFile(const InnerNode *inner,
if (status == CodeMarker::Compat) {
title = "Qt 3 Support Members for " + inner->name();
fileName = fileBase(inner) + "-qt3." + fileExtension(inner);
- } else {
+ }
+ else {
title = "Obsolete Members for " + inner->name();
fileName = fileBase(inner) + "-obsolete." + fileExtension(inner);
}
@@ -1758,10 +1825,11 @@ QString HtmlGenerator::generateLowStatusMemberFile(const InnerNode *inner,
"Qt 3 support layer. "
"They are provided to help you port old code to Qt 4. We advise against "
"using them in new code.
\n";
- } else {
- out() << "The following class members are obsolete. They are provided to keep "
- "old source code working. We strongly advise against using them in new "
- "code.
\n";
+ }
+ else {
+ out() << "The following class members are obsolete. "
+ << "They are provided to keep old source code working. "
+ << "We strongly advise against using them in new code.
\n";
}
out() << "- \n";
- } else {
- const ClassNode *child = static_cast(*stack.top().begin());
+ }
+ else {
+ const ClassNode *child =
+ static_cast(*stack.top().begin());
out() << "
- ";
generateFullName(child, relative, marker);
out() << "
\n";
@@ -1836,10 +1906,9 @@ void HtmlGenerator::generateClassHierarchy(const Node *relative,
}
}
-void
-HtmlGenerator::generateAnnotatedList(const Node *relative,
- CodeMarker *marker,
- const QMap&nodeMap)
+void HtmlGenerator::generateAnnotatedList(const Node *relative,
+ CodeMarker *marker,
+ const QMap &nodeMap)
{
out() << "\n";
@@ -1866,7 +1935,8 @@ HtmlGenerator::generateAnnotatedList(const Node *relative,
generateText(brief, node, marker);
out() << "";
}
- } else {
+ }
+ else {
out() << "";
out() << protect(node->doc().briefText().toString());
out() << " | ";
@@ -1876,10 +1946,9 @@ HtmlGenerator::generateAnnotatedList(const Node *relative,
out() << "
\n";
}
-void
-HtmlGenerator::generateCompactList(const Node *relative,
- CodeMarker *marker,
- const QMap &classMap)
+void HtmlGenerator::generateCompactList(const Node *relative,
+ CodeMarker *marker,
+ const QMap &classMap)
{
const int NumParagraphs = 37; // '0' to '9', 'A' to 'Z', '_'
const int NumColumns = 4; // number of columns in the result
@@ -1922,8 +1991,9 @@ HtmlGenerator::generateCompactList(const Node *relative,
last = classMap.begin().key();
if (classMap.size() > 1) {
- while (commonPrefixLen < first.length() + 1 && commonPrefixLen < last.length() + 1
- && first[commonPrefixLen] == last[commonPrefixLen])
+ while (commonPrefixLen < first.length() + 1 &&
+ commonPrefixLen < last.length() + 1 &&
+ first[commonPrefixLen] == last[commonPrefixLen])
++commonPrefixLen;
}
@@ -1952,7 +2022,8 @@ HtmlGenerator::generateCompactList(const Node *relative,
if (key[0].digitValue() != -1) {
paragraphNo = key[0].digitValue();
- } else if (key[0] >= QLatin1Char('a') && key[0] <= QLatin1Char('z')) {
+ }
+ else if (key[0] >= QLatin1Char('a') && key[0] <= QLatin1Char('z')) {
paragraphNo = 10 + key[0].unicode() - 'a';
}
@@ -2105,7 +2176,8 @@ void HtmlGenerator::generateFunctionIndex(const Node *relative,
#endif
}
-void HtmlGenerator::generateLegaleseList(const Node *relative, CodeMarker *marker)
+void HtmlGenerator::generateLegaleseList(const Node *relative,
+ CodeMarker *marker)
{
QMap::ConstIterator it = legaleseTexts.begin();
while (it != legaleseTexts.end()) {
@@ -2123,6 +2195,77 @@ void HtmlGenerator::generateLegaleseList(const Node *relative, CodeMarker *marke
}
}
+/*void HtmlGenerator::generateSynopsis(const Node *node,
+ const Node *relative,
+ CodeMarker *marker,
+ CodeMarker::SynopsisStyle style)
+{
+ QString marked = marker->markedUpSynopsis(node, relative, style);
+ QRegExp templateTag("(<[^@>]*>)");
+ if (marked.indexOf(templateTag) != -1) {
+ QString contents = protect(marked.mid(templateTag.pos(1),
+ templateTag.cap(1).length()));
+ marked.replace(templateTag.pos(1), templateTag.cap(1).length(),
+ contents);
+ }
+ marked.replace(QRegExp("<@param>([a-z]+)_([1-9n])@param>"),
+ "\\1\\2");
+ marked.replace("<@param>", "");
+ marked.replace("@param>", "");
+
+ if (style == CodeMarker::Summary)
+ marked.replace("@name>", "b>");
+
+ if (style == CodeMarker::SeparateList) {
+ QRegExp extraRegExp("<@extra>.*@extra>");
+ extraRegExp.setMinimal(true);
+ marked.replace(extraRegExp, "");
+ }
+ else {
+ marked.replace("<@extra>", " ");
+ marked.replace("@extra>", "");
+ }
+
+ if (style != CodeMarker::Detailed) {
+ marked.replace("<@type>", "");
+ marked.replace("@type>", "");
+ }
+ out() << highlightedCode(marked, marker, relative);
+}*/
+
+#ifdef QDOC_QML
+void HtmlGenerator::generateQmlItem(const Node *node,
+ const Node *relative,
+ CodeMarker *marker,
+ bool summary)
+{
+ QString marked = marker->markedUpQmlItem(node,summary);
+ QRegExp templateTag("(<[^@>]*>)");
+ if (marked.indexOf(templateTag) != -1) {
+ QString contents = protect(marked.mid(templateTag.pos(1),
+ templateTag.cap(1).length()));
+ marked.replace(templateTag.pos(1), templateTag.cap(1).length(),
+ contents);
+ }
+ marked.replace(QRegExp("<@param>([a-z]+)_([1-9n])@param>"),
+ "\\1\\2");
+ marked.replace("<@param>", "");
+ marked.replace("@param>", "");
+
+ if (summary)
+ marked.replace("@name>", "b>");
+
+ marked.replace("<@extra>", " ");
+ marked.replace("@extra>", "");
+
+ if (summary) {
+ marked.replace("<@type>", "");
+ marked.replace("@type>", "");
+ }
+ out() << highlightedCode(marked, marker, relative);
+}
+#endif
+
void HtmlGenerator::generateOverviewList(const Node *relative, CodeMarker * /* marker */)
{
QMap > fakeNodeMap;
@@ -2145,7 +2288,7 @@ void HtmlGenerator::generateOverviewList(const Node *relative, CodeMarker * /* m
}
// there are too many examples; they would clutter the list
- if (fakeNode->subType() == FakeNode::Example)
+ if (fakeNode->subType() == Node::Example)
continue;
// not interested either in individual (Qt Designer etc.) manual chapters
@@ -2153,7 +2296,7 @@ void HtmlGenerator::generateOverviewList(const Node *relative, CodeMarker * /* m
continue;
// Discard external nodes.
- if (fakeNode->subType() == FakeNode::ExternalPage)
+ if (fakeNode->subType() == Node::ExternalPage)
continue;
QString sortKey = fakeNode->fullTitle().toLower();
@@ -2178,7 +2321,8 @@ void HtmlGenerator::generateOverviewList(const Node *relative, CodeMarker * /* m
groupTitlesMap[fakeNode->fullTitle()] = const_cast(fakeNode);
}
}
- } else if (!isGroupPage) {
+ }
+ else if (!isGroupPage) {
// If we encounter a page that belongs to a group then
// we add that page to the list for that group.
const FakeNode *groupNode = static_cast(tre->root()->findNode(group, Node::Fake));
@@ -2737,8 +2881,8 @@ QString HtmlGenerator::highlightedCode(const QString& markedCode,
if (src.at(i) == charLangle && src.at(i + 1) == charAt) {
i += 2;
if (parseArg(src, linkTag, &i, n, &arg, &par1)) {
- QString link = linkForNode(
- CodeMarker::nodeForString(par1.toString()), relative);
+ const Node* node = CodeMarker::nodeForString(par1.toString());
+ QString link = linkForNode(node, relative);
addLink(link, arg, &html);
}
else {
@@ -2751,7 +2895,6 @@ QString HtmlGenerator::highlightedCode(const QString& markedCode,
}
}
-
if (slow) {
// is this block ever used at all?
// replace all <@func> tags: "(<@func target=\"([^\"]*)\">)(.*)(@func>)"
@@ -3076,10 +3219,9 @@ QString HtmlGenerator::fileBase(const Node *node,
QString HtmlGenerator::fileName(const Node *node)
{
if (node->type() == Node::Fake) {
- if (static_cast(node)->subType() == FakeNode::ExternalPage)
+ if (static_cast(node)->subType() == Node::ExternalPage)
return node->name();
}
-
return PageGenerator::fileName(node);
}
@@ -3101,7 +3243,8 @@ QString HtmlGenerator::refForNode(const Node *node)
typedeffe = static_cast(node);
if (typedeffe->associatedEnum()) {
return refForNode(typedeffe->associatedEnum());
- } else {
+ }
+ else {
ref = node->name() + "-typedef";
}
break;
@@ -3109,15 +3252,27 @@ QString HtmlGenerator::refForNode(const Node *node)
func = static_cast(node);
if (func->associatedProperty()) {
return refForNode(func->associatedProperty());
- } else {
+ }
+ else {
ref = func->name();
if (func->overloadNumber() != 1)
ref += "-" + QString::number(func->overloadNumber());
}
break;
case Node::Property:
+#ifdef QDOC_QML
+ case Node::QmlProperty:
+#endif
ref = node->name() + "-prop";
break;
+#ifdef QDOC_QML
+ case Node::QmlSignal:
+ ref = node->name() + "-signal";
+ break;
+ case Node::QmlMethod:
+ ref = node->name() + "-method";
+ break;
+#endif
case Node::Variable:
ref = node->name() + "-var";
break;
@@ -3166,9 +3321,11 @@ QString HtmlGenerator::refForAtom(Atom *atom, const Node * /* node */)
{
if (atom->type() == Atom::SectionLeft) {
return Doc::canonicalTitle(Text::sectionHeading(atom).toString());
- } else if (atom->type() == Atom::Target) {
+ }
+ else if (atom->type() == Atom::Target) {
return Doc::canonicalTitle(atom->string());
- } else {
+ }
+ else {
return QString();
}
}
@@ -3212,7 +3369,10 @@ void HtmlGenerator::generateDetailedMember(const Node *node,
out() << "";
generateSynopsis(enume, relative, marker, CodeMarker::Detailed);
out() << "
";
- generateSynopsis(enume->flagsType(), relative, marker, CodeMarker::Detailed);
+ generateSynopsis(enume->flagsType(),
+ relative,
+ marker,
+ CodeMarker::Detailed);
out() << "\n";
}
else {
@@ -3364,7 +3524,7 @@ void HtmlGenerator::findAllNamespaces(const InnerNode *node)
}
}
-#ifdef ZZZ_QDOC_QML
+#ifdef ZZZ_QDOC_QML
/*!
This function finds all the qml element nodes and
stores them in a map for later use.
@@ -3375,24 +3535,16 @@ void HtmlGenerator::findAllQmlClasses(const InnerNode *node)
while (c != node->childNodes().constEnd()) {
if ((*c)->type() == Node::Fake) {
const FakeNode* fakeNode = static_cast(*c);
- if (fakeNode->subType() == FakeNode::QmlClass) {
- const QmlNode* qmlNode = static_cast(fakeNode);
- //qDebug() << "HtmlGenerator: QML CLASS" << qmlNode->name();
+ if (fakeNode->subType() == Node::QmlClass) {
+ const QmlClassNode* qmlNode =
+ static_cast(fakeNode);
const Node* n = qmlNode->classNode();
- if (n)
- //qDebug() << " FOUND IT!" << n->name();
}
qmlClasses.insert(fakeNode->name(),*c);
}
++c;
}
}
-#endif
-
-#if 0
- else if ((*c)->isInnerNode()) {
- findAllClasses(static_cast(*c));
- }
#endif
int HtmlGenerator::hOffset(const Node *node)
@@ -3705,3 +3857,214 @@ void HtmlGenerator::endLink()
}
QT_END_NAMESPACE
+
+#ifdef QDOC_QML
+
+/*!
+ Generates the summary for for the \a section. Only used for
+ sections of QML element documentation.
+
+ Currently handles only the QML property group.
+ */
+void HtmlGenerator::generateQmlSummary(const Section& section,
+ const Node *relative,
+ CodeMarker *marker)
+{
+ if (!section.members.isEmpty()) {
+ NodeList::ConstIterator m;
+ int count = section.members.size();
+ bool twoColumn = false;
+ if (section.members.first()->type() == Node::QmlProperty) {
+ twoColumn = (count >= 5);
+ }
+ if (twoColumn)
+ out() << "\n"
+ << "";
+ out() << "\n";
+
+ int row = 0;
+ m = section.members.begin();
+ while (m != section.members.end()) {
+ if (twoColumn && row == (int) (count + 1) / 2)
+ out() << " | \n";
+ out() << "- ";
+ generateQmlItem(*m,relative,marker,true);
+ out() << "
\n";
+ row++;
+ ++m;
+ }
+ out() << " \n";
+ if (twoColumn)
+ out() << " |
\n
\n";
+ }
+}
+
+/*!
+ Outputs the html detailed documentation for a section
+ on a QML element reference page.
+ */
+void HtmlGenerator::generateDetailedQmlMember(const Node *node,
+ const InnerNode *relative,
+ CodeMarker *marker)
+{
+ const QmlPropertyNode* qpn = 0;
+ generateMacRef(node, marker);
+ out() << "";
+ if (node->subType() == Node::QmlPropertyGroup) {
+ const QmlPropGroupNode* qpgn = static_cast
(node);
+ NodeList::ConstIterator p = qpgn->childNodes().begin();
+ out() << "";
+ out() << "
";
+
+ while (p != qpgn->childNodes().end()) {
+ if ((*p)->type() == Node::QmlProperty) {
+ qpn = static_cast(*p);
+ out() << "";
+ out() << "";
+ generateQmlItem(qpn, relative, marker, false);
+ out() << " |
";
+ if (qpgn->isDefault()) {
+ out() << "
"
+ << "
"
+ << ""
+ << "
"
+ << "
"
+ << ""
+ << "default |
";
+ }
+ }
+ ++p;
+ }
+ out() << "
";
+ out() << "
";
+ }
+ else if (node->type() == Node::QmlSignal) {
+ const QmlSignalNode* qsn = static_cast
(node);
+ out() << "";
+ out() << "
";
+ out() << "";
+ out() << "";
+ generateQmlItem(qsn,relative,marker,false);
+ out() << " |
";
+ out() << "
";
+ out() << "
";
+ }
+ else if (node->type() == Node::QmlMethod) {
+ const QmlMethodNode* qmn = static_cast(node);
+ out() << "";
+ out() << "
";
+ out() << "";
+ out() << "";
+ generateQmlItem(qmn,relative,marker,false);
+ out() << " |
";
+ out() << "
";
+ out() << "
";
+ }
+ out() << "";
+ generateStatus(node, marker);
+ generateBody(node, marker);
+ generateThreadSafeness(node, marker);
+ generateSince(node, marker);
+ generateAlsoList(node, marker);
+ out() << "
";
+ out() << " ";
+}
+
+/*!
+ Output the "Inherits" line for the QML element,
+ if there should be one.
+ */
+void HtmlGenerator::generateQmlInherits(const QmlClassNode* cn,
+ CodeMarker* marker)
+{
+ if (cn && !cn->links().empty()) {
+ if (cn->links().contains(Node::InheritsLink)) {
+ QPair linkPair;
+ linkPair = cn->links()[Node::InheritsLink];
+ QStringList strList(linkPair.first);
+ const Node* n = tre->findNode(strList,Node::Fake);
+ if (n && n->subType() == Node::QmlClass) {
+ const QmlClassNode* qcn = static_cast(n);
+ out() << "";
+ Text text;
+ text << "[Inherits ";
+ text << Atom(Atom::LinkNode,CodeMarker::stringForNode(qcn));
+ text << Atom(Atom::FormattingLeft, ATOM_FORMATTING_LINK);
+ text << Atom(Atom::String, linkPair.second);
+ text << Atom(Atom::FormattingRight, ATOM_FORMATTING_LINK);
+ text << "]";
+ generateText(text, cn, marker);
+ out() << "
";
+ }
+// else
+// qDebug() << "generateQmlInherits(): "
+// << "Inherited element not documented -->"
+// << linkPair.first;
+ }
+ }
+}
+
+/*!
+ Output the "[Xxx instantiates the C++ class QFxXxx]"
+ line for the QML element, if there should be one.
+
+ If there is no class node, or if the class node status
+ is set to Node::Internal, do nothing.
+ */
+void HtmlGenerator::generateQmlInstantiates(const QmlClassNode* qcn,
+ CodeMarker* marker)
+{
+ const ClassNode* cn = qcn->classNode();
+ if (cn && (cn->status() != Node::Internal)) {
+ out() << "";
+ Text text;
+ text << "[";
+ text << Atom(Atom::LinkNode,CodeMarker::stringForNode(qcn));
+ text << Atom(Atom::FormattingLeft, ATOM_FORMATTING_LINK);
+ text << Atom(Atom::String, qcn->name());
+ text << Atom(Atom::FormattingRight, ATOM_FORMATTING_LINK);
+ text << " instantiates the C++ class ";
+ text << Atom(Atom::LinkNode,CodeMarker::stringForNode(cn));
+ text << Atom(Atom::FormattingLeft, ATOM_FORMATTING_LINK);
+ text << Atom(Atom::String, cn->name());
+ text << Atom(Atom::FormattingRight, ATOM_FORMATTING_LINK);
+ text << "]";
+ generateText(text, qcn, marker);
+ out() << "
";
+ }
+}
+
+/*!
+ Output the "[QFxXxx is instantiated by QML element Xxx]"
+ line for the class, if there should be one.
+
+ If there is no QML element, or if the class node status
+ is set to Node::Internal, do nothing.
+ */
+void HtmlGenerator::generateInstantiatedBy(const ClassNode* cn,
+ CodeMarker* marker)
+{
+ if (cn && cn->status() != Node::Internal && !cn->qmlElement().isEmpty()) {
+ const Node* n = tre->root()->findNode(cn->qmlElement(),Node::Fake);
+ if (n && n->subType() == Node::QmlClass) {
+ out() << "";
+ Text text;
+ text << "[";
+ text << Atom(Atom::LinkNode,CodeMarker::stringForNode(cn));
+ text << Atom(Atom::FormattingLeft, ATOM_FORMATTING_LINK);
+ text << Atom(Atom::String, cn->name());
+ text << Atom(Atom::FormattingRight, ATOM_FORMATTING_LINK);
+ text << " is instantiated by QML element ";
+ text << Atom(Atom::LinkNode,CodeMarker::stringForNode(n));
+ text << Atom(Atom::FormattingLeft, ATOM_FORMATTING_LINK);
+ text << Atom(Atom::String, n->name());
+ text << Atom(Atom::FormattingRight, ATOM_FORMATTING_LINK);
+ text << "]";
+ generateText(text, cn, marker);
+ out() << "
";
+ }
+ }
+}
+
+#endif
diff --git a/tools/qdoc3/htmlgenerator.h b/tools/qdoc3/htmlgenerator.h
index a7632cd..180c307 100644
--- a/tools/qdoc3/htmlgenerator.h
+++ b/tools/qdoc3/htmlgenerator.h
@@ -145,6 +145,21 @@ class HtmlGenerator : public PageGenerator
const Node *relative,
CodeMarker *marker,
CodeMarker::SynopsisStyle style);
+#ifdef QDOC_QML
+ void generateQmlSummary(const Section& section,
+ const Node *relative,
+ CodeMarker *marker);
+ void generateQmlItem(const Node *node,
+ const Node *relative,
+ CodeMarker *marker,
+ bool summary);
+ void generateDetailedQmlMember(const Node *node,
+ const InnerNode *relative,
+ CodeMarker *marker);
+ void generateQmlInherits(const QmlClassNode* cn, CodeMarker* marker);
+ void generateQmlInstantiates(const QmlClassNode* qcn, CodeMarker* marker);
+ void generateInstantiatedBy(const ClassNode* cn, CodeMarker* marker);
+#endif
#ifdef QDOC_NAME_ALIGNMENT
void generateSection(const NodeList& nl,
const Node *relative,
@@ -180,8 +195,12 @@ class HtmlGenerator : public PageGenerator
const Node *relative,
CodeMarker *marker,
const Node *actualNode = 0);
- void generateDetailedMember(const Node *node, const InnerNode *relative, CodeMarker *marker);
- void generateLink(const Atom *atom, const Node *relative, CodeMarker *marker);
+ void generateDetailedMember(const Node *node,
+ const InnerNode *relative,
+ CodeMarker *marker);
+ void generateLink(const Atom *atom,
+ const Node *relative,
+ CodeMarker *marker);
void generateStatus(const Node *node, CodeMarker *marker);
QString registerRef(const QString& ref);
diff --git a/tools/qdoc3/jambiapiparser.cpp b/tools/qdoc3/jambiapiparser.cpp
index f981e6d..70e9260 100644
--- a/tools/qdoc3/jambiapiparser.cpp
+++ b/tools/qdoc3/jambiapiparser.cpp
@@ -234,8 +234,9 @@ void JambiApiParser::doneParsingSourceFiles(Tree * /* tree */)
foreach (Node *cppNode, cppTre->root()->childNodes()) {
if (cppNode->type() == Node::Fake) {
FakeNode *cppFake = static_cast(cppNode);
- if (cppFake->subType() == FakeNode::Page) {
- FakeNode *javaFake = new FakeNode(javaTre->root(), cppFake->name(),
+ if (cppFake->subType() == Node::Page) {
+ FakeNode *javaFake = new FakeNode(javaTre->root(),
+ cppFake->name(),
cppFake->subType());
javaFake->setModuleName("com.trolltech.qt"); // ### hard-coded
javaFake->setTitle(cppFake->title());
diff --git a/tools/qdoc3/node.cpp b/tools/qdoc3/node.cpp
index b2e53ab..610249d 100644
--- a/tools/qdoc3/node.cpp
+++ b/tools/qdoc3/node.cpp
@@ -43,6 +43,7 @@
node.cpp
*/
+#include
#include "node.h"
QT_BEGIN_NAMESPACE
@@ -113,6 +114,9 @@ void Node::setRelates(InnerNode *pseudoParent)
}
/*!
+ This function creates a pair that describes a link.
+ The pair is composed from \a link and \a desc. The
+ \a linkType is the map index the pair is filed under.
*/
void Node::setLink(LinkType linkType, const QString &link, const QString &desc)
{
@@ -623,7 +627,7 @@ void InnerNode::removeRelated(Node *pseudoChild)
*/
/*!
- Returns false because this is an InnerNode.
+ Returns false because this is a LeafNode.
*/
bool LeafNode::isInnerNode() const
{
@@ -713,9 +717,11 @@ void ClassNode::fixBaseClasses()
*/
/*!
+ The type of a FakeNode is Fake, and it has a \a subtype,
+ which specifies the type of FakeNode.
*/
-FakeNode::FakeNode(InnerNode *parent, const QString& name, SubType subType)
- : InnerNode(Fake, parent, name), sub(subType)
+FakeNode::FakeNode(InnerNode *parent, const QString& name, SubType subtype)
+ : InnerNode(Fake, parent, name), sub(subtype)
{
}
@@ -1033,4 +1039,98 @@ bool TargetNode::isInnerNode() const
return false;
}
+#ifdef QDOC_QML
+/*!
+ Constructor for the Qml class node.
+ */
+QmlClassNode::QmlClassNode(InnerNode *parent,
+ const QString& name,
+ const ClassNode* cn)
+ : FakeNode(parent, name, QmlClass), cnode(cn)
+{
+ setTitle("QML " + name + " Element Reference");
+}
+
+/*!
+ The base file name for this kind of node has "qml_"
+ prepended to it.
+
+ But not yet. Still testing.
+ */
+QString QmlClassNode::fileBase() const
+{
+#if 0
+ if (Node::fileBase() == "item")
+ qDebug() << "FILEBASE: qmlitem" << name();
+ return "qml_" + Node::fileBase();
+#endif
+ return Node::fileBase();
+}
+
+/*!
+ Constructor for the Qml property group node. \a parent is
+ always a QmlClassNode.
+ */
+QmlPropGroupNode::QmlPropGroupNode(QmlClassNode* parent, const QString& name)
+ : FakeNode(parent, name, QmlPropertyGroup), isdefault(false)
+{
+ // nothing.
+}
+
+/*!
+ Constructor for the QML property node.
+ */
+QmlPropertyNode::QmlPropertyNode(QmlPropGroupNode *parent,
+ const QString& name,
+ const QString& type)
+ : LeafNode(QmlProperty, parent, name),
+ dt(type),
+ sto(Trool_Default),
+ des(Trool_Default)
+{
+ // nothing.
+}
+
+/*!
+ I don't know what this is.
+ */
+QmlPropertyNode::Trool QmlPropertyNode::toTrool(bool boolean)
+{
+ return boolean ? Trool_True : Trool_False;
+}
+
+/*!
+ I don't know what this is either.
+ */
+bool QmlPropertyNode::fromTrool(Trool troolean, bool defaultValue)
+{
+ switch (troolean) {
+ case Trool_True:
+ return true;
+ case Trool_False:
+ return false;
+ default:
+ return defaultValue;
+ }
+}
+
+/*!
+ Constructor for the QML signal node.
+ */
+QmlSignalNode::QmlSignalNode(QmlClassNode *parent, const QString& name)
+ : LeafNode(QmlSignal, parent, name)
+{
+ // nothing.
+}
+
+/*!
+ Constructor for the QML method node.
+ */
+QmlMethodNode::QmlMethodNode(QmlClassNode *parent, const QString& name)
+ : LeafNode(QmlMethod, parent, name)
+{
+ // nothing.
+}
+#endif
+
QT_END_NAMESPACE
diff --git a/tools/qdoc3/node.h b/tools/qdoc3/node.h
index a35bc17..17ec447 100644
--- a/tools/qdoc3/node.h
+++ b/tools/qdoc3/node.h
@@ -72,7 +72,31 @@ class Node
Function,
Property,
Variable,
+#ifdef QDOC_QML
+ Target,
+ QmlProperty,
+ QmlSignal,
+ QmlMethod
+#else
Target
+#endif
+ };
+
+ enum SubType {
+ NoSubType,
+ Example,
+ HeaderFile,
+ File,
+ Group,
+ Module,
+ Page,
+#ifdef QDOC_QML
+ ExternalPage,
+ QmlClass,
+ QmlPropertyGroup
+#else
+ ExternalPage
+#endif
};
enum Access { Public, Protected, Private };
@@ -99,7 +123,8 @@ class Node
NextLink,
PreviousLink,
ContentsLink,
- IndexLink /*,
+ IndexLink,
+ InheritsLink /*,
GlossaryLink,
CopyrightLink,
ChapterLink,
@@ -125,6 +150,7 @@ class Node
virtual bool isInnerNode() const = 0;
virtual bool isReimp() const { return false; }
Type type() const { return typ; }
+ virtual SubType subType() const { return NoSubType; }
InnerNode *parent() const { return par; }
InnerNode *relates() const { return rel; }
const QString& name() const { return nam; }
@@ -144,7 +170,7 @@ class Node
void clearRelated() { rel = 0; }
- QString fileBase() const;
+ virtual QString fileBase() const;
protected:
Node(Type type, InnerNode *parent, const QString& name);
@@ -181,7 +207,7 @@ typedef QList NodeList;
class InnerNode : public Node
{
public:
- ~InnerNode();
+ virtual ~InnerNode();
Node *findNode(const QString& name);
Node *findNode(const QString& name, Type type);
@@ -203,6 +229,7 @@ class InnerNode : public Node
const EnumNode *findEnumNodeForValue(const QString &enumValue) const;
const NodeList & childNodes() const { return children; }
const NodeList & relatedNodes() const { return related; }
+ int count() const { return children.size(); }
int overloadNumber(const FunctionNode *func) const;
int numOverloads(const QString& funcName) const;
NodeList overloads(const QString &funcName) const;
@@ -232,17 +259,19 @@ class LeafNode : public Node
{
public:
LeafNode();
+ virtual ~LeafNode() { }
virtual bool isInnerNode() const;
protected:
- LeafNode(Type type, InnerNode *parent, const QString& name);
+ LeafNode(Type type, InnerNode* parent, const QString& name);
};
class NamespaceNode : public InnerNode
{
public:
NamespaceNode(InnerNode *parent, const QString& name);
+ virtual ~NamespaceNode() { }
};
class ClassNode;
@@ -266,6 +295,7 @@ class ClassNode : public InnerNode
{
public:
ClassNode(InnerNode *parent, const QString& name);
+ virtual ~ClassNode() { }
void addBaseClass(Access access,
ClassNode *node,
@@ -280,29 +310,23 @@ class ClassNode : public InnerNode
QString serviceName() const { return sname; }
void setServiceName(const QString& value) { sname = value; }
+ QString qmlElement() const { return qmlelement; }
+ void setQmlElement(const QString& value) { qmlelement = value; }
private:
QList bas;
QList der;
bool hidden;
QString sname;
+ QString qmlelement;
};
class FakeNode : public InnerNode
{
public:
- enum SubType {
- Example,
- HeaderFile,
- File,
- Group,
- Module,
- Page,
- ExternalPage,
- QmlClass
- };
FakeNode(InnerNode *parent, const QString& name, SubType subType);
+ virtual ~FakeNode() { }
void setTitle(const QString &title) { tle = title; }
void setSubTitle(const QString &subTitle) { stle = subTitle; }
@@ -321,18 +345,85 @@ class FakeNode : public InnerNode
NodeList gr;
};
-class QmlNode : public FakeNode
+#ifdef QDOC_QML
+class QmlClassNode : public FakeNode
{
public:
- QmlNode(InnerNode *parent, const QString& name, const ClassNode* cn)
- : FakeNode(parent, name, QmlClass), cnode(cn) { }
+ QmlClassNode(InnerNode *parent,
+ const QString& name,
+ const ClassNode* cn);
+ virtual ~QmlClassNode() { }
const ClassNode* classNode() const { return cnode; }
+ virtual QString fileBase() const;
private:
const ClassNode* cnode;
};
+class QmlPropGroupNode : public FakeNode
+{
+ public:
+ QmlPropGroupNode(QmlClassNode* parent, const QString& name);
+ virtual ~QmlPropGroupNode() { }
+
+ const QString& element() const { return name(); }
+ void setDefault() { isdefault = true; }
+ bool isDefault() const { return isdefault; }
+
+ private:
+ bool isdefault;
+};
+
+class QmlPropertyNode : public LeafNode
+{
+ public:
+ QmlPropertyNode(QmlPropGroupNode* parent,
+ const QString& name,
+ const QString& type);
+ virtual ~QmlPropertyNode() { }
+
+ void setDataType(const QString& dataType) { dt = dataType; }
+ void setStored(bool stored) { sto = toTrool(stored); }
+ void setDesignable(bool designable) { des = toTrool(designable); }
+
+ const QString &dataType() const { return dt; }
+ QString qualifiedDataType() const { return dt; }
+ bool isStored() const { return fromTrool(sto,true); }
+ bool isDesignable() const { return fromTrool(des,false); }
+
+ const QString& element() const { return parent()->name(); }
+
+ private:
+ enum Trool { Trool_True, Trool_False, Trool_Default };
+
+ static Trool toTrool(bool boolean);
+ static bool fromTrool(Trool troolean, bool defaultValue);
+
+ QString dt;
+ Trool sto;
+ Trool des;
+};
+
+class QmlSignalNode : public LeafNode
+{
+ public:
+ QmlSignalNode(QmlClassNode* parent, const QString& name);
+ virtual ~QmlSignalNode() { }
+
+ const QString& element() const { return parent()->name(); }
+};
+
+class QmlMethodNode : public LeafNode
+{
+ public:
+ QmlMethodNode(QmlClassNode* parent, const QString& name);
+ virtual ~QmlMethodNode() { }
+
+ const QString& element() const { return parent()->name(); }
+};
+#endif
+
class EnumItem
{
public:
@@ -358,6 +449,7 @@ class EnumNode : public LeafNode
{
public:
EnumNode(InnerNode *parent, const QString& name);
+ virtual ~EnumNode() { }
void addItem(const EnumItem& item);
void setFlagsType(TypedefNode *typedeff);
@@ -378,6 +470,7 @@ class TypedefNode : public LeafNode
{
public:
TypedefNode(InnerNode *parent, const QString& name);
+ virtual ~TypedefNode() { }
const EnumNode *associatedEnum() const { return ae; }
@@ -438,6 +531,7 @@ class FunctionNode : public LeafNode
enum Virtualness { NonVirtual, ImpureVirtual, PureVirtual };
FunctionNode(InnerNode *parent, const QString &name);
+ virtual ~FunctionNode() { }
void setReturnType(const QString& returnType) { rt = returnType; }
void setMetaness(Metaness metaness) { met = metaness; }
@@ -500,6 +594,7 @@ class PropertyNode : public LeafNode
enum { NumFunctionRoles = Resetter + 1 };
PropertyNode(InnerNode *parent, const QString& name);
+ virtual ~PropertyNode() { }
void setDataType(const QString& dataType) { dt = dataType; }
void addFunction(FunctionNode *function, FunctionRole role);
@@ -557,6 +652,7 @@ class VariableNode : public LeafNode
{
public:
VariableNode(InnerNode *parent, const QString &name);
+ virtual ~VariableNode() { }
void setLeftType(const QString &leftType) { lt = leftType; }
void setRightType(const QString &rightType) { rt = rightType; }
@@ -582,6 +678,7 @@ class TargetNode : public LeafNode
{
public:
TargetNode(InnerNode *parent, const QString& name);
+ virtual ~TargetNode() { }
virtual bool isInnerNode() const;
};
diff --git a/tools/qdoc3/pagegenerator.cpp b/tools/qdoc3/pagegenerator.cpp
index 06ff398..8715f4a 100644
--- a/tools/qdoc3/pagegenerator.cpp
+++ b/tools/qdoc3/pagegenerator.cpp
@@ -81,30 +81,50 @@ QString PageGenerator::fileBase(const Node *node)
{
if (node->relates())
node = node->relates();
- else if (!node->isInnerNode())
+ else if (!node->isInnerNode()) {
node = node->parent();
+#ifdef QDOC_QML
+ if (node->subType() == Node::QmlPropertyGroup) {
+ node = node->parent();
+ }
+#endif
+ }
QString base = node->doc().baseName();
if (!base.isEmpty())
return base;
- const Node *p = node;
-
- forever {
- base.prepend(p->name());
+ const Node *p = node;
+
+ forever {
+ base.prepend(p->name());
+#ifdef QDOC_QML
+ /*
+ To avoid file name conflicts in the html directory,
+ we prepend "qml-" to the file name of QML element doc
+ files.
+ */
+ if ((p->subType() == Node::QmlClass) ||
+ (p->subType() == Node::QmlPropertyGroup))
+ base.prepend("qml-");
+ else if ((p->type() == Node::QmlProperty) ||
+ (p->type() == Node::QmlSignal) ||
+ (p->type() == Node::QmlMethod))
+ base.prepend("qml-");
+#endif
const Node *pp = p->parent();
if (!pp || pp->name().isEmpty() || pp->type() == Node::Fake)
- break;
+ break;
base.prepend(QLatin1Char('-'));
p = pp;
- }
-
- if (node->type() == Node::Fake) {
+ }
+
+ if (node->type() == Node::Fake) {
#ifdef QDOC2_COMPAT
- if (base.endsWith(".html"))
- base.truncate(base.length() - 5);
+ if (base.endsWith(".html"))
+ base.truncate(base.length() - 5);
#endif
- }
+ }
// the code below is effectively equivalent to:
// base.replace(QRegExp("[^A-Za-z0-9]+"), " ");
@@ -126,7 +146,8 @@ QString PageGenerator::fileBase(const Node *node)
if ((u >= 'a' && u <= 'z') || (u >= '0' && u <= '9')) {
res += QLatin1Char(u);
begun = true;
- } else if (begun) {
+ }
+ else if (begun) {
res += QLatin1Char('-');
begun = false;
}
@@ -187,8 +208,12 @@ void PageGenerator::generateInnerNode(const InnerNode *node,
if (node->type() == Node::Fake) {
const FakeNode *fakeNode = static_cast(node);
- if (fakeNode->subType() == FakeNode::ExternalPage)
+ if (fakeNode->subType() == Node::ExternalPage)
+ return;
+#ifdef QDOC_QML
+ if (fakeNode->subType() == Node::QmlPropertyGroup)
return;
+#endif
}
if (node->parent() != 0) {
@@ -197,12 +222,6 @@ void PageGenerator::generateInnerNode(const InnerNode *node,
generateClassLikeNode(node, marker);
}
else if (node->type() == Node::Fake) {
- const FakeNode* fakeNode = static_cast(node);
-#ifdef QDOC_QML
- if (fakeNode->subType() == FakeNode::QmlClass) {
- //qDebug() << "FILENAME:" << fileName(node);
- }
-#endif
generateFakeNode(static_cast(node), marker);
}
endSubPage();
diff --git a/tools/qdoc3/test/classic.css b/tools/qdoc3/test/classic.css
index 3816164..4225a1b 100644
--- a/tools/qdoc3/test/classic.css
+++ b/tools/qdoc3/test/classic.css
@@ -225,3 +225,52 @@ span.string,span.char
{
font-size: 0.65em
}
+
+.qmlitem {
+ padding: 0;
+}
+
+.qmlname {
+ white-space: nowrap;
+ font-weight: bold;
+ font-size: 125%;
+}
+
+.qmltype {
+ font-weight: bold;
+ font-size: 125%;
+}
+
+.qmlproto, .qmldoc {
+ // border-top: 1px solid #84b0c7;
+}
+
+.qmlproto {
+ padding: 0;
+ //background-color: #e4e4e4;//#d5e1e8;
+ //font-weight: bold;
+ //-webkit-border-top-left-radius: 8px;
+ //-webkit-border-top-right-radius: 8px;
+ //-moz-border-radius-topleft: 8px;
+ //-moz-border-radius-topright: 8px;
+}
+
+.qmldoc {
+ border-top: 1px solid #e4e4e4;
+ //padding: 2px 5px;
+ //background-color: #eef3f5;
+ //border-top-width: 0;
+ //-webkit-border-bottom-left-radius: 8px;
+ //-webkit-border-bottom-right-radius: 8px;
+ //-moz-border-radius-bottomleft: 8px;
+ //-moz-border-radius-bottomright: 8px;
+}
+
+.qmldoc p, .qmldoc dl, .qmldoc ul {
+ //margin: 6px 0;
+}
+
+*.qmlitem p {
+ //margin-top: 0px;
+ //margin-bottom: 0px;
+}
diff --git a/tools/qdoc3/tree.cpp b/tools/qdoc3/tree.cpp
index 308ba0e..e6dd084 100644
--- a/tools/qdoc3/tree.cpp
+++ b/tools/qdoc3/tree.cpp
@@ -176,6 +176,8 @@ const Node *Tree::findNode(const QStringList &path,
}
/*!
+ Find the node with the specified \a path name of the
+ specified \a type.
*/
Node *Tree::findNode(const QStringList &path,
Node::Type type,
@@ -189,6 +191,8 @@ Node *Tree::findNode(const QStringList &path,
}
/*!
+ Find the node with the specified \a path name of the
+ specified \a type.
*/
const Node *Tree::findNode(const QStringList &path,
Node::Type type,
@@ -208,7 +212,9 @@ FunctionNode *Tree::findFunctionNode(const QStringList& path,
int findFlags)
{
return const_cast(
- const_cast(this)->findFunctionNode(path, relative, findFlags));
+ const_cast(this)->findFunctionNode(path,
+ relative,
+ findFlags));
}
/*!
@@ -233,7 +239,8 @@ const FunctionNode *Tree::findFunctionNode(const QStringList &path,
else
next = ((InnerNode *) node)->findNode(path.at(i));
- if (!next && node->type() == Node::Class && (findFlags & SearchBaseClasses)) {
+ if (!next && node->type() == Node::Class &&
+ (findFlags & SearchBaseClasses)) {
NodeList baseClasses = allBaseClasses(static_cast(node));
foreach (const Node *baseClass, baseClasses) {
if (i == path.size() - 1)
@@ -563,7 +570,7 @@ void Tree::resolveGroups()
FakeNode *fake =
static_cast(findNode(QStringList(i.key()),Node::Fake));
- if (fake && fake->subType() == FakeNode::Group) {
+ if (fake && fake->subType() == Node::Group) {
fake->addGroupMember(i.value());
}
else {
@@ -770,21 +777,21 @@ void Tree::readIndexSection(const QDomElement &element,
}
else if (element.nodeName() == "page") {
- FakeNode::SubType subtype;
+ Node::SubType subtype;
if (element.attribute("subtype") == "example")
- subtype = FakeNode::Example;
+ subtype = Node::Example;
else if (element.attribute("subtype") == "header")
- subtype = FakeNode::HeaderFile;
+ subtype = Node::HeaderFile;
else if (element.attribute("subtype") == "file")
- subtype = FakeNode::File;
+ subtype = Node::File;
else if (element.attribute("subtype") == "group")
- subtype = FakeNode::Group;
+ subtype = Node::Group;
else if (element.attribute("subtype") == "module")
- subtype = FakeNode::Module;
+ subtype = Node::Module;
else if (element.attribute("subtype") == "page")
- subtype = FakeNode::Page;
+ subtype = Node::Page;
else if (element.attribute("subtype") == "externalpage")
- subtype = FakeNode::ExternalPage;
+ subtype = Node::ExternalPage;
else
return;
@@ -1226,25 +1233,25 @@ bool Tree::generateIndexSection(QXmlStreamWriter &writer,
const FakeNode *fakeNode = static_cast(node);
switch (fakeNode->subType()) {
- case FakeNode::Example:
+ case Node::Example:
writer.writeAttribute("subtype", "example");
break;
- case FakeNode::HeaderFile:
+ case Node::HeaderFile:
writer.writeAttribute("subtype", "header");
break;
- case FakeNode::File:
+ case Node::File:
writer.writeAttribute("subtype", "file");
break;
- case FakeNode::Group:
+ case Node::Group:
writer.writeAttribute("subtype", "group");
break;
- case FakeNode::Module:
+ case Node::Module:
writer.writeAttribute("subtype", "module");
break;
- case FakeNode::Page:
+ case Node::Page:
writer.writeAttribute("subtype", "page");
break;
- case FakeNode::ExternalPage:
+ case Node::ExternalPage:
writer.writeAttribute("subtype", "externalpage");
break;
default:
@@ -1383,7 +1390,7 @@ bool Tree::generateIndexSection(QXmlStreamWriter &writer,
bool external = false;
if (inner->type() == Node::Fake) {
const FakeNode *fakeNode = static_cast(inner);
- if (fakeNode->subType() == FakeNode::ExternalPage)
+ if (fakeNode->subType() == Node::ExternalPage)
external = true;
}
@@ -1863,7 +1870,7 @@ void Tree::generateTagFile(const QString &fileName) const
*/
void Tree::addExternalLink(const QString &url, const Node *relative)
{
- FakeNode *fakeNode = new FakeNode(root(), url, FakeNode::ExternalPage);
+ FakeNode *fakeNode = new FakeNode(root(), url, Node::ExternalPage);
fakeNode->setAccess(Node::Public);
// Create some content for the node.
@@ -1898,6 +1905,11 @@ QString Tree::fullDocumentLocation(const Node *node) const
return "";
}
else if (node->type() == Node::Fake) {
+#ifdef QDOC_QML
+ if (node->subType() == Node::QmlClass)
+ return "qml-" + node->fileBase() + ".html";
+ else
+#endif
parentName = node->fileBase() + ".html";
}
else if (node->fileBase().isEmpty())
diff --git a/tools/qdoc3/webxmlgenerator.cpp b/tools/qdoc3/webxmlgenerator.cpp
index c5209b8..e87e812 100644
--- a/tools/qdoc3/webxmlgenerator.cpp
+++ b/tools/qdoc3/webxmlgenerator.cpp
@@ -191,7 +191,7 @@ void WebXMLGenerator::generateIndexSections(QXmlStreamWriter &writer,
generateRelations(writer, node, marker);
- if (fake->subType() == FakeNode::Module) {
+ if (fake->subType() == Node::Module) {
writer.writeStartElement("generatedlist");
writer.writeAttribute("contents", "classesbymodule");
@@ -264,7 +264,7 @@ void WebXMLGenerator::generateInnerNode(const InnerNode *node, CodeMarker *marke
if (node->type() == Node::Fake) {
const FakeNode *fakeNode = static_cast(node);
- if (fakeNode->subType() == FakeNode::ExternalPage)
+ if (fakeNode->subType() == Node::ExternalPage)
return;
}
--
cgit v0.12
From 567a18967b4d656b9f12a505f3146732d96eb935 Mon Sep 17 00:00:00 2001
From: Aaron Kennedy
Date: Wed, 29 Jul 2009 18:13:24 +1000
Subject: Add CONSTANT attribute to Q_PROPERTY()
This will be used by the declarative module to determine if a property lacking a NOTIFY signal is truly constant, or just missing a NOTIFY signal.
---
doc/src/properties.qdoc | 6 ++++++
doc/src/snippets/code/doc_src_properties.qdoc | 3 ++-
src/corelib/kernel/qmetaobject.cpp | 29 ++++++++++++++++++++++++++-
src/corelib/kernel/qmetaobject.h | 2 ++
src/tools/moc/generator.cpp | 7 ++++++-
src/tools/moc/moc.cpp | 23 +++++++++++++++++++++
src/tools/moc/moc.h | 3 ++-
tests/auto/qmetaobject/tst_qmetaobject.cpp | 17 ++++++++++++++++
8 files changed, 86 insertions(+), 4 deletions(-)
diff --git a/doc/src/properties.qdoc b/doc/src/properties.qdoc
index 5490dd0..cac5016 100644
--- a/doc/src/properties.qdoc
+++ b/doc/src/properties.qdoc
@@ -122,6 +122,12 @@
editable property for (checkable) buttons. Note that QItemDelegate
gets and sets a widget's \c USER property.
+ \o The presence of the \c CONSTANT attibute indicates that the property
+ value is constant. For a given object instance, the READ method of a
+ constant property must return the same value every time it is called. This
+ constant value may be different for different instances of the object. A
+ constant property cannot have a WRTE method or a NOTIFY signal.
+
\endlist
The \c READ, \c WRITE, and \c RESET functions can be inherited.
diff --git a/doc/src/snippets/code/doc_src_properties.qdoc b/doc/src/snippets/code/doc_src_properties.qdoc
index 377cc9c..64e5377 100644
--- a/doc/src/snippets/code/doc_src_properties.qdoc
+++ b/doc/src/snippets/code/doc_src_properties.qdoc
@@ -7,7 +7,8 @@ Q_PROPERTY(type name
[DESIGNABLE bool]
[SCRIPTABLE bool]
[STORED bool]
- [USER bool])
+ [USER bool]
+ [CONSTANT])
//! [0]
diff --git a/src/corelib/kernel/qmetaobject.cpp b/src/corelib/kernel/qmetaobject.cpp
index 08cecaf..fee2da9 100644
--- a/src/corelib/kernel/qmetaobject.cpp
+++ b/src/corelib/kernel/qmetaobject.cpp
@@ -159,7 +159,9 @@ enum PropertyFlags {
ResolveEditable = 0x00080000,
User = 0x00100000,
ResolveUser = 0x00200000,
- Notify = 0x00400000
+ Notify = 0x00400000,
+ Dynamic = 0x00800000,
+ Constant = 0x00000400
};
enum MethodFlags {
@@ -2439,6 +2441,31 @@ bool QMetaProperty::isUser(const QObject *object) const
}
/*!
+ \internal
+*/
+bool QMetaProperty::isDynamic() const
+{
+ if (!mobj)
+ return false;
+ int flags = mobj->d.data[handle + 2];
+ return flags & Dynamic;
+}
+
+/*!
+ Returns true if the property is constant; otherwise returns false.
+
+ A property is constant if the \c{Q_PROPERTY()}'s \c CONSTANT attribute
+ is set.
+*/
+bool QMetaProperty::isConstant() const
+{
+ if (!mobj)
+ return false;
+ int flags = mobj->d.data[handle + 2];
+ return flags & Constant;
+}
+
+/*!
\obsolete
Returns true if the property is editable for the given \a object;
diff --git a/src/corelib/kernel/qmetaobject.h b/src/corelib/kernel/qmetaobject.h
index 000ba6e..73b52a9 100644
--- a/src/corelib/kernel/qmetaobject.h
+++ b/src/corelib/kernel/qmetaobject.h
@@ -187,6 +187,8 @@ public:
bool isStored(const QObject *obj = 0) const;
bool isEditable(const QObject *obj = 0) const;
bool isUser(const QObject *obj = 0) const;
+ bool isDynamic() const;
+ bool isConstant() const;
bool isFlagType() const;
bool isEnumType() const;
diff --git a/src/tools/moc/generator.cpp b/src/tools/moc/generator.cpp
index b872dfd..e4086e6 100644
--- a/src/tools/moc/generator.cpp
+++ b/src/tools/moc/generator.cpp
@@ -66,7 +66,9 @@ enum PropertyFlags {
ResolveEditable = 0x00080000,
User = 0x00100000,
ResolveUser = 0x00200000,
- Notify = 0x00400000
+ Notify = 0x00400000,
+ Dynamic = 0x00800000,
+ Constant = 0x00000400
};
enum MethodFlags {
AccessPrivate = 0x00,
@@ -597,6 +599,9 @@ void Generator::generateProperties()
if (p.notifyId != -1)
flags |= Notify;
+ if (p.constant)
+ flags |= Constant;
+
fprintf(out, " %4d, %4d, ",
strreg(p.name),
strreg(p.type));
diff --git a/src/tools/moc/moc.cpp b/src/tools/moc/moc.cpp
index 797595f..66012ca 100644
--- a/src/tools/moc/moc.cpp
+++ b/src/tools/moc/moc.cpp
@@ -908,6 +908,12 @@ void Moc::parseProperty(ClassDef *def)
propDef.name = lexem();
while (test(IDENTIFIER)) {
QByteArray l = lexem();
+
+ if (l[0] == 'C' && l == "CONSTANT") {
+ propDef.constant = true;
+ continue;
+ }
+
QByteArray v, v2;
if (test(LPAREN)) {
v = lexemUntil(RPAREN);
@@ -963,6 +969,23 @@ void Moc::parseProperty(ClassDef *def)
msg += " has no READ accessor function. The property will be invalid.";
warning(msg.constData());
}
+ if (propDef.constant && !propDef.write.isNull()) {
+ QByteArray msg;
+ msg += "Property declaration ";
+ msg += propDef.name;
+ msg += " is both WRITEable and CONSTANT. CONSTANT will be ignored.";
+ propDef.constant = false;
+ warning(msg.constData());
+ }
+ if (propDef.constant && !propDef.notify.isNull()) {
+ QByteArray msg;
+ msg += "Property declaration ";
+ msg += propDef.name;
+ msg += " is both NOTIFYable and CONSTANT. CONSTANT will be ignored.";
+ propDef.constant = false;
+ warning(msg.constData());
+ }
+
if(!propDef.notify.isEmpty())
def->notifyableProperties++;
diff --git a/src/tools/moc/moc.h b/src/tools/moc/moc.h
index 9fa9ac2..494d53e 100644
--- a/src/tools/moc/moc.h
+++ b/src/tools/moc/moc.h
@@ -115,9 +115,10 @@ struct FunctionDef
struct PropertyDef
{
- PropertyDef():notifyId(-1), gspec(ValueSpec){}
+ PropertyDef():notifyId(-1), constant(false), gspec(ValueSpec){}
QByteArray name, type, read, write, reset, designable, scriptable, editable, stored, user, notify;
int notifyId;
+ bool constant;
enum Specification { ValueSpec, ReferenceSpec, PointerSpec };
Specification gspec;
bool stdCppSet() const {
diff --git a/tests/auto/qmetaobject/tst_qmetaobject.cpp b/tests/auto/qmetaobject/tst_qmetaobject.cpp
index dea0ffb..f4cff2b 100644
--- a/tests/auto/qmetaobject/tst_qmetaobject.cpp
+++ b/tests/auto/qmetaobject/tst_qmetaobject.cpp
@@ -108,6 +108,7 @@ class tst_QMetaObject : public QObject
Q_PROPERTY(int value6 READ value6 NOTIFY value6Changed)
Q_PROPERTY(MyStruct value7 READ value7 WRITE setVal7 NOTIFY value7Changed)
Q_PROPERTY(int value8 READ value8 NOTIFY value8Changed)
+ Q_PROPERTY(int value9 READ value9 CONSTANT)
public:
enum EnumType { EnumType1 };
@@ -137,6 +138,8 @@ public:
int value8() const { return 1; }
+ int value9() const { return 1; }
+
QList value4;
QVariantList value5;
@@ -159,6 +162,7 @@ private slots:
void customPropertyType();
void checkScope();
void propertyNotify();
+ void propertyConstant();
void stdSet();
void classInfo();
@@ -785,6 +789,19 @@ void tst_QMetaObject::propertyNotify()
QCOMPARE(signal.signature(), (const char *)0);
}
+void tst_QMetaObject::propertyConstant()
+{
+ const QMetaObject *mo = metaObject();
+
+ QMetaProperty prop = mo->property(mo->indexOfProperty("value8"));
+ QVERIFY(prop.isValid());
+ QVERIFY(!prop.isConstant());
+
+ prop = mo->property(mo->indexOfProperty("value9"));
+ QVERIFY(prop.isValid());
+ QVERIFY(prop.isConstant());
+}
+
class ClassInfoTestObjectA : public QObject
{
Q_OBJECT
--
cgit v0.12
From 8c905fd4376f8a8076ffce56f77c7039e8de4f25 Mon Sep 17 00:00:00 2001
From: Aaron Kennedy
Date: Thu, 16 Jul 2009 12:35:08 +1000
Subject: Add FINAL attribute to Q_PROPERTY()
This will be used by the declarative module to optimize property bindings.
---
doc/src/properties.qdoc | 5 +++++
doc/src/snippets/code/doc_src_properties.qdoc | 3 ++-
src/corelib/kernel/qmetaobject.cpp | 17 ++++++++++++++++-
src/corelib/kernel/qmetaobject.h | 1 +
src/tools/moc/generator.cpp | 5 ++++-
src/tools/moc/moc.cpp | 3 +++
src/tools/moc/moc.h | 3 ++-
tests/auto/qmetaobject/tst_qmetaobject.cpp | 17 +++++++++++++++++
8 files changed, 50 insertions(+), 4 deletions(-)
diff --git a/doc/src/properties.qdoc b/doc/src/properties.qdoc
index cac5016..2d03e91 100644
--- a/doc/src/properties.qdoc
+++ b/doc/src/properties.qdoc
@@ -128,6 +128,11 @@
constant value may be different for different instances of the object. A
constant property cannot have a WRTE method or a NOTIFY signal.
+ \o The presence of the \c FINAL attribute indicates that the property
+ will not be overridden by a derived class. This can be used for performance
+ optimizations in some cases, but is not enforced by moc. Care must be taken
+ never to override a \c FINAL property.
+
\endlist
The \c READ, \c WRITE, and \c RESET functions can be inherited.
diff --git a/doc/src/snippets/code/doc_src_properties.qdoc b/doc/src/snippets/code/doc_src_properties.qdoc
index 64e5377..3c9109f 100644
--- a/doc/src/snippets/code/doc_src_properties.qdoc
+++ b/doc/src/snippets/code/doc_src_properties.qdoc
@@ -8,7 +8,8 @@ Q_PROPERTY(type name
[SCRIPTABLE bool]
[STORED bool]
[USER bool]
- [CONSTANT])
+ [CONSTANT]
+ [FINAL])
//! [0]
diff --git a/src/corelib/kernel/qmetaobject.cpp b/src/corelib/kernel/qmetaobject.cpp
index fee2da9..3b09061 100644
--- a/src/corelib/kernel/qmetaobject.cpp
+++ b/src/corelib/kernel/qmetaobject.cpp
@@ -161,7 +161,8 @@ enum PropertyFlags {
ResolveUser = 0x00200000,
Notify = 0x00400000,
Dynamic = 0x00800000,
- Constant = 0x00000400
+ Constant = 0x00000400,
+ Final = 0x00000800
};
enum MethodFlags {
@@ -2466,6 +2467,20 @@ bool QMetaProperty::isConstant() const
}
/*!
+ Returns true if the property is final; otherwise returns false.
+
+ A property is final if the \c{Q_PROPERTY()}'s \c FINAL attribute
+ is set.
+*/
+bool QMetaProperty::isFinal() const
+{
+ if (!mobj)
+ return false;
+ int flags = mobj->d.data[handle + 2];
+ return flags & Final;
+}
+
+/*!
\obsolete
Returns true if the property is editable for the given \a object;
diff --git a/src/corelib/kernel/qmetaobject.h b/src/corelib/kernel/qmetaobject.h
index 73b52a9..bd47582 100644
--- a/src/corelib/kernel/qmetaobject.h
+++ b/src/corelib/kernel/qmetaobject.h
@@ -189,6 +189,7 @@ public:
bool isUser(const QObject *obj = 0) const;
bool isDynamic() const;
bool isConstant() const;
+ bool isFinal() const;
bool isFlagType() const;
bool isEnumType() const;
diff --git a/src/tools/moc/generator.cpp b/src/tools/moc/generator.cpp
index e4086e6..fbc434d 100644
--- a/src/tools/moc/generator.cpp
+++ b/src/tools/moc/generator.cpp
@@ -68,7 +68,8 @@ enum PropertyFlags {
ResolveUser = 0x00200000,
Notify = 0x00400000,
Dynamic = 0x00800000,
- Constant = 0x00000400
+ Constant = 0x00000400,
+ Final = 0x00000800
};
enum MethodFlags {
AccessPrivate = 0x00,
@@ -601,6 +602,8 @@ void Generator::generateProperties()
if (p.constant)
flags |= Constant;
+ if (p.final)
+ flags |= Final;
fprintf(out, " %4d, %4d, ",
strreg(p.name),
diff --git a/src/tools/moc/moc.cpp b/src/tools/moc/moc.cpp
index 66012ca..aa11d0e 100644
--- a/src/tools/moc/moc.cpp
+++ b/src/tools/moc/moc.cpp
@@ -912,6 +912,9 @@ void Moc::parseProperty(ClassDef *def)
if (l[0] == 'C' && l == "CONSTANT") {
propDef.constant = true;
continue;
+ } else if(l[0] == 'F' && l == "FINAL") {
+ propDef.final = true;
+ continue;
}
QByteArray v, v2;
diff --git a/src/tools/moc/moc.h b/src/tools/moc/moc.h
index 494d53e..767f84e 100644
--- a/src/tools/moc/moc.h
+++ b/src/tools/moc/moc.h
@@ -115,10 +115,11 @@ struct FunctionDef
struct PropertyDef
{
- PropertyDef():notifyId(-1), constant(false), gspec(ValueSpec){}
+ PropertyDef():notifyId(-1), constant(false), final(false), gspec(ValueSpec){}
QByteArray name, type, read, write, reset, designable, scriptable, editable, stored, user, notify;
int notifyId;
bool constant;
+ bool final;
enum Specification { ValueSpec, ReferenceSpec, PointerSpec };
Specification gspec;
bool stdCppSet() const {
diff --git a/tests/auto/qmetaobject/tst_qmetaobject.cpp b/tests/auto/qmetaobject/tst_qmetaobject.cpp
index f4cff2b..ac2858c 100644
--- a/tests/auto/qmetaobject/tst_qmetaobject.cpp
+++ b/tests/auto/qmetaobject/tst_qmetaobject.cpp
@@ -109,6 +109,7 @@ class tst_QMetaObject : public QObject
Q_PROPERTY(MyStruct value7 READ value7 WRITE setVal7 NOTIFY value7Changed)
Q_PROPERTY(int value8 READ value8 NOTIFY value8Changed)
Q_PROPERTY(int value9 READ value9 CONSTANT)
+ Q_PROPERTY(int value10 READ value10 FINAL)
public:
enum EnumType { EnumType1 };
@@ -140,6 +141,8 @@ public:
int value9() const { return 1; }
+ int value10() const { return 1; }
+
QList value4;
QVariantList value5;
@@ -163,6 +166,7 @@ private slots:
void checkScope();
void propertyNotify();
void propertyConstant();
+ void propertyFinal();
void stdSet();
void classInfo();
@@ -802,6 +806,19 @@ void tst_QMetaObject::propertyConstant()
QVERIFY(prop.isConstant());
}
+void tst_QMetaObject::propertyFinal()
+{
+ const QMetaObject *mo = metaObject();
+
+ QMetaProperty prop = mo->property(mo->indexOfProperty("value10"));
+ QVERIFY(prop.isValid());
+ QVERIFY(prop.isFinal());
+
+ prop = mo->property(mo->indexOfProperty("value9"));
+ QVERIFY(prop.isValid());
+ QVERIFY(!prop.isFinal());
+}
+
class ClassInfoTestObjectA : public QObject
{
Q_OBJECT
--
cgit v0.12
From 354b13b99f836ff0bc03b502fdbefed85f416d33 Mon Sep 17 00:00:00 2001
From: Aaron Kennedy
Date: Thu, 30 Jul 2009 10:18:05 +1000
Subject: extend the QObjectPrivate::connectedSignals bitfield to make space
for all the required NOTIFY signals we need for QML bindings. An additional
internal function QMetaObject::isConnected() allows to query the bits, or you
use connectedSignals[0] if you know that the signal in question has a
QMetaObject::indexOfSignal() < 32.
---
src/corelib/animation/qvariantanimation.cpp | 2 +-
src/corelib/kernel/qobject.cpp | 77 +++++++++++++++++++++++------
src/corelib/kernel/qobject_p.h | 2 +-
src/corelib/kernel/qobjectdefs.h | 3 ++
src/gui/graphicsview/qgraphicsitem.cpp | 2 +-
src/gui/graphicsview/qgraphicsscene.cpp | 8 +--
6 files changed, 72 insertions(+), 22 deletions(-)
diff --git a/src/corelib/animation/qvariantanimation.cpp b/src/corelib/animation/qvariantanimation.cpp
index 48e5ec1..fdd98c2 100644
--- a/src/corelib/animation/qvariantanimation.cpp
+++ b/src/corelib/animation/qvariantanimation.cpp
@@ -267,7 +267,7 @@ void QVariantAnimationPrivate::setCurrentValueForProgress(const qreal progress)
localProgress);
qSwap(currentValue, ret);
q->updateCurrentValue(currentValue);
- if ((connectedSignals & changedSignalMask) && currentValue != ret) {
+ if ((connectedSignals[0] & changedSignalMask) && currentValue != ret) {
//the value has changed
emit q->valueChanged(currentValue);
}
diff --git a/src/corelib/kernel/qobject.cpp b/src/corelib/kernel/qobject.cpp
index 6503ab0..e5cc375 100644
--- a/src/corelib/kernel/qobject.cpp
+++ b/src/corelib/kernel/qobject.cpp
@@ -139,7 +139,8 @@ QObjectPrivate::QObjectPrivate(int version)
receiveChildEvents = true;
postedEvents = 0;
extraData = 0;
- connectedSignals = 0;
+ for (uint i = 0; i < (sizeof connectedSignals / sizeof connectedSignals[0]); ++i)
+ connectedSignals[i] = 0;
inEventHandler = false;
inThreadChangeEvent = false;
deleteWatch = 0;
@@ -2849,10 +2850,16 @@ bool QMetaObject::connect(const QObject *sender, int signal_index,
s->d_func()->addConnection(signal_index, c);
- if (signal_index < 0)
- sender->d_func()->connectedSignals = ~0u;
- else if (signal_index < 32)
- sender->d_func()->connectedSignals |= (1 << signal_index);
+ if (signal_index < 0) {
+ for (uint i = 0; i < (sizeof sender->d_func()->connectedSignals
+ / sizeof sender->d_func()->connectedSignals[0] ); ++i)
+ sender->d_func()->connectedSignals[i] = ~0u;
+ } else if (signal_index < (int)sizeof sender->d_func()->connectedSignals * 8) {
+ uint n = (signal_index / (8 * sizeof sender->d_func()->connectedSignals[0]));
+ sender->d_func()->connectedSignals[n] |= (1 << (signal_index - n * 8
+ * sizeof sender->d_func()->connectedSignals[0]));
+ }
+
return true;
}
@@ -3192,11 +3199,12 @@ void QMetaObject::activate(QObject *sender, int from_signal_index, int to_signal
*/
void QMetaObject::activate(QObject *sender, int signal_index, void **argv)
{
- if (signal_index < 32
+ if (signal_index < (int)sizeof(sender->d_func()->connectedSignals) * 8
&& !qt_signal_spy_callback_set.signal_begin_callback
&& !qt_signal_spy_callback_set.signal_end_callback) {
- uint signal_mask = 1 << signal_index;
- if ((sender->d_func()->connectedSignals & signal_mask) == 0)
+ uint n = (signal_index / (8 * sizeof sender->d_func()->connectedSignals[0]));
+ uint m = 1 << (signal_index - n * 8 * sizeof sender->d_func()->connectedSignals[0]);
+ if ((sender->d_func()->connectedSignals[n] & m) == 0)
// nothing connected to these signals, and no spy
return;
}
@@ -3209,11 +3217,12 @@ void QMetaObject::activate(QObject *sender, const QMetaObject *m, int local_sign
void **argv)
{
int signal_index = m->methodOffset() + local_signal_index;
- if (signal_index < 32
+ if (signal_index < (int)sizeof(sender->d_func()->connectedSignals) * 8
&& !qt_signal_spy_callback_set.signal_begin_callback
&& !qt_signal_spy_callback_set.signal_end_callback) {
- uint signal_mask = 1 << signal_index;
- if ((sender->d_func()->connectedSignals & signal_mask) == 0)
+ uint n = (signal_index / (8 * sizeof sender->d_func()->connectedSignals[0]));
+ uint m = 1 << (signal_index - n * 8 * sizeof sender->d_func()->connectedSignals[0]);
+ if ((sender->d_func()->connectedSignals[n] & m) == 0)
// nothing connected to these signals, and no spy
return;
}
@@ -3225,21 +3234,59 @@ void QMetaObject::activate(QObject *sender, const QMetaObject *m, int local_sign
void QMetaObject::activate(QObject *sender, const QMetaObject *m,
int from_local_signal_index, int to_local_signal_index, void **argv)
{
+ Q_ASSERT(from_local_signal_index <= to_local_signal_index);
int offset = m->methodOffset();
int from_signal_index = offset + from_local_signal_index;
int to_signal_index = offset + to_local_signal_index;
- if (to_signal_index < 32
+
+ if (to_signal_index < (int)sizeof(sender->d_func()->connectedSignals) * 8
&& !qt_signal_spy_callback_set.signal_begin_callback
&& !qt_signal_spy_callback_set.signal_end_callback) {
- uint signal_mask = (1 << (to_signal_index + 1)) - 1;
- signal_mask ^= (1 << from_signal_index) - 1;
- if ((sender->d_func()->connectedSignals & signal_mask) == 0)
+
+ uint n = (from_signal_index / (8 * sizeof sender->d_func()->connectedSignals[0]));
+ uint m = 1 << (from_signal_index - n * 8 * sizeof sender->d_func()->connectedSignals[0]);
+ uint nt = (to_signal_index / (8 * sizeof sender->d_func()->connectedSignals[0]));
+ uint mt = 1 << (to_signal_index - n * 8 * sizeof sender->d_func()->connectedSignals[0]);
+ bool connected = false;
+ quint32 *connectedSignals = sender->d_func()->connectedSignals;
+ for (uint i = 0; !connected && i < (sizeof sender->d_func()->connectedSignals
+ / sizeof sender->d_func()->connectedSignals[0]); ++i) {
+ uint mask = 0;
+ if (i > n)
+ mask = ~0u;
+ else if (i == n)
+ mask = ~(m -1);
+ if (i > nt)
+ mask = 0;
+ else if (i == nt)
+ mask &= (mt << 1) - 1;
+ connected = connectedSignals[i] & mask;
+ }
+ if (!connected)
// nothing connected to these signals, and no spy
return;
}
activate(sender, from_signal_index, to_signal_index, argv);
}
+/*! \internal
+
+ Returns true if the signal with index \a signal_index from object \a sender is connected.
+ Signals with indices above a certain range are always considered connected (see connectedSignals
+ in QObjectPrivate). If a signal spy is installed, all signals are considered connected.
+*/
+bool QMetaObject::isConnected(QObject *sender, int signal_index) {
+ if (signal_index < (int)sizeof(sender->d_func()->connectedSignals) * 8
+ && !qt_signal_spy_callback_set.signal_begin_callback
+ && !qt_signal_spy_callback_set.signal_end_callback) {
+ uint n = (signal_index / (8 * sizeof sender->d_func()->connectedSignals[0]));
+ uint m = 1 << (signal_index - n * 8 * sizeof sender->d_func()->connectedSignals[0]);
+ if ((sender->d_func()->connectedSignals[n] & m) == 0)
+ // nothing connected to these signals, and no spy
+ return false;
+ }
+ return true;
+}
/*****************************************************************************
Properties
diff --git a/src/corelib/kernel/qobject_p.h b/src/corelib/kernel/qobject_p.h
index 07c397f..6a20040 100644
--- a/src/corelib/kernel/qobject_p.h
+++ b/src/corelib/kernel/qobject_p.h
@@ -140,7 +140,7 @@ public:
QList propertyValues;
};
ExtraData *extraData;
- mutable quint32 connectedSignals;
+ mutable quint32 connectedSignals[2];
QString objectName;
diff --git a/src/corelib/kernel/qobjectdefs.h b/src/corelib/kernel/qobjectdefs.h
index 9187765..300e9fa 100644
--- a/src/corelib/kernel/qobjectdefs.h
+++ b/src/corelib/kernel/qobjectdefs.h
@@ -334,6 +334,9 @@ struct Q_CORE_EXPORT QMetaObject
static void activate(QObject *sender, int from_signal_index, int to_signal_index, void **argv);
static void activate(QObject *sender, const QMetaObject *, int local_signal_index, void **argv);
static void activate(QObject *sender, const QMetaObject *, int from_local_signal_index, int to_local_signal_index, void **argv);
+
+ static bool isConnected(QObject *sender, int signal_index);
+
// internal guarded pointers
static void addGuard(QObject **ptr);
static void removeGuard(QObject **ptr);
diff --git a/src/gui/graphicsview/qgraphicsitem.cpp b/src/gui/graphicsview/qgraphicsitem.cpp
index 6770206..20f0bb9 100644
--- a/src/gui/graphicsview/qgraphicsitem.cpp
+++ b/src/gui/graphicsview/qgraphicsitem.cpp
@@ -6462,7 +6462,7 @@ void QGraphicsItem::prepareGeometryChange()
// if someone is connected to the changed signal or the scene has no views.
// Note that this has to be done *after* markDirty to ensure that
// _q_processDirtyItems is called before _q_emitUpdated.
- if ((scenePrivate->connectedSignals & scenePrivate->changedSignalMask)
+ if ((scenePrivate->connectedSignals[0] & scenePrivate->changedSignalMask)
|| scenePrivate->views.isEmpty()) {
if (d_ptr->hasTranslateOnlySceneTransform()) {
d_ptr->scene->update(boundingRect().translated(d_ptr->sceneTransform.dx(),
diff --git a/src/gui/graphicsview/qgraphicsscene.cpp b/src/gui/graphicsview/qgraphicsscene.cpp
index a846cf6..da4a347 100644
--- a/src/gui/graphicsview/qgraphicsscene.cpp
+++ b/src/gui/graphicsview/qgraphicsscene.cpp
@@ -344,7 +344,7 @@ void QGraphicsScenePrivate::_q_emitUpdated()
// the optimization that items send updates directly to the views, but it
// needs to happen in order to keep compatibility with the behavior from
// Qt 4.4 and backward.
- if (connectedSignals & changedSignalMask) {
+ if (connectedSignals[0] & changedSignalMask) {
for (int i = 0; i < views.size(); ++i) {
QGraphicsView *view = views.at(i);
if (!view->d_func()->connectedToScene) {
@@ -2899,7 +2899,7 @@ void QGraphicsScene::update(const QRectF &rect)
// Check if anyone's connected; if not, we can send updates directly to
// the views. Otherwise or if there are no views, use old behavior.
- bool directUpdates = !(d->connectedSignals & d->changedSignalMask) && !d->views.isEmpty();
+ bool directUpdates = !(d->connectedSignals[0] & d->changedSignalMask) && !d->views.isEmpty();
if (rect.isNull()) {
d->updateAll = true;
d->updatedRects.clear();
@@ -4477,7 +4477,7 @@ void QGraphicsScenePrivate::markDirty(QGraphicsItem *item, const QRectF &rect, b
if (removingItemFromScene) {
// Note that this function can be called from the item's destructor, so
// do NOT call any virtual functions on it within this block.
- if ((connectedSignals & changedSignalMask) || views.isEmpty()) {
+ if ((connectedSignals[0] & changedSignalMask) || views.isEmpty()) {
// This block of code is kept for compatibility. Since 4.5, by default
// QGraphicsView does not connect the signal and we use the below
// method of delivering updates.
@@ -4623,7 +4623,7 @@ void QGraphicsScenePrivate::processDirtyItemsRecursive(QGraphicsItem *item, bool
// Process item.
if (item->d_ptr->dirty || item->d_ptr->paintedViewBoundingRectsNeedRepaint) {
- const bool useCompatUpdate = views.isEmpty() || (connectedSignals & changedSignalMask);
+ const bool useCompatUpdate = views.isEmpty() || (connectedSignals[0] & changedSignalMask);
const QRectF itemBoundingRect = adjustedItemBoundingRect(item);
if (useCompatUpdate && !itemIsUntransformable && qFuzzyIsNull(item->boundingRegionGranularity())) {
--
cgit v0.12
From 2d05bf654cfa27a7843e50aef181b0e27bfb1c12 Mon Sep 17 00:00:00 2001
From: Aaron Kennedy
Date: Thu, 30 Jul 2009 10:52:40 +1000
Subject: Allow retrieval of interface IId from class type.
This method is necessary for QML to support Qt interfaces, but probably
shouldn't be used otherwise.
---
src/corelib/kernel/qobject.h | 10 ++++++++++
tests/auto/qobject/tst_qobject.cpp | 11 +++++++++++
2 files changed, 21 insertions(+)
diff --git a/src/corelib/kernel/qobject.h b/src/corelib/kernel/qobject.h
index 1fb216b..4715626 100644
--- a/src/corelib/kernel/qobject.h
+++ b/src/corelib/kernel/qobject.h
@@ -379,6 +379,9 @@ inline QList qFindChildren(const QObject *o, const QRegExp &re)
#endif // Q_MOC_RUN
+template inline const char * qobject_interface_iid()
+{ return 0; }
+
template inline T qobject_cast_helper(QObject *object, T)
{ return static_cast(((T)0)->staticMetaObject.cast(object)); }
@@ -395,6 +398,8 @@ inline T qobject_cast(const QObject *object)
#ifndef Q_MOC_RUN
# define Q_DECLARE_INTERFACE(IFace, IId) \
+ template <> inline const char *qobject_interface_iid() \
+ { return IId; } \
template <> inline IFace *qobject_cast_helper(QObject *object, IFace *) \
{ return (IFace *)(object ? object->qt_metacast(IId) : 0); } \
template <> inline IFace *qobject_cast_helper(const QObject *object, IFace *) \
@@ -458,8 +463,13 @@ inline T qobject_cast(const QObject *object)
}
+template inline const char * qobject_interface_iid()
+{ return 0; }
+
#ifndef Q_MOC_RUN
# define Q_DECLARE_INTERFACE(IFace, IId) \
+ template <> inline const char *qobject_interface_iid() \
+ { return IId; } \
template <> inline IFace *qobject_cast(QObject *object) \
{ return reinterpret_cast((object ? object->qt_metacast(IId) : 0)); } \
template <> inline IFace *qobject_cast(const QObject *object) \
diff --git a/tests/auto/qobject/tst_qobject.cpp b/tests/auto/qobject/tst_qobject.cpp
index 4f25af6..3df83d7 100644
--- a/tests/auto/qobject/tst_qobject.cpp
+++ b/tests/auto/qobject/tst_qobject.cpp
@@ -118,6 +118,7 @@ private slots:
void connectToSender();
void qobjectConstCast();
void uniqConnection();
+ void interfaceIid();
protected:
};
@@ -2887,5 +2888,15 @@ void tst_QObject::uniqConnection()
delete r2;
}
+void tst_QObject::interfaceIid()
+{
+ QCOMPARE(QByteArray(qobject_interface_iid()),
+ QByteArray(Bleh_iid));
+ QCOMPARE(QByteArray(qobject_interface_iid()),
+ QByteArray("com.qtest.foobar"));
+ QCOMPARE(QByteArray(qobject_interface_iid()),
+ QByteArray());
+}
+
QTEST_MAIN(tst_QObject)
#include "tst_qobject.moc"
--
cgit v0.12
From e0119bd179c01b380521fc238229ad8056ca11bb Mon Sep 17 00:00:00 2001
From: Aaron Kennedy
Date: Thu, 30 Jul 2009 11:04:03 +1000
Subject: Add non-threadsafe QGuard class
Cherry pick of 4031c0f0613090d70cd1fcacfc5b8316b12eb14e
---
src/corelib/kernel/kernel.pri | 6 +-
src/corelib/kernel/qguard.cpp | 26 +++++++
src/corelib/kernel/qguard_p.h | 151 +++++++++++++++++++++++++++++++++++++++++
src/corelib/kernel/qobject.cpp | 18 ++++-
src/corelib/kernel/qobject_p.h | 2 +
5 files changed, 200 insertions(+), 3 deletions(-)
create mode 100644 src/corelib/kernel/qguard.cpp
create mode 100644 src/corelib/kernel/qguard_p.h
diff --git a/src/corelib/kernel/kernel.pri b/src/corelib/kernel/kernel.pri
index 8759578..a7f954a 100644
--- a/src/corelib/kernel/kernel.pri
+++ b/src/corelib/kernel/kernel.pri
@@ -32,7 +32,8 @@ HEADERS += \
kernel/qsharedmemory_p.h \
kernel/qsystemsemaphore.h \
kernel/qsystemsemaphore_p.h \
- kernel/qfunctions_p.h
+ kernel/qfunctions_p.h \
+ kernel/qguard_p.h
SOURCES += \
kernel/qabstracteventdispatcher.cpp \
@@ -54,7 +55,8 @@ SOURCES += \
kernel/qcoreglobaldata.cpp \
kernel/qsharedmemory.cpp \
kernel/qsystemsemaphore.cpp \
- kernel/qpointer.cpp
+ kernel/qpointer.cpp \
+ kernel/qguard.cpp
win32 {
SOURCES += \
diff --git a/src/corelib/kernel/qguard.cpp b/src/corelib/kernel/qguard.cpp
new file mode 100644
index 0000000..c61be00
--- /dev/null
+++ b/src/corelib/kernel/qguard.cpp
@@ -0,0 +1,26 @@
+#include "qguard_p.h"
+#include
+
+void q_guard_addGuard(QGuard *g)
+{
+ QObjectPrivate *p = QObjectPrivate::get(g->o);
+ if (p->wasDeleted) {
+ qWarning("QGuard: cannot add guard to deleted object");
+ g->o = 0;
+ return;
+ }
+
+ g->next = p->objectGuards;
+ p->objectGuards = g;
+ g->prev = &p->objectGuards;
+ if (g->next)
+ g->next->prev = &g->next;
+}
+
+void q_guard_removeGuard(QGuard *g)
+{
+ *g->prev = g->next;
+ g->next = 0;
+ g->prev = 0;
+}
+
diff --git a/src/corelib/kernel/qguard_p.h b/src/corelib/kernel/qguard_p.h
new file mode 100644
index 0000000..7236ed6
--- /dev/null
+++ b/src/corelib/kernel/qguard_p.h
@@ -0,0 +1,151 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtCore module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://www.qtsoftware.com/contact.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QGUARD_P_H
+#define QGUARD_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists for the convenience
+// of qapplication_*.cpp, qwidget*.cpp and qfiledialog.cpp. This header
+// file may change from version to version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include "QtCore/qglobal.h"
+
+QT_BEGIN_NAMESPACE
+
+class QObject;
+template
+class QGuard
+{
+ QObject *o;
+ QGuard *next;
+ QGuard **prev;
+ friend void q_guard_addGuard(QGuard *);
+ friend void q_guard_removeGuard(QGuard *);
+ friend class QObjectPrivate;
+public:
+ inline QGuard();
+ inline QGuard(T *);
+ inline QGuard(const QGuard &);
+ inline virtual ~QGuard();
+
+ inline QGuard &operator=(const QGuard &o);
+ inline QGuard &operator=(T *);
+
+ inline bool isNull() const
+ { return !o; }
+
+ inline T* operator->() const
+ { return static_cast(const_cast(o)); }
+ inline T& operator*() const
+ { return *static_cast(const_cast(o)); }
+ inline operator T*() const
+ { return static_cast(const_cast(o)); }
+ inline T* data() const
+ { return static_cast(const_cast(o)); }
+
+protected:
+ virtual void objectDestroyed(T *) {}
+};
+
+void Q_CORE_EXPORT q_guard_addGuard(QGuard *);
+void Q_CORE_EXPORT q_guard_removeGuard(QGuard *);
+
+template
+QGuard::QGuard()
+: o(0), next(0), prev(0)
+{
+}
+
+template
+QGuard::QGuard(T *g)
+: o(g), next(0), prev(0)
+{
+ if (o) q_guard_addGuard(reinterpret_cast *>(this));
+}
+
+template
+QGuard::QGuard(const QGuard &g)
+: o(g.o), next(0), prev(0)
+{
+ if (o) q_guard_addGuard(reinterpret_cast *>(this));
+}
+
+template
+QGuard::~QGuard()
+{
+ if (prev) q_guard_removeGuard(reinterpret_cast *>(this));
+ o = 0;
+}
+
+template
+QGuard &QGuard::operator=(const QGuard &g)
+{
+ if (g.o != o) {
+ if (prev)
+ q_guard_removeGuard(reinterpret_cast *>(this));
+ o = g.o;
+ if (o) q_guard_addGuard(reinterpret_cast *>(this));
+ }
+ return *this;
+}
+
+template
+inline QGuard &QGuard::operator=(T *g)
+{
+ if (g != o) {
+ if (prev)
+ q_guard_removeGuard(reinterpret_cast *>(this));
+ o = g;
+ if (o) q_guard_addGuard(reinterpret_cast *>(this));
+ }
+ return *this;
+}
+
+QT_END_NAMESPACE
+
+#endif // QGUARD_P_H
diff --git a/src/corelib/kernel/qobject.cpp b/src/corelib/kernel/qobject.cpp
index e5cc375..a1702d9 100644
--- a/src/corelib/kernel/qobject.cpp
+++ b/src/corelib/kernel/qobject.cpp
@@ -144,6 +144,7 @@ QObjectPrivate::QObjectPrivate(int version)
inEventHandler = false;
inThreadChangeEvent = false;
deleteWatch = 0;
+ objectGuards = 0;
hasGuards = false;
}
@@ -426,7 +427,22 @@ void QMetaObject::changeGuard(QObject **ptr, QObject *o)
*/
void QObjectPrivate::clearGuards(QObject *object)
{
- if (!QObjectPrivate::get(object)->hasGuards)
+ QObjectPrivate *priv = QObjectPrivate::get(object);
+ QGuard *guard = priv->objectGuards;
+ while (guard) {
+ guard->o = 0;
+ guard = guard->next;
+ }
+ while (priv->objectGuards) {
+ guard = priv->objectGuards;
+ guard->prev = 0;
+ if (guard->next) guard->next->prev = &priv->objectGuards;
+ priv->objectGuards = guard->next;
+ guard->next = 0;
+ guard->objectDestroyed(object);
+ }
+
+ if (!priv->hasGuards)
return;
GuardHash *hash = guardHash();
if (hash) {
diff --git a/src/corelib/kernel/qobject_p.h b/src/corelib/kernel/qobject_p.h
index 6a20040..335768c 100644
--- a/src/corelib/kernel/qobject_p.h
+++ b/src/corelib/kernel/qobject_p.h
@@ -60,6 +60,7 @@
#include "QtCore/qvector.h"
#include "QtCore/qreadwritelock.h"
#include "QtCore/qvariant.h"
+#include "qguard_p.h"
QT_BEGIN_NAMESPACE
@@ -174,6 +175,7 @@ public:
static void resetDeleteWatch(QObjectPrivate *d, int *oldWatch, int deleteWatch);
int *deleteWatch;
+ QGuard *objectGuards;
static QObjectPrivate *get(QObject *o) {
return o->d_func();
--
cgit v0.12
From 1fd84c7f3580650b3aeb78b55a52ba3e0a0b7d10 Mon Sep 17 00:00:00 2001
From: Aaron Kennedy
Date: Thu, 30 Jul 2009 11:06:24 +1000
Subject: removing Q_CORE_EXPORT for q_guard_addGuard() and
q_guard_removeGuard()
I made the functions inline instead and moved them to qobject_p.h
Reviewed-by: Aaron Kennedy
(cherry picked from commit fd27c5ac9670b56ccd60e8d8f6791237358f3633)
---
src/corelib/kernel/kernel.pri | 3 +--
src/corelib/kernel/qguard.cpp | 26 --------------------------
src/corelib/kernel/qguard_p.h | 3 +--
src/corelib/kernel/qobject_p.h | 24 ++++++++++++++++++++++++
4 files changed, 26 insertions(+), 30 deletions(-)
delete mode 100644 src/corelib/kernel/qguard.cpp
diff --git a/src/corelib/kernel/kernel.pri b/src/corelib/kernel/kernel.pri
index a7f954a..d479e05 100644
--- a/src/corelib/kernel/kernel.pri
+++ b/src/corelib/kernel/kernel.pri
@@ -55,8 +55,7 @@ SOURCES += \
kernel/qcoreglobaldata.cpp \
kernel/qsharedmemory.cpp \
kernel/qsystemsemaphore.cpp \
- kernel/qpointer.cpp \
- kernel/qguard.cpp
+ kernel/qpointer.cpp
win32 {
SOURCES += \
diff --git a/src/corelib/kernel/qguard.cpp b/src/corelib/kernel/qguard.cpp
deleted file mode 100644
index c61be00..0000000
--- a/src/corelib/kernel/qguard.cpp
+++ /dev/null
@@ -1,26 +0,0 @@
-#include "qguard_p.h"
-#include
-
-void q_guard_addGuard(QGuard *g)
-{
- QObjectPrivate *p = QObjectPrivate::get(g->o);
- if (p->wasDeleted) {
- qWarning("QGuard: cannot add guard to deleted object");
- g->o = 0;
- return;
- }
-
- g->next = p->objectGuards;
- p->objectGuards = g;
- g->prev = &p->objectGuards;
- if (g->next)
- g->next->prev = &g->next;
-}
-
-void q_guard_removeGuard(QGuard *g)
-{
- *g->prev = g->next;
- g->next = 0;
- g->prev = 0;
-}
-
diff --git a/src/corelib/kernel/qguard_p.h b/src/corelib/kernel/qguard_p.h
index 7236ed6..cbc9cca 100644
--- a/src/corelib/kernel/qguard_p.h
+++ b/src/corelib/kernel/qguard_p.h
@@ -54,6 +54,7 @@
//
#include "QtCore/qglobal.h"
+#include "private/qobject_p.h"
QT_BEGIN_NAMESPACE
@@ -92,8 +93,6 @@ protected:
virtual void objectDestroyed(T *) {}
};
-void Q_CORE_EXPORT q_guard_addGuard(QGuard *);
-void Q_CORE_EXPORT q_guard_removeGuard(QGuard *);
template
QGuard::QGuard()
diff --git a/src/corelib/kernel/qobject_p.h b/src/corelib/kernel/qobject_p.h
index 335768c..7e3e97d 100644
--- a/src/corelib/kernel/qobject_p.h
+++ b/src/corelib/kernel/qobject_p.h
@@ -182,6 +182,30 @@ public:
}
};
+inline void q_guard_addGuard(QGuard *g)
+{
+ QObjectPrivate *p = QObjectPrivate::get(g->o);
+ if (p->wasDeleted) {
+ qWarning("QGuard: cannot add guard to deleted object");
+ g->o = 0;
+ return;
+ }
+
+ g->next = p->objectGuards;
+ p->objectGuards = g;
+ g->prev = &p->objectGuards;
+ if (g->next)
+ g->next->prev = &g->next;
+}
+
+inline void q_guard_removeGuard(QGuard *g)
+{
+ if (g->next) g->next->prev = g->prev;
+ *g->prev = g->next;
+ g->next = 0;
+ g->prev = 0;
+}
+
Q_DECLARE_TYPEINFO(QObjectPrivate::Connection, Q_MOVABLE_TYPE);
Q_DECLARE_TYPEINFO(QObjectPrivate::Sender, Q_MOVABLE_TYPE);
--
cgit v0.12
From 0f2206eb9e8ed33f52632746ae5af99ea1ee9fd7 Mon Sep 17 00:00:00 2001
From: Erik Verbruggen
Date: Mon, 27 Jul 2009 16:35:38 +0200
Subject: Fixed missing forward declarations, which made gcc fail to compile
anything that included qobject.h
Reviewed-by: Thomas Hartmann
(cherry picked from commit cc287101308fa606eb4de2597b5309c8099654c3)
---
src/corelib/kernel/qguard_p.h | 9 ++++++++-
src/corelib/kernel/qobject_p.h | 2 +-
2 files changed, 9 insertions(+), 2 deletions(-)
diff --git a/src/corelib/kernel/qguard_p.h b/src/corelib/kernel/qguard_p.h
index cbc9cca..6af01ac 100644
--- a/src/corelib/kernel/qguard_p.h
+++ b/src/corelib/kernel/qguard_p.h
@@ -54,7 +54,6 @@
//
#include "QtCore/qglobal.h"
-#include "private/qobject_p.h"
QT_BEGIN_NAMESPACE
@@ -93,6 +92,14 @@ protected:
virtual void objectDestroyed(T *) {}
};
+QT_END_NAMESPACE
+
+#include "private/qobject_p.h"
+
+QT_BEGIN_NAMESPACE
+
+inline void q_guard_addGuard(QGuard *);
+inline void q_guard_removeGuard(QGuard *);
template
QGuard::QGuard()
diff --git a/src/corelib/kernel/qobject_p.h b/src/corelib/kernel/qobject_p.h
index 7e3e97d..54c98ad 100644
--- a/src/corelib/kernel/qobject_p.h
+++ b/src/corelib/kernel/qobject_p.h
@@ -60,7 +60,7 @@
#include "QtCore/qvector.h"
#include "QtCore/qreadwritelock.h"
#include "QtCore/qvariant.h"
-#include "qguard_p.h"
+#include "private/qguard_p.h"
QT_BEGIN_NAMESPACE
--
cgit v0.12
From 101c748b14f085a49dd565633ad4b12831a39556 Mon Sep 17 00:00:00 2001
From: Aaron Kennedy
Date: Thu, 30 Jul 2009 11:52:53 +1000
Subject: Autotest for QGuard
---
tests/auto/qguard/qguard.pro | 2 +
tests/auto/qguard/tst_qguard.cpp | 350 +++++++++++++++++++++++++++++++++++++++
2 files changed, 352 insertions(+)
create mode 100644 tests/auto/qguard/qguard.pro
create mode 100644 tests/auto/qguard/tst_qguard.cpp
diff --git a/tests/auto/qguard/qguard.pro b/tests/auto/qguard/qguard.pro
new file mode 100644
index 0000000..f249dde
--- /dev/null
+++ b/tests/auto/qguard/qguard.pro
@@ -0,0 +1,2 @@
+load(qttest_p4)
+SOURCES += tst_qguard.cpp
diff --git a/tests/auto/qguard/tst_qguard.cpp b/tests/auto/qguard/tst_qguard.cpp
new file mode 100644
index 0000000..96d1b60
--- /dev/null
+++ b/tests/auto/qguard/tst_qguard.cpp
@@ -0,0 +1,350 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://www.qtsoftware.com/contact.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+// NOTE: This is identical to the QPointer autotest
+
+#include
+
+#include
+#include
+#include
+#include
+
+class tst_QGuard : public QObject
+{
+ Q_OBJECT
+public:
+ tst_QGuard();
+ ~tst_QGuard();
+
+ inline tst_QGuard *me() const
+ { return const_cast(this); }
+
+public slots:
+ void initTestCase();
+ void cleanupTestCase();
+ void init();
+ void cleanup();
+private slots:
+ void constructors();
+ void destructor();
+ void assignment_operators();
+ void equality_operators();
+ void isNull();
+ void dereference_operators();
+ void disconnect();
+ void castDuringDestruction();
+ void data() const;
+ void dataSignature() const;
+};
+
+tst_QGuard::tst_QGuard()
+{ }
+
+tst_QGuard::~tst_QGuard()
+{ }
+
+void tst_QGuard::initTestCase()
+{ }
+
+void tst_QGuard::cleanupTestCase()
+{ }
+
+void tst_QGuard::init()
+{ }
+
+void tst_QGuard::cleanup()
+{ }
+
+void tst_QGuard::constructors()
+{
+ QGuard p1;
+ QGuard p2(this);
+ QGuard p3(p2);
+ QCOMPARE(p1, QGuard(0));
+ QCOMPARE(p2, QGuard(this));
+ QCOMPARE(p3, QGuard(this));
+}
+
+void tst_QGuard::destructor()
+{
+ QObject *object = new QObject;
+ QGuard p = object;
+ QCOMPARE(p, QGuard(object));
+ delete object;
+ QCOMPARE(p, QGuard(0));
+}
+
+void tst_QGuard::assignment_operators()
+{
+ QGuard p1;
+ QGuard p2;
+
+ p1 = this;
+ p2 = p1;
+
+ QCOMPARE(p1, QGuard(this));
+ QCOMPARE(p2, QGuard(this));
+ QCOMPARE(p1, QGuard(p2));
+
+ p1 = 0;
+ p2 = p1;
+ QCOMPARE(p1, QGuard(0));
+ QCOMPARE(p2, QGuard(0));
+ QCOMPARE(p1, QGuard(p2));
+
+ QObject *object = new QObject;
+
+ p1 = object;
+ p2 = p1;
+ QCOMPARE(p1, QGuard(object));
+ QCOMPARE(p2, QGuard(object));
+ QCOMPARE(p1, QGuard(p2));
+
+ delete object;
+ QCOMPARE(p1, QGuard(0));
+ QCOMPARE(p2, QGuard(0));
+ QCOMPARE(p1, QGuard(p2));
+}
+
+void tst_QGuard::equality_operators()
+{
+ QGuard p1;
+ QGuard p2;
+
+ QVERIFY(p1 == p2);
+
+ QObject *object = 0;
+ QWidget *widget = 0;
+
+ p1 = object;
+ QVERIFY(p1 == p2);
+ QVERIFY(p1 == object);
+ p2 = object;
+ QVERIFY(p2 == p1);
+ QVERIFY(p2 == object);
+
+ p1 = this;
+ QVERIFY(p1 != p2);
+ p2 = p1;
+ QVERIFY(p1 == p2);
+
+ // compare to zero
+ p1 = 0;
+ QVERIFY(p1 == 0);
+ QVERIFY(0 == p1);
+ QVERIFY(p2 != 0);
+ QVERIFY(0 != p2);
+ QVERIFY(p1 == object);
+ QVERIFY(object == p1);
+ QVERIFY(p2 != object);
+ QVERIFY(object != p2);
+ QVERIFY(p1 == widget);
+ QVERIFY(widget == p1);
+ QVERIFY(p2 != widget);
+ QVERIFY(widget != p2);
+}
+
+void tst_QGuard::isNull()
+{
+ QGuard p1;
+ QVERIFY(p1.isNull());
+ p1 = this;
+ QVERIFY(!p1.isNull());
+ p1 = 0;
+ QVERIFY(p1.isNull());
+}
+
+void tst_QGuard::dereference_operators()
+{
+ QGuard p1 = this;
+
+ QObject *object = p1->me();
+ QVERIFY(object == this);
+
+ QObject &ref = *p1;
+ QVERIFY(&ref == this);
+
+ object = static_cast(p1);
+ QVERIFY(object == this);
+}
+
+void tst_QGuard::disconnect()
+{
+ QGuard p1 = new QObject;
+ QVERIFY(!p1.isNull());
+ p1->disconnect();
+ QVERIFY(!p1.isNull());
+ delete static_cast(p1);
+ QVERIFY(p1.isNull());
+}
+
+class ChildObject : public QObject
+{
+ QGuard guardedPointer;
+
+public:
+ ChildObject(QObject *parent)
+ : QObject(parent), guardedPointer(parent)
+ { }
+ ~ChildObject();
+};
+
+ChildObject::~ChildObject()
+{
+ QCOMPARE(static_cast(guardedPointer), static_cast(0));
+ QCOMPARE(qobject_cast(guardedPointer), static_cast(0));
+}
+
+class ChildWidget : public QWidget
+{
+ QGuard guardedPointer;
+
+public:
+ ChildWidget(QWidget *parent)
+ : QWidget(parent), guardedPointer(parent)
+ { }
+ ~ChildWidget();
+};
+
+ChildWidget::~ChildWidget()
+{
+ QCOMPARE(static_cast(guardedPointer), static_cast(0));
+ QCOMPARE(qobject_cast(guardedPointer), static_cast(0));
+}
+
+class DerivedChild;
+
+class DerivedParent : public QObject
+{
+ Q_OBJECT
+
+ DerivedChild *derivedChild;
+
+public:
+ DerivedParent();
+ ~DerivedParent();
+};
+
+class DerivedChild : public QObject
+{
+ Q_OBJECT
+
+ DerivedParent *parentPointer;
+ QGuard guardedParentPointer;
+
+public:
+ DerivedChild(DerivedParent *parent)
+ : QObject(parent), parentPointer(parent), guardedParentPointer(parent)
+ { }
+ ~DerivedChild();
+};
+
+DerivedParent::DerivedParent()
+ : QObject()
+{
+ derivedChild = new DerivedChild(this);
+}
+
+DerivedParent::~DerivedParent()
+{
+ delete derivedChild;
+}
+
+DerivedChild::~DerivedChild()
+{
+ QCOMPARE(static_cast(guardedParentPointer), parentPointer);
+ QCOMPARE(qobject_cast(guardedParentPointer), parentPointer);
+}
+
+void tst_QGuard::castDuringDestruction()
+{
+ {
+ QObject *parentObject = new QObject();
+ (void) new ChildObject(parentObject);
+ delete parentObject;
+ }
+
+ {
+ QWidget *parentWidget = new QWidget();
+ (void) new ChildWidget(parentWidget);
+ delete parentWidget;
+ }
+
+ {
+ delete new DerivedParent();
+ }
+}
+
+void tst_QGuard::data() const
+{
+ /* Check value of a default constructed object. */
+ {
+ QGuard p;
+ QCOMPARE(p.data(), static_cast(0));
+ }
+
+ /* Check value of a default constructed object. */
+ {
+ QObject *const object = new QObject();
+ QGuard p(object);
+ QCOMPARE(p.data(), object);
+ }
+}
+
+void tst_QGuard::dataSignature() const
+{
+ /* data() should be const. */
+ {
+ const QGuard p;
+ p.data();
+ }
+
+ /* The return type should be T. */
+ {
+ const QGuard p;
+ /* If the types differs, the QCOMPARE will fail to instansiate. */
+ QCOMPARE(p.data(), static_cast(0));
+ }
+}
+
+QTEST_MAIN(tst_QGuard)
+#include "tst_qguard.moc"
--
cgit v0.12