From 0ef673efe8bf381e1aa0202752deac27e86ada53 Mon Sep 17 00:00:00 2001 From: Caroline Chao Date: Tue, 3 Sep 2013 14:03:21 +0200 Subject: qmlplugindump: Add support for composite types Task-number: QTBUG-33106 Change-Id: I80fc817eb59256e860f3fdd591104930688ef84c Reviewed-by: Shawn Rutledge --- tools/qmlplugindump/main.cpp | 193 +++++++++++++++++++++++++++++++------------ 1 file changed, 139 insertions(+), 54 deletions(-) (limited to 'tools/qmlplugindump/main.cpp') diff --git a/tools/qmlplugindump/main.cpp b/tools/qmlplugindump/main.cpp index ead6392d7f..f312604e17 100644 --- a/tools/qmlplugindump/main.cpp +++ b/tools/qmlplugindump/main.cpp @@ -140,6 +140,9 @@ public: */ static QHash > qmlTypesByCppName; +// No different versioning possible for a composite type. +static QMap qmlTypesByCompositeName; + static QHash cppToId; /* Takes a C++ type name, such as Qt::LayoutDirection or QString and @@ -191,8 +194,9 @@ QSet collectReachableMetaObjects(QQmlEngine *engine, const if (ty->isExtendedType()) extensions[ty->typeName()].insert(ty->metaObject()->className()); collectReachableMetaObjects(ty, &metas); + } else { + qmlTypesByCompositeName[ty->elementName()] = ty; } - // TODO actually handle composite types } // Adjust exports of the base object if there are extensions. @@ -288,6 +292,135 @@ public: relocatableModuleUri = uri; } + const QString getExportString(QString qmlTyName, int majorVersion, int minorVersion) + { + if (qmlTyName.startsWith(relocatableModuleUri + QLatin1Char('/'))) { + qmlTyName.remove(0, relocatableModuleUri.size() + 1); + } + if (qmlTyName.startsWith("./")) { + qmlTyName.remove(0, 2); + } + if (qmlTyName.startsWith("/")) { + qmlTyName.remove(0, 1); + } + const QString exportString = enquote( + QString("%1 %2.%3").arg( + qmlTyName, + QString::number(majorVersion), + QString::number(minorVersion))); + return exportString; + } + + void writeMetaContent(const QMetaObject *meta) + { + QSet implicitSignals; + for (int index = meta->propertyOffset(); index < meta->propertyCount(); ++index) { + const QMetaProperty &property = meta->property(index); + dump(property); + implicitSignals.insert(QString("%1Changed").arg(QString::fromUtf8(property.name()))); + } + + if (meta == &QObject::staticMetaObject) { + // for QObject, hide deleteLater() and onDestroyed + for (int index = meta->methodOffset(); index < meta->methodCount(); ++index) { + QMetaMethod method = meta->method(index); + QByteArray signature = method.methodSignature(); + if (signature == QByteArrayLiteral("destroyed(QObject*)") + || signature == QByteArrayLiteral("destroyed()") + || signature == QByteArrayLiteral("deleteLater()")) + continue; + dump(method, implicitSignals); + } + + // and add toString(), destroy() and destroy(int) + qml->writeStartObject(QLatin1String("Method")); + qml->writeScriptBinding(QLatin1String("name"), enquote(QLatin1String("toString"))); + qml->writeEndObject(); + qml->writeStartObject(QLatin1String("Method")); + qml->writeScriptBinding(QLatin1String("name"), enquote(QLatin1String("destroy"))); + qml->writeEndObject(); + qml->writeStartObject(QLatin1String("Method")); + qml->writeScriptBinding(QLatin1String("name"), enquote(QLatin1String("destroy"))); + qml->writeStartObject(QLatin1String("Parameter")); + qml->writeScriptBinding(QLatin1String("name"), enquote(QLatin1String("delay"))); + qml->writeScriptBinding(QLatin1String("type"), enquote(QLatin1String("int"))); + qml->writeEndObject(); + qml->writeEndObject(); + } else { + for (int index = meta->methodOffset(); index < meta->methodCount(); ++index) + dump(meta->method(index), implicitSignals); + } + } + + QString getPrototypeNameForCompositeType(const QMetaObject *metaObject) + { + QString prototypeName; + const QMetaObject *superMetaObject = metaObject->superClass(); + if (!superMetaObject) + return "QObject"; + QString className = convertToId(superMetaObject->className()); + if (className.startsWith("QQuick")) + prototypeName = className; + else + prototypeName = getPrototypeNameForCompositeType(superMetaObject); + return prototypeName; + } + + void dumpComposite(QQmlEngine *engine, const QQmlType *compositeType, QSet &defaultReachableNames) + { + + QQmlComponent e(engine, compositeType->sourceUrl()); + QObject *object = e.create(); + + if (!object) + return; + + qml->writeStartObject("Component"); + + const QMetaObject *mainMeta = object->metaObject(); + + // Get C++ base class name for the composite type + QString prototypeName = getPrototypeNameForCompositeType(mainMeta); + qml->writeScriptBinding(QLatin1String("prototype"), enquote(prototypeName)); + + QString qmlTyName = compositeType->qmlTypeName(); + // name should be unique + qml->writeScriptBinding(QLatin1String("name"), enquote(qmlTyName)); + const QString exportString = getExportString(qmlTyName, compositeType->majorVersion(), compositeType->minorVersion()); + qml->writeArrayBinding(QLatin1String("exports"), QStringList() << exportString); + qml->writeArrayBinding(QLatin1String("exportMetaObjectRevisions"), QStringList() << QString::number(compositeType->minorVersion())); + + for (int index = mainMeta->classInfoCount() - 1 ; index >= 0 ; --index) { + QMetaClassInfo classInfo = mainMeta->classInfo(index); + if (QLatin1String(classInfo.name()) == QLatin1String("DefaultProperty")) { + qml->writeScriptBinding(QLatin1String("defaultProperty"), enquote(QLatin1String(classInfo.value()))); + break; + } + } + + QSet metas; + QSet candidatesComposite; + collectReachableMetaObjects(mainMeta, &candidatesComposite); + + // Also eliminate meta objects with the same classname. + // This is required because extended objects seem not to share + // a single meta object instance. + foreach (const QMetaObject *mo, candidatesComposite) { + if (!defaultReachableNames.contains(mo->className())) + metas.insert(mo); + } + + // put the metaobjects into a map so they are always dumped in the same order + QMap nameToMeta; + foreach (const QMetaObject *meta, metas) + nameToMeta.insert(convertToId(meta), meta); + + foreach (const QMetaObject *meta, nameToMeta) + writeMetaContent(meta); + + qml->writeEndObject(); + } + void dump(const QMetaObject *meta) { qml->writeStartObject("Component"); @@ -311,21 +444,7 @@ public: QHash exports; foreach (const QQmlType *qmlTy, qmlTypes) { - QString qmlTyName = qmlTy->qmlTypeName(); - if (qmlTyName.startsWith(relocatableModuleUri + QLatin1Char('/'))) { - qmlTyName.remove(0, relocatableModuleUri.size() + 1); - } - if (qmlTyName.startsWith("./")) { - qmlTyName.remove(0, 2); - } - if (qmlTyName.startsWith("/")) { - qmlTyName.remove(0, 1); - } - const QString exportString = enquote( - QString("%1 %2.%3").arg( - qmlTyName, - QString::number(qmlTy->majorVersion()), - QString::number(qmlTy->minorVersion()))); + const QString exportString = getExportString(qmlTy->qmlTypeName(), qmlTy->majorVersion(), qmlTy->minorVersion()); exports.insert(exportString, qmlTy); } @@ -355,43 +474,7 @@ public: for (int index = meta->enumeratorOffset(); index < meta->enumeratorCount(); ++index) dump(meta->enumerator(index)); - QSet implicitSignals; - for (int index = meta->propertyOffset(); index < meta->propertyCount(); ++index) { - const QMetaProperty &property = meta->property(index); - dump(property); - implicitSignals.insert(QString("%1Changed").arg(QString::fromUtf8(property.name()))); - } - - if (meta == &QObject::staticMetaObject) { - // for QObject, hide deleteLater() and onDestroyed - for (int index = meta->methodOffset(); index < meta->methodCount(); ++index) { - QMetaMethod method = meta->method(index); - QByteArray signature = method.methodSignature(); - if (signature == QByteArrayLiteral("destroyed(QObject*)") - || signature == QByteArrayLiteral("destroyed()") - || signature == QByteArrayLiteral("deleteLater()")) - continue; - dump(method, implicitSignals); - } - - // and add toString(), destroy() and destroy(int) - qml->writeStartObject(QLatin1String("Method")); - qml->writeScriptBinding(QLatin1String("name"), enquote(QLatin1String("toString"))); - qml->writeEndObject(); - qml->writeStartObject(QLatin1String("Method")); - qml->writeScriptBinding(QLatin1String("name"), enquote(QLatin1String("destroy"))); - qml->writeEndObject(); - qml->writeStartObject(QLatin1String("Method")); - qml->writeScriptBinding(QLatin1String("name"), enquote(QLatin1String("destroy"))); - qml->writeStartObject(QLatin1String("Parameter")); - qml->writeScriptBinding(QLatin1String("name"), enquote(QLatin1String("delay"))); - qml->writeScriptBinding(QLatin1String("type"), enquote(QLatin1String("int"))); - qml->writeEndObject(); - qml->writeEndObject(); - } else { - for (int index = meta->methodOffset(); index < meta->methodCount(); ++index) - dump(meta->method(index), implicitSignals); - } + writeMetaContent(meta); qml->writeEndObject(); } @@ -673,6 +756,7 @@ int main(int argc, char *argv[]) // add some otherwise unreachable QMetaObjects defaultReachable.insert(&QQuickMouseEvent::staticMetaObject); // QQuickKeyEvent, QQuickPinchEvent, QQuickDropEvent are not exported + QSet defaultReachableNames; // this will hold the meta objects we want to dump information of QSet metas; @@ -724,7 +808,6 @@ int main(int argc, char *argv[]) // Also eliminate meta objects with the same classname. // This is required because extended objects seem not to share // a single meta object instance. - QSet defaultReachableNames; foreach (const QMetaObject *mo, defaultReachable) defaultReachableNames.insert(QByteArray(mo->className())); foreach (const QMetaObject *mo, candidates) { @@ -762,6 +845,8 @@ int main(int argc, char *argv[]) foreach (const QMetaObject *meta, nameToMeta) { dumper.dump(meta); } + foreach (const QQmlType *compositeType, qmlTypesByCompositeName) + dumper.dumpComposite(&engine, compositeType, defaultReachableNames); // define QEasingCurve as an extension of QQmlEasingValueType, this way // properties using the QEasingCurve type get useful type information. -- cgit v1.2.3