aboutsummaryrefslogtreecommitdiffstats
path: root/tools/qmlplugindump/main.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'tools/qmlplugindump/main.cpp')
-rw-r--r--tools/qmlplugindump/main.cpp240
1 files changed, 178 insertions, 62 deletions
diff --git a/tools/qmlplugindump/main.cpp b/tools/qmlplugindump/main.cpp
index 4337db1689..6939ce92e2 100644
--- a/tools/qmlplugindump/main.cpp
+++ b/tools/qmlplugindump/main.cpp
@@ -58,6 +58,7 @@
#include <QtCore/private/qmetaobject_p.h>
#include <iostream>
+#include <algorithm>
#include "qmlstreamwriter.h"
@@ -139,6 +140,9 @@ public:
*/
static QHash<QByteArray, QSet<const QQmlType *> > qmlTypesByCppName;
+// No different versioning possible for a composite type.
+static QMap<QString, const QQmlType * > qmlTypesByCompositeName;
+
static QHash<QByteArray, QByteArray> cppToId;
/* Takes a C++ type name, such as Qt::LayoutDirection or QString and
@@ -190,8 +194,9 @@ QSet<const QMetaObject *> 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.
@@ -249,7 +254,16 @@ QSet<const QMetaObject *> collectReachableMetaObjects(QQmlEngine *engine, const
if (ty->isSingleton()) {
QQmlType::SingletonInstanceInfo *siinfo = ty->singletonInstanceInfo();
+ if (!siinfo) {
+ qWarning() << "Internal error, " << tyName
+ << "(" << QString::fromUtf8(ty->typeName()) << ")"
+ << " is singleton, but has no singletonInstanceInfo";
+ continue;
+ }
if (siinfo->qobjectCallback) {
+ if (verbose)
+ qDebug() << "Trying to get singleton for " << tyName
+ << " (" << siinfo->typeName << ")";
siinfo->init(engine);
collectReachableMetaObjects(object, &metas);
object = siinfo->qobjectApi(engine);
@@ -258,15 +272,22 @@ QSet<const QMetaObject *> collectReachableMetaObjects(QQmlEngine *engine, const
continue; // we don't handle QJSValue singleton types.
}
} else {
+ if (verbose)
+ qDebug() << "Trying to create object " << tyName
+ << " (" << QString::fromUtf8(ty->typeName()) << ")";
object = ty->create();
}
inObjectInstantiation.clear();
- if (object)
+ if (object) {
+ if (verbose)
+ qDebug() << "Got " << tyName
+ << " (" << QString::fromUtf8(ty->typeName()) << ")";
collectReachableMetaObjects(object, &metas);
- else
+ } else {
qWarning() << "Could not create" << tyName;
+ }
}
}
@@ -287,6 +308,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<QString> 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, QSet<QByteArray> &defaultReachableNames)
+ {
+ QString prototypeName;
+ if (!defaultReachableNames.contains(metaObject->className())) {
+ const QMetaObject *superMetaObject = metaObject->superClass();
+ if (!superMetaObject)
+ prototypeName = "QObject";
+ else
+ prototypeName = getPrototypeNameForCompositeType(superMetaObject, defaultReachableNames);
+ } else {
+ prototypeName = convertToId(metaObject->className());
+ }
+ return prototypeName;
+ }
+
+ void dumpComposite(QQmlEngine *engine, const QQmlType *compositeType, QSet<QByteArray> &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, defaultReachableNames);
+ 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<const QMetaObject *> metas;
+ QSet<const QMetaObject *> 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<QString, const QMetaObject *> 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");
@@ -310,27 +460,13 @@ public:
QHash<QString, const QQmlType *> 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);
}
// ensure exports are sorted and don't change order when the plugin is dumped again
QStringList exportStrings = exports.keys();
- qSort(exportStrings);
+ std::sort(exportStrings.begin(), exportStrings.end());
qml->writeArrayBinding(QLatin1String("exports"), exportStrings);
// write meta object revisions
@@ -354,43 +490,7 @@ public:
for (int index = meta->enumeratorOffset(); index < meta->enumeratorCount(); ++index)
dump(meta->enumerator(index));
- QSet<QString> 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();
}
@@ -461,7 +561,7 @@ private:
void dump(const QMetaMethod &meth, const QSet<QString> &implicitSignals)
{
if (meth.methodType() == QMetaMethod::Signal) {
- if (meth.access() != QMetaMethod::Protected)
+ if (meth.access() != QMetaMethod::Public)
return; // nothing to do.
} else if (meth.access() != QMetaMethod::Public) {
return; // nothing to do.
@@ -543,7 +643,7 @@ void sigSegvHandler(int) {
void printUsage(const QString &appName)
{
qWarning() << qPrintable(QString(
- "Usage: %1 [-v] [-noinstantiate] [-[non]relocatable] module.uri version [module/import/path]\n"
+ "Usage: %1 [-v] [-noinstantiate] [-defaultplatform] [-[non]relocatable] module.uri version [module/import/path]\n"
" %1 [-v] [-noinstantiate] -path path/to/qmldir/directory [version]\n"
" %1 [-v] -builtins\n"
"Example: %1 Qt.labs.folderlistmodel 2.0 /home/user/dev/qt-install/imports").arg(
@@ -570,7 +670,17 @@ int main(int argc, char *argv[])
#endif
// don't require a window manager even though we're a QGuiApplication
- qputenv("QT_QPA_PLATFORM", QByteArrayLiteral("minimal"));
+ bool requireWindowManager = false;
+ for (int index = 1; index < argc; ++index) {
+ if (QString::fromLocal8Bit(argv[index]) == "--defaultplatform"
+ || QString::fromLocal8Bit(argv[index]) == "-defaultplatform") {
+ requireWindowManager = true;
+ break;
+ }
+ }
+
+ if (!requireWindowManager)
+ qputenv("QT_QPA_PLATFORM", QByteArrayLiteral("minimal"));
QGuiApplication app(argc, argv);
const QStringList args = app.arguments();
@@ -612,6 +722,9 @@ int main(int argc, char *argv[])
action = Builtins;
} else if (arg == QLatin1String("-v")) {
verbose = true;
+ } else if (arg == QLatin1String("--defaultplatform")
+ || arg == QLatin1String("-defaultplatform")) {
+ continue;
} else {
qWarning() << "Invalid argument: " << arg;
return EXIT_INVALIDARGUMENTS;
@@ -672,6 +785,7 @@ int main(int argc, char *argv[])
// add some otherwise unreachable QMetaObjects
defaultReachable.insert(&QQuickMouseEvent::staticMetaObject);
// QQuickKeyEvent, QQuickPinchEvent, QQuickDropEvent are not exported
+ QSet<QByteArray> defaultReachableNames;
// this will hold the meta objects we want to dump information of
QSet<const QMetaObject *> metas;
@@ -723,7 +837,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<QByteArray> defaultReachableNames;
foreach (const QMetaObject *mo, defaultReachable)
defaultReachableNames.insert(QByteArray(mo->className()));
foreach (const QMetaObject *mo, candidates) {
@@ -746,8 +859,9 @@ int main(int argc, char *argv[])
"// This file describes the plugin-supplied types contained in the library.\n"
"// It is used for QML tooling purposes only.\n"
"//\n"
- "// This file was auto-generated with the command '%1'.\n"
- "\n").arg(args.join(QLatin1String(" "))));
+ "// This file was auto-generated by:\n"
+ "// '%1 %2'\n"
+ "\n").arg(QFileInfo(args.at(0)).fileName()).arg(QStringList(args.mid(1)).join(QLatin1String(" "))));
qml.writeStartObject("Module");
// put the metaobjects into a map so they are always dumped in the same order
@@ -761,6 +875,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.