2011-04-27 12:13:26 +00:00
|
|
|
/****************************************************************************
|
|
|
|
**
|
2013-01-02 11:17:46 +00:00
|
|
|
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
|
2012-09-20 05:21:40 +00:00
|
|
|
** Contact: http://www.qt-project.org/legal
|
2011-04-27 12:13:26 +00:00
|
|
|
**
|
|
|
|
** This file is part of the tools applications of the Qt Toolkit.
|
|
|
|
**
|
|
|
|
** $QT_BEGIN_LICENSE:LGPL$
|
2012-09-20 05:21:40 +00:00
|
|
|
** Commercial License Usage
|
|
|
|
** Licensees holding valid commercial Qt licenses may use this file in
|
|
|
|
** accordance with the commercial license agreement provided with the
|
|
|
|
** Software or, alternatively, in accordance with the terms contained in
|
|
|
|
** a written agreement between you and Digia. For licensing terms and
|
|
|
|
** conditions see http://qt.digia.com/licensing. For further information
|
|
|
|
** use the contact form at http://qt.digia.com/contact-us.
|
|
|
|
**
|
2011-04-27 12:13:26 +00:00
|
|
|
** GNU Lesser General Public License Usage
|
2012-09-20 05:21:40 +00:00
|
|
|
** 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, Digia gives you certain additional
|
|
|
|
** rights. These rights are described in the Digia Qt LGPL Exception
|
2011-04-27 12:13:26 +00:00
|
|
|
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
|
|
|
|
**
|
2011-07-07 12:52:03 +00:00
|
|
|
** GNU General Public License Usage
|
2012-09-20 05:21:40 +00:00
|
|
|
** 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.
|
2011-04-27 12:13:26 +00:00
|
|
|
**
|
2012-01-24 03:37:23 +00:00
|
|
|
**
|
2011-04-27 12:13:26 +00:00
|
|
|
** $QT_END_LICENSE$
|
|
|
|
**
|
|
|
|
****************************************************************************/
|
|
|
|
|
2012-02-16 04:43:03 +00:00
|
|
|
#include <QtQml/qqmlengine.h>
|
|
|
|
#include <QtQml/private/qqmlmetatype_p.h>
|
|
|
|
#include <QtQml/private/qqmlopenmetaobject_p.h>
|
Say hello to QtQuick module
This change moves the QtQuick 2 types and C++ API (including
SceneGraph) to a new module (AKA library), QtQuick.
99% of this change is moving files from src/declarative to
src/quick, and from tests/auto/declarative to
tests/auto/qtquick2.
The loading of QtQuick 2 ("import QtQuick 2.0") is now delegated to
a plugin, src/imports/qtquick2, just like it's done for QtQuick 1.
All tools, examples, and tests that use QtQuick C++ API have gotten
"QT += quick" or "QT += quick-private" added to their .pro file.
A few additional internal QtDeclarative classes had to be exported
(via Q_DECLARATIVE_PRIVATE_EXPORT) since they're needed by the
QtQuick 2 implementation.
The old header locations (e.g. QtDeclarative/qquickitem.h) will
still be supported for some time, but will produce compile-time
warnings. (To avoid the QtQuick implementation using the
compatibility headers (since QtDeclarative's includepath comes
first), a few include statements were modified, e.g. from
"#include <qsgnode.h>" to "#include <QtQuick/qsgnode.h>".)
There's a change in qtbase that automatically adds QtQuick to the
module list if QtDeclarative is used. Together with the compatibility
headers, this should help reduce the migration pain for existing
projects.
In theory, simply getting an existing QtDeclarative-based project
to compile and link shouldn't require any changes for now -- but
porting to the new scheme is of course recommended, and will
eventually become mandatory.
Task-number: QTBUG-22889
Reviewed-by: Lars Knoll <lars.knoll@nokia.com>
Change-Id: Ia52be9373172ba2f37e7623231ecb060316c96a7
Reviewed-by: Kent Hansen <kent.hansen@nokia.com>
Reviewed-by: Sergio Ahumada <sergio.ahumada@nokia.com>
2011-11-23 14:14:07 +00:00
|
|
|
#include <QtQuick/private/qquickevents_p_p.h>
|
|
|
|
#include <QtQuick/private/qquickpincharea_p.h>
|
2011-04-27 12:13:26 +00:00
|
|
|
|
2011-12-08 08:52:01 +00:00
|
|
|
#include <QtGui/QGuiApplication>
|
Say hello to QtQuick module
This change moves the QtQuick 2 types and C++ API (including
SceneGraph) to a new module (AKA library), QtQuick.
99% of this change is moving files from src/declarative to
src/quick, and from tests/auto/declarative to
tests/auto/qtquick2.
The loading of QtQuick 2 ("import QtQuick 2.0") is now delegated to
a plugin, src/imports/qtquick2, just like it's done for QtQuick 1.
All tools, examples, and tests that use QtQuick C++ API have gotten
"QT += quick" or "QT += quick-private" added to their .pro file.
A few additional internal QtDeclarative classes had to be exported
(via Q_DECLARATIVE_PRIVATE_EXPORT) since they're needed by the
QtQuick 2 implementation.
The old header locations (e.g. QtDeclarative/qquickitem.h) will
still be supported for some time, but will produce compile-time
warnings. (To avoid the QtQuick implementation using the
compatibility headers (since QtDeclarative's includepath comes
first), a few include statements were modified, e.g. from
"#include <qsgnode.h>" to "#include <QtQuick/qsgnode.h>".)
There's a change in qtbase that automatically adds QtQuick to the
module list if QtDeclarative is used. Together with the compatibility
headers, this should help reduce the migration pain for existing
projects.
In theory, simply getting an existing QtDeclarative-based project
to compile and link shouldn't require any changes for now -- but
porting to the new scheme is of course recommended, and will
eventually become mandatory.
Task-number: QTBUG-22889
Reviewed-by: Lars Knoll <lars.knoll@nokia.com>
Change-Id: Ia52be9373172ba2f37e7623231ecb060316c96a7
Reviewed-by: Kent Hansen <kent.hansen@nokia.com>
Reviewed-by: Sergio Ahumada <sergio.ahumada@nokia.com>
2011-11-23 14:14:07 +00:00
|
|
|
#include <QtCore/QDir>
|
|
|
|
#include <QtCore/QFileInfo>
|
2011-04-27 12:13:26 +00:00
|
|
|
#include <QtCore/QSet>
|
Say hello to QtQuick module
This change moves the QtQuick 2 types and C++ API (including
SceneGraph) to a new module (AKA library), QtQuick.
99% of this change is moving files from src/declarative to
src/quick, and from tests/auto/declarative to
tests/auto/qtquick2.
The loading of QtQuick 2 ("import QtQuick 2.0") is now delegated to
a plugin, src/imports/qtquick2, just like it's done for QtQuick 1.
All tools, examples, and tests that use QtQuick C++ API have gotten
"QT += quick" or "QT += quick-private" added to their .pro file.
A few additional internal QtDeclarative classes had to be exported
(via Q_DECLARATIVE_PRIVATE_EXPORT) since they're needed by the
QtQuick 2 implementation.
The old header locations (e.g. QtDeclarative/qquickitem.h) will
still be supported for some time, but will produce compile-time
warnings. (To avoid the QtQuick implementation using the
compatibility headers (since QtDeclarative's includepath comes
first), a few include statements were modified, e.g. from
"#include <qsgnode.h>" to "#include <QtQuick/qsgnode.h>".)
There's a change in qtbase that automatically adds QtQuick to the
module list if QtDeclarative is used. Together with the compatibility
headers, this should help reduce the migration pain for existing
projects.
In theory, simply getting an existing QtDeclarative-based project
to compile and link shouldn't require any changes for now -- but
porting to the new scheme is of course recommended, and will
eventually become mandatory.
Task-number: QTBUG-22889
Reviewed-by: Lars Knoll <lars.knoll@nokia.com>
Change-Id: Ia52be9373172ba2f37e7623231ecb060316c96a7
Reviewed-by: Kent Hansen <kent.hansen@nokia.com>
Reviewed-by: Sergio Ahumada <sergio.ahumada@nokia.com>
2011-11-23 14:14:07 +00:00
|
|
|
#include <QtCore/QStringList>
|
|
|
|
#include <QtCore/QTimer>
|
2011-04-27 12:13:26 +00:00
|
|
|
#include <QtCore/QMetaObject>
|
|
|
|
#include <QtCore/QMetaProperty>
|
|
|
|
#include <QtCore/QDebug>
|
|
|
|
#include <QtCore/private/qobject_p.h>
|
|
|
|
#include <QtCore/private/qmetaobject_p.h>
|
|
|
|
|
|
|
|
#include <iostream>
|
2013-09-12 09:06:59 +00:00
|
|
|
#include <algorithm>
|
2011-04-27 12:13:26 +00:00
|
|
|
|
|
|
|
#include "qmlstreamwriter.h"
|
|
|
|
|
|
|
|
#ifdef QT_SIMULATOR
|
|
|
|
#include <QtGui/private/qsimulatorconnection_p.h>
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifdef Q_OS_UNIX
|
|
|
|
#include <signal.h>
|
|
|
|
#endif
|
|
|
|
|
2011-04-28 10:22:30 +00:00
|
|
|
QString pluginImportPath;
|
2011-06-21 09:59:49 +00:00
|
|
|
bool verbose = false;
|
2013-05-02 17:42:31 +00:00
|
|
|
bool creatable = true;
|
2011-04-28 10:22:30 +00:00
|
|
|
|
2011-06-29 08:06:39 +00:00
|
|
|
QString currentProperty;
|
|
|
|
QString inObjectInstantiation;
|
|
|
|
|
2011-12-08 13:15:58 +00:00
|
|
|
void collectReachableMetaObjects(const QMetaObject *meta, QSet<const QMetaObject *> *metas, bool extended = false)
|
2011-04-27 12:13:26 +00:00
|
|
|
{
|
|
|
|
if (! meta || metas->contains(meta))
|
|
|
|
return;
|
|
|
|
|
2012-01-31 06:52:36 +00:00
|
|
|
// dynamic meta objects can break things badly
|
|
|
|
// but extended types are usually fine
|
2011-04-27 12:13:26 +00:00
|
|
|
const QMetaObjectPrivate *mop = reinterpret_cast<const QMetaObjectPrivate *>(meta->d.data);
|
2011-12-08 13:15:58 +00:00
|
|
|
if (extended || !(mop->flags & DynamicMetaObject))
|
2011-04-27 12:13:26 +00:00
|
|
|
metas->insert(meta);
|
|
|
|
|
|
|
|
collectReachableMetaObjects(meta->superClass(), metas);
|
|
|
|
}
|
|
|
|
|
|
|
|
void collectReachableMetaObjects(QObject *object, QSet<const QMetaObject *> *metas)
|
|
|
|
{
|
|
|
|
if (! object)
|
|
|
|
return;
|
|
|
|
|
|
|
|
const QMetaObject *meta = object->metaObject();
|
2011-06-21 09:59:49 +00:00
|
|
|
if (verbose)
|
|
|
|
qDebug() << "Processing object" << meta->className();
|
2011-04-27 12:13:26 +00:00
|
|
|
collectReachableMetaObjects(meta, metas);
|
|
|
|
|
|
|
|
for (int index = 0; index < meta->propertyCount(); ++index) {
|
|
|
|
QMetaProperty prop = meta->property(index);
|
2012-02-16 04:43:03 +00:00
|
|
|
if (QQmlMetaType::isQObject(prop.userType())) {
|
2011-06-21 09:59:49 +00:00
|
|
|
if (verbose)
|
|
|
|
qDebug() << " Processing property" << prop.name();
|
2011-04-27 12:13:26 +00:00
|
|
|
currentProperty = QString("%1::%2").arg(meta->className(), prop.name());
|
|
|
|
|
|
|
|
// if the property was not initialized during construction,
|
|
|
|
// accessing a member of oo is going to cause a segmentation fault
|
2012-02-16 04:43:03 +00:00
|
|
|
QObject *oo = QQmlMetaType::toQObject(prop.read(object));
|
2011-04-27 12:13:26 +00:00
|
|
|
if (oo && !metas->contains(oo->metaObject()))
|
|
|
|
collectReachableMetaObjects(oo, metas);
|
|
|
|
currentProperty.clear();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-02-16 04:43:03 +00:00
|
|
|
void collectReachableMetaObjects(const QQmlType *ty, QSet<const QMetaObject *> *metas)
|
2011-04-27 12:13:26 +00:00
|
|
|
{
|
2011-12-08 13:15:58 +00:00
|
|
|
collectReachableMetaObjects(ty->metaObject(), metas, ty->isExtendedType());
|
2011-04-27 12:13:26 +00:00
|
|
|
if (ty->attachedPropertiesType())
|
|
|
|
collectReachableMetaObjects(ty->attachedPropertiesType(), metas);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* We want to add the MetaObject for 'Qt' to the list, this is a
|
|
|
|
simple way to access it.
|
|
|
|
*/
|
|
|
|
class FriendlyQObject: public QObject
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
static const QMetaObject *qtMeta() { return &staticQtMetaObject; }
|
|
|
|
};
|
|
|
|
|
|
|
|
/* When we dump a QMetaObject, we want to list all the types it is exported as.
|
2012-03-05 01:39:24 +00:00
|
|
|
To do this, we need to find the QQmlTypes associated with this
|
2011-04-27 12:13:26 +00:00
|
|
|
QMetaObject.
|
|
|
|
*/
|
2012-02-16 04:43:03 +00:00
|
|
|
static QHash<QByteArray, QSet<const QQmlType *> > qmlTypesByCppName;
|
2011-04-27 12:13:26 +00:00
|
|
|
|
2013-09-03 12:03:21 +00:00
|
|
|
// No different versioning possible for a composite type.
|
|
|
|
static QMap<QString, const QQmlType * > qmlTypesByCompositeName;
|
|
|
|
|
2011-04-27 12:13:26 +00:00
|
|
|
static QHash<QByteArray, QByteArray> cppToId;
|
|
|
|
|
|
|
|
/* Takes a C++ type name, such as Qt::LayoutDirection or QString and
|
|
|
|
maps it to how it should appear in the description file.
|
|
|
|
|
|
|
|
These names need to be unique globally, so we don't change the C++ symbol's
|
|
|
|
name much. It is mostly used to for explicit translations such as
|
|
|
|
QString->string and translations for extended QML objects.
|
|
|
|
*/
|
|
|
|
QByteArray convertToId(const QByteArray &cppName)
|
|
|
|
{
|
|
|
|
return cppToId.value(cppName, cppName);
|
|
|
|
}
|
|
|
|
|
2011-11-17 12:57:37 +00:00
|
|
|
QByteArray convertToId(const QMetaObject *mo)
|
|
|
|
{
|
|
|
|
QByteArray className(mo->className());
|
|
|
|
if (!className.isEmpty())
|
|
|
|
return convertToId(className);
|
|
|
|
|
|
|
|
// likely a metaobject generated for an extended qml object
|
|
|
|
if (mo->superClass()) {
|
|
|
|
className = convertToId(mo->superClass());
|
|
|
|
className.append("_extended");
|
|
|
|
return className;
|
|
|
|
}
|
|
|
|
|
|
|
|
static QHash<const QMetaObject *, QByteArray> generatedNames;
|
|
|
|
className = generatedNames.value(mo);
|
|
|
|
if (!className.isEmpty())
|
|
|
|
return className;
|
|
|
|
|
|
|
|
qWarning() << "Found a QMetaObject without a className, generating a random name";
|
|
|
|
className = QByteArray("error-unknown-name-");
|
|
|
|
className.append(QByteArray::number(generatedNames.size()));
|
|
|
|
generatedNames.insert(mo, className);
|
|
|
|
return className;
|
|
|
|
}
|
|
|
|
|
2012-02-16 04:43:03 +00:00
|
|
|
QSet<const QMetaObject *> collectReachableMetaObjects(QQmlEngine *engine, const QList<QQmlType *> &skip = QList<QQmlType *>())
|
2011-04-27 12:13:26 +00:00
|
|
|
{
|
|
|
|
QSet<const QMetaObject *> metas;
|
|
|
|
metas.insert(FriendlyQObject::qtMeta());
|
|
|
|
|
|
|
|
QHash<QByteArray, QSet<QByteArray> > extensions;
|
2012-02-16 04:43:03 +00:00
|
|
|
foreach (const QQmlType *ty, QQmlMetaType::qmlTypes()) {
|
2013-02-13 16:42:56 +00:00
|
|
|
if (!ty->isComposite()) {
|
|
|
|
qmlTypesByCppName[ty->metaObject()->className()].insert(ty);
|
|
|
|
if (ty->isExtendedType())
|
|
|
|
extensions[ty->typeName()].insert(ty->metaObject()->className());
|
|
|
|
collectReachableMetaObjects(ty, &metas);
|
2013-09-03 12:03:21 +00:00
|
|
|
} else {
|
|
|
|
qmlTypesByCompositeName[ty->elementName()] = ty;
|
2011-04-27 12:13:26 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-06-22 15:13:56 +00:00
|
|
|
// Adjust exports of the base object if there are extensions.
|
|
|
|
// For each export of a base object there can be a single extension object overriding it.
|
|
|
|
// Example: QDeclarativeGraphicsWidget overrides the QtQuick/QGraphicsWidget export
|
|
|
|
// of QGraphicsWidget.
|
|
|
|
foreach (const QByteArray &baseCpp, extensions.keys()) {
|
2012-02-16 04:43:03 +00:00
|
|
|
QSet<const QQmlType *> baseExports = qmlTypesByCppName.value(baseCpp);
|
2011-06-22 15:13:56 +00:00
|
|
|
|
|
|
|
const QSet<QByteArray> extensionCppNames = extensions.value(baseCpp);
|
2011-04-27 12:13:26 +00:00
|
|
|
foreach (const QByteArray &extensionCppName, extensionCppNames) {
|
2012-02-16 04:43:03 +00:00
|
|
|
const QSet<const QQmlType *> extensionExports = qmlTypesByCppName.value(extensionCppName);
|
2011-06-22 15:13:56 +00:00
|
|
|
|
|
|
|
// remove extension exports from base imports
|
2012-09-08 15:39:02 +00:00
|
|
|
// unfortunately the QQmlType pointers don't match, so can't use QSet::subtract
|
2012-02-16 04:43:03 +00:00
|
|
|
QSet<const QQmlType *> newBaseExports;
|
|
|
|
foreach (const QQmlType *baseExport, baseExports) {
|
2011-06-22 15:13:56 +00:00
|
|
|
bool match = false;
|
2012-02-16 04:43:03 +00:00
|
|
|
foreach (const QQmlType *extensionExport, extensionExports) {
|
2011-06-27 09:01:20 +00:00
|
|
|
if (baseExport->qmlTypeName() == extensionExport->qmlTypeName()
|
2011-06-22 15:13:56 +00:00
|
|
|
&& baseExport->majorVersion() == extensionExport->majorVersion()
|
|
|
|
&& baseExport->minorVersion() == extensionExport->minorVersion()) {
|
|
|
|
match = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (!match)
|
|
|
|
newBaseExports.insert(baseExport);
|
2011-04-27 12:13:26 +00:00
|
|
|
}
|
2011-06-22 15:13:56 +00:00
|
|
|
baseExports = newBaseExports;
|
2011-04-27 12:13:26 +00:00
|
|
|
}
|
2011-06-22 15:13:56 +00:00
|
|
|
qmlTypesByCppName[baseCpp] = baseExports;
|
2011-04-27 12:13:26 +00:00
|
|
|
}
|
|
|
|
|
2013-05-02 17:42:31 +00:00
|
|
|
if (creatable) {
|
|
|
|
// find even more QMetaObjects by instantiating QML types and running
|
|
|
|
// over the instances
|
|
|
|
foreach (QQmlType *ty, QQmlMetaType::qmlTypes()) {
|
|
|
|
if (skip.contains(ty))
|
|
|
|
continue;
|
|
|
|
if (ty->isExtendedType())
|
|
|
|
continue;
|
|
|
|
if (!ty->isCreatable())
|
|
|
|
continue;
|
|
|
|
if (ty->typeName() == "QQmlComponent")
|
|
|
|
continue;
|
|
|
|
|
|
|
|
QString tyName = ty->qmlTypeName();
|
|
|
|
tyName = tyName.mid(tyName.lastIndexOf(QLatin1Char('/')) + 1);
|
|
|
|
if (tyName.isEmpty())
|
|
|
|
continue;
|
|
|
|
|
|
|
|
inObjectInstantiation = tyName;
|
|
|
|
QObject *object = 0;
|
|
|
|
|
|
|
|
if (ty->isSingleton()) {
|
|
|
|
QQmlType::SingletonInstanceInfo *siinfo = ty->singletonInstanceInfo();
|
|
|
|
if (siinfo->qobjectCallback) {
|
|
|
|
siinfo->init(engine);
|
|
|
|
collectReachableMetaObjects(object, &metas);
|
|
|
|
object = siinfo->qobjectApi(engine);
|
|
|
|
} else {
|
|
|
|
inObjectInstantiation.clear();
|
|
|
|
continue; // we don't handle QJSValue singleton types.
|
|
|
|
}
|
2012-08-14 01:44:49 +00:00
|
|
|
} else {
|
2013-05-02 17:42:31 +00:00
|
|
|
object = ty->create();
|
2012-08-14 01:44:49 +00:00
|
|
|
}
|
|
|
|
|
2013-05-02 17:42:31 +00:00
|
|
|
inObjectInstantiation.clear();
|
2011-06-29 08:06:39 +00:00
|
|
|
|
2013-05-02 17:42:31 +00:00
|
|
|
if (object)
|
|
|
|
collectReachableMetaObjects(object, &metas);
|
|
|
|
else
|
|
|
|
qWarning() << "Could not create" << tyName;
|
|
|
|
}
|
2011-04-27 12:13:26 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return metas;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
class Dumper
|
|
|
|
{
|
|
|
|
QmlStreamWriter *qml;
|
|
|
|
QString relocatableModuleUri;
|
|
|
|
|
|
|
|
public:
|
|
|
|
Dumper(QmlStreamWriter *qml) : qml(qml) {}
|
|
|
|
|
|
|
|
void setRelocatableModuleUri(const QString &uri)
|
|
|
|
{
|
|
|
|
relocatableModuleUri = uri;
|
|
|
|
}
|
|
|
|
|
2013-09-03 12:03:21 +00:00
|
|
|
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)
|
|
|
|
{
|
|
|
|
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<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);
|
|
|
|
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();
|
|
|
|
}
|
|
|
|
|
2011-04-27 12:13:26 +00:00
|
|
|
void dump(const QMetaObject *meta)
|
|
|
|
{
|
|
|
|
qml->writeStartObject("Component");
|
|
|
|
|
2011-11-17 12:57:37 +00:00
|
|
|
QByteArray id = convertToId(meta);
|
2011-04-27 12:13:26 +00:00
|
|
|
qml->writeScriptBinding(QLatin1String("name"), enquote(id));
|
|
|
|
|
|
|
|
for (int index = meta->classInfoCount() - 1 ; index >= 0 ; --index) {
|
|
|
|
QMetaClassInfo classInfo = meta->classInfo(index);
|
|
|
|
if (QLatin1String(classInfo.name()) == QLatin1String("DefaultProperty")) {
|
|
|
|
qml->writeScriptBinding(QLatin1String("defaultProperty"), enquote(QLatin1String(classInfo.value())));
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (meta->superClass())
|
2011-11-17 12:57:37 +00:00
|
|
|
qml->writeScriptBinding(QLatin1String("prototype"), enquote(convertToId(meta->superClass())));
|
2011-04-27 12:13:26 +00:00
|
|
|
|
2012-02-16 04:43:03 +00:00
|
|
|
QSet<const QQmlType *> qmlTypes = qmlTypesByCppName.value(meta->className());
|
2011-04-27 12:13:26 +00:00
|
|
|
if (!qmlTypes.isEmpty()) {
|
2012-02-16 04:43:03 +00:00
|
|
|
QHash<QString, const QQmlType *> exports;
|
2011-04-27 12:13:26 +00:00
|
|
|
|
2012-02-16 04:43:03 +00:00
|
|
|
foreach (const QQmlType *qmlTy, qmlTypes) {
|
2013-09-03 12:03:21 +00:00
|
|
|
const QString exportString = getExportString(qmlTy->qmlTypeName(), qmlTy->majorVersion(), qmlTy->minorVersion());
|
2011-09-21 10:54:10 +00:00
|
|
|
exports.insert(exportString, qmlTy);
|
2011-04-27 12:13:26 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// ensure exports are sorted and don't change order when the plugin is dumped again
|
2011-09-21 10:54:10 +00:00
|
|
|
QStringList exportStrings = exports.keys();
|
2013-09-12 09:06:59 +00:00
|
|
|
std::sort(exportStrings.begin(), exportStrings.end());
|
2011-09-21 10:54:10 +00:00
|
|
|
qml->writeArrayBinding(QLatin1String("exports"), exportStrings);
|
|
|
|
|
2013-04-10 09:26:16 +00:00
|
|
|
// write meta object revisions
|
2011-09-21 10:54:10 +00:00
|
|
|
QStringList metaObjectRevisions;
|
|
|
|
foreach (const QString &exportString, exportStrings) {
|
|
|
|
int metaObjectRevision = exports[exportString]->metaObjectRevision();
|
|
|
|
metaObjectRevisions += QString::number(metaObjectRevision);
|
|
|
|
}
|
2013-04-10 09:26:16 +00:00
|
|
|
qml->writeArrayBinding(QLatin1String("exportMetaObjectRevisions"), metaObjectRevisions);
|
2011-04-27 12:13:26 +00:00
|
|
|
|
|
|
|
if (const QMetaObject *attachedType = (*qmlTypes.begin())->attachedPropertiesType()) {
|
2011-11-29 07:52:14 +00:00
|
|
|
// Can happen when a type is registered that returns itself as attachedPropertiesType()
|
|
|
|
// because there is no creatable type to attach to.
|
|
|
|
if (attachedType != meta) {
|
|
|
|
qml->writeScriptBinding(QLatin1String("attachedType"), enquote(
|
|
|
|
convertToId(attachedType)));
|
|
|
|
}
|
2011-04-27 12:13:26 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
for (int index = meta->enumeratorOffset(); index < meta->enumeratorCount(); ++index)
|
|
|
|
dump(meta->enumerator(index));
|
|
|
|
|
2013-09-03 12:03:21 +00:00
|
|
|
writeMetaContent(meta);
|
2011-04-27 12:13:26 +00:00
|
|
|
|
|
|
|
qml->writeEndObject();
|
|
|
|
}
|
|
|
|
|
|
|
|
void writeEasingCurve()
|
|
|
|
{
|
2011-10-05 09:42:33 +00:00
|
|
|
qml->writeStartObject(QLatin1String("Component"));
|
2011-04-27 12:13:26 +00:00
|
|
|
qml->writeScriptBinding(QLatin1String("name"), enquote(QLatin1String("QEasingCurve")));
|
2012-02-16 04:43:03 +00:00
|
|
|
qml->writeScriptBinding(QLatin1String("prototype"), enquote(QLatin1String("QQmlEasingValueType")));
|
2011-04-27 12:13:26 +00:00
|
|
|
qml->writeEndObject();
|
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
static QString enquote(const QString &string)
|
|
|
|
{
|
|
|
|
return QString("\"%1\"").arg(string);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Removes pointer and list annotations from a type name, returning
|
|
|
|
what was removed in isList and isPointer
|
|
|
|
*/
|
|
|
|
static void removePointerAndList(QByteArray *typeName, bool *isList, bool *isPointer)
|
|
|
|
{
|
2012-02-16 04:43:03 +00:00
|
|
|
static QByteArray declListPrefix = "QQmlListProperty<";
|
2011-04-27 12:13:26 +00:00
|
|
|
|
|
|
|
if (typeName->endsWith('*')) {
|
|
|
|
*isPointer = true;
|
|
|
|
typeName->truncate(typeName->length() - 1);
|
|
|
|
removePointerAndList(typeName, isList, isPointer);
|
|
|
|
} else if (typeName->startsWith(declListPrefix)) {
|
|
|
|
*isList = true;
|
|
|
|
typeName->truncate(typeName->length() - 1); // get rid of the suffix '>'
|
|
|
|
*typeName = typeName->mid(declListPrefix.size());
|
|
|
|
removePointerAndList(typeName, isList, isPointer);
|
|
|
|
}
|
|
|
|
|
|
|
|
*typeName = convertToId(*typeName);
|
|
|
|
}
|
|
|
|
|
|
|
|
void writeTypeProperties(QByteArray typeName, bool isWritable)
|
|
|
|
{
|
|
|
|
bool isList = false, isPointer = false;
|
|
|
|
removePointerAndList(&typeName, &isList, &isPointer);
|
|
|
|
|
|
|
|
qml->writeScriptBinding(QLatin1String("type"), enquote(typeName));
|
|
|
|
if (isList)
|
|
|
|
qml->writeScriptBinding(QLatin1String("isList"), QLatin1String("true"));
|
|
|
|
if (!isWritable)
|
|
|
|
qml->writeScriptBinding(QLatin1String("isReadonly"), QLatin1String("true"));
|
|
|
|
if (isPointer)
|
|
|
|
qml->writeScriptBinding(QLatin1String("isPointer"), QLatin1String("true"));
|
|
|
|
}
|
|
|
|
|
|
|
|
void dump(const QMetaProperty &prop)
|
|
|
|
{
|
|
|
|
qml->writeStartObject("Property");
|
|
|
|
|
|
|
|
qml->writeScriptBinding(QLatin1String("name"), enquote(QString::fromUtf8(prop.name())));
|
2011-05-30 07:24:20 +00:00
|
|
|
#if (QT_VERSION >= QT_VERSION_CHECK(4, 7, 4))
|
|
|
|
if (int revision = prop.revision())
|
|
|
|
qml->writeScriptBinding(QLatin1String("revision"), QString::number(revision));
|
|
|
|
#endif
|
2011-04-27 12:13:26 +00:00
|
|
|
writeTypeProperties(prop.typeName(), prop.isWritable());
|
|
|
|
|
|
|
|
qml->writeEndObject();
|
|
|
|
}
|
|
|
|
|
2011-10-06 10:12:34 +00:00
|
|
|
void dump(const QMetaMethod &meth, const QSet<QString> &implicitSignals)
|
2011-04-27 12:13:26 +00:00
|
|
|
{
|
|
|
|
if (meth.methodType() == QMetaMethod::Signal) {
|
|
|
|
if (meth.access() != QMetaMethod::Protected)
|
|
|
|
return; // nothing to do.
|
|
|
|
} else if (meth.access() != QMetaMethod::Public) {
|
|
|
|
return; // nothing to do.
|
|
|
|
}
|
|
|
|
|
2012-03-05 07:31:00 +00:00
|
|
|
QByteArray name = meth.name();
|
2011-10-06 10:12:34 +00:00
|
|
|
const QString typeName = convertToId(meth.typeName());
|
|
|
|
|
|
|
|
if (implicitSignals.contains(name)
|
|
|
|
&& !meth.revision()
|
|
|
|
&& meth.methodType() == QMetaMethod::Signal
|
|
|
|
&& meth.parameterNames().isEmpty()
|
2012-09-10 12:17:00 +00:00
|
|
|
&& typeName == QLatin1String("void")) {
|
2011-10-06 10:12:34 +00:00
|
|
|
// don't mention implicit signals
|
|
|
|
return;
|
|
|
|
}
|
2011-04-27 12:13:26 +00:00
|
|
|
|
|
|
|
if (meth.methodType() == QMetaMethod::Signal)
|
|
|
|
qml->writeStartObject(QLatin1String("Signal"));
|
|
|
|
else
|
|
|
|
qml->writeStartObject(QLatin1String("Method"));
|
|
|
|
|
|
|
|
qml->writeScriptBinding(QLatin1String("name"), enquote(name));
|
|
|
|
|
2011-05-30 07:24:20 +00:00
|
|
|
#if (QT_VERSION >= QT_VERSION_CHECK(4, 7, 4))
|
|
|
|
if (int revision = meth.revision())
|
|
|
|
qml->writeScriptBinding(QLatin1String("revision"), QString::number(revision));
|
|
|
|
#endif
|
|
|
|
|
2012-09-07 08:43:18 +00:00
|
|
|
if (typeName != QLatin1String("void"))
|
2011-04-27 12:13:26 +00:00
|
|
|
qml->writeScriptBinding(QLatin1String("type"), enquote(typeName));
|
|
|
|
|
|
|
|
for (int i = 0; i < meth.parameterTypes().size(); ++i) {
|
|
|
|
QByteArray argName = meth.parameterNames().at(i);
|
|
|
|
|
|
|
|
qml->writeStartObject(QLatin1String("Parameter"));
|
|
|
|
if (! argName.isEmpty())
|
|
|
|
qml->writeScriptBinding(QLatin1String("name"), enquote(argName));
|
|
|
|
writeTypeProperties(meth.parameterTypes().at(i), true);
|
|
|
|
qml->writeEndObject();
|
|
|
|
}
|
|
|
|
|
|
|
|
qml->writeEndObject();
|
|
|
|
}
|
|
|
|
|
|
|
|
void dump(const QMetaEnum &e)
|
|
|
|
{
|
|
|
|
qml->writeStartObject(QLatin1String("Enum"));
|
|
|
|
qml->writeScriptBinding(QLatin1String("name"), enquote(QString::fromUtf8(e.name())));
|
|
|
|
|
|
|
|
QList<QPair<QString, QString> > namesValues;
|
|
|
|
for (int index = 0; index < e.keyCount(); ++index) {
|
|
|
|
namesValues.append(qMakePair(enquote(QString::fromUtf8(e.key(index))), QString::number(e.value(index))));
|
|
|
|
}
|
|
|
|
|
|
|
|
qml->writeScriptObjectLiteralBinding(QLatin1String("values"), namesValues);
|
|
|
|
qml->writeEndObject();
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
enum ExitCode {
|
|
|
|
EXIT_INVALIDARGUMENTS = 1,
|
|
|
|
EXIT_SEGV = 2,
|
|
|
|
EXIT_IMPORTERROR = 3
|
|
|
|
};
|
|
|
|
|
|
|
|
#ifdef Q_OS_UNIX
|
|
|
|
void sigSegvHandler(int) {
|
|
|
|
fprintf(stderr, "Error: SEGV\n");
|
|
|
|
if (!currentProperty.isEmpty())
|
|
|
|
fprintf(stderr, "While processing the property '%s', which probably has uninitialized data.\n", currentProperty.toLatin1().constData());
|
2011-06-29 08:06:39 +00:00
|
|
|
if (!inObjectInstantiation.isEmpty())
|
|
|
|
fprintf(stderr, "While instantiating the object '%s'.\n", inObjectInstantiation.toLatin1().constData());
|
2011-04-27 12:13:26 +00:00
|
|
|
exit(EXIT_SEGV);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
void printUsage(const QString &appName)
|
|
|
|
{
|
|
|
|
qWarning() << qPrintable(QString(
|
2013-05-02 17:42:31 +00:00
|
|
|
"Usage: %1 [-v] [-noinstantiate] [-[non]relocatable] module.uri version [module/import/path]\n"
|
|
|
|
" %1 [-v] [-noinstantiate] -path path/to/qmldir/directory [version]\n"
|
2011-06-21 09:59:49 +00:00
|
|
|
" %1 [-v] -builtins\n"
|
2012-09-17 14:44:08 +00:00
|
|
|
"Example: %1 Qt.labs.folderlistmodel 2.0 /home/user/dev/qt-install/imports").arg(
|
2011-04-27 12:13:26 +00:00
|
|
|
appName));
|
|
|
|
}
|
|
|
|
|
|
|
|
int main(int argc, char *argv[])
|
|
|
|
{
|
|
|
|
#ifdef Q_OS_UNIX
|
|
|
|
// qmldump may crash, but we don't want any crash handlers to pop up
|
|
|
|
// therefore we intercept the segfault and just exit() ourselves
|
2011-06-21 09:59:49 +00:00
|
|
|
struct sigaction sigAction;
|
2011-04-27 12:13:26 +00:00
|
|
|
|
2011-06-21 09:59:49 +00:00
|
|
|
sigemptyset(&sigAction.sa_mask);
|
|
|
|
sigAction.sa_handler = &sigSegvHandler;
|
|
|
|
sigAction.sa_flags = 0;
|
2011-04-27 12:13:26 +00:00
|
|
|
|
2011-06-21 09:59:49 +00:00
|
|
|
sigaction(SIGSEGV, &sigAction, 0);
|
2011-04-27 12:13:26 +00:00
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifdef QT_SIMULATOR
|
2013-04-19 16:33:27 +00:00
|
|
|
// Running this application would bring up the Qt Simulator (since it links Qt GUI), avoid that!
|
2011-04-27 12:13:26 +00:00
|
|
|
QtSimulatorPrivate::SimulatorConnection::createStubInstance();
|
|
|
|
#endif
|
2011-12-08 08:52:01 +00:00
|
|
|
|
2012-11-30 09:55:07 +00:00
|
|
|
// don't require a window manager even though we're a QGuiApplication
|
|
|
|
qputenv("QT_QPA_PLATFORM", QByteArrayLiteral("minimal"));
|
|
|
|
|
2011-12-08 08:52:01 +00:00
|
|
|
QGuiApplication app(argc, argv);
|
2011-04-27 12:13:26 +00:00
|
|
|
const QStringList args = app.arguments();
|
|
|
|
const QString appName = QFileInfo(app.applicationFilePath()).baseName();
|
2011-06-21 09:59:49 +00:00
|
|
|
if (args.size() < 2) {
|
2011-04-27 12:13:26 +00:00
|
|
|
printUsage(appName);
|
|
|
|
return EXIT_INVALIDARGUMENTS;
|
|
|
|
}
|
|
|
|
|
|
|
|
QString pluginImportUri;
|
|
|
|
QString pluginImportVersion;
|
|
|
|
bool relocatable = true;
|
2011-06-21 09:59:49 +00:00
|
|
|
enum Action { Uri, Path, Builtins };
|
|
|
|
Action action = Uri;
|
|
|
|
{
|
2011-04-27 12:13:26 +00:00
|
|
|
QStringList positionalArgs;
|
|
|
|
foreach (const QString &arg, args) {
|
|
|
|
if (!arg.startsWith(QLatin1Char('-'))) {
|
|
|
|
positionalArgs.append(arg);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (arg == QLatin1String("--notrelocatable")
|
2013-04-23 17:03:14 +00:00
|
|
|
|| arg == QLatin1String("-notrelocatable")
|
|
|
|
|| arg == QLatin1String("--nonrelocatable")
|
|
|
|
|| arg == QLatin1String("-nonrelocatable")) {
|
2011-04-27 12:13:26 +00:00
|
|
|
relocatable = false;
|
2013-04-23 17:03:14 +00:00
|
|
|
} else if (arg == QLatin1String("--relocatable")
|
|
|
|
|| arg == QLatin1String("-relocatable")) {
|
|
|
|
relocatable = true;
|
2013-05-02 17:42:31 +00:00
|
|
|
} else if (arg == QLatin1String("--noinstantiate")
|
|
|
|
|| arg == QLatin1String("-noinstantiate")) {
|
|
|
|
creatable = false;
|
2011-04-27 12:13:26 +00:00
|
|
|
} else if (arg == QLatin1String("--path")
|
|
|
|
|| arg == QLatin1String("-path")) {
|
2011-06-21 09:59:49 +00:00
|
|
|
action = Path;
|
|
|
|
} else if (arg == QLatin1String("--builtins")
|
|
|
|
|| arg == QLatin1String("-builtins")) {
|
|
|
|
action = Builtins;
|
|
|
|
} else if (arg == QLatin1String("-v")) {
|
|
|
|
verbose = true;
|
2011-04-27 12:13:26 +00:00
|
|
|
} else {
|
|
|
|
qWarning() << "Invalid argument: " << arg;
|
|
|
|
return EXIT_INVALIDARGUMENTS;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-06-21 09:59:49 +00:00
|
|
|
if (action == Uri) {
|
2011-04-27 12:13:26 +00:00
|
|
|
if (positionalArgs.size() != 3 && positionalArgs.size() != 4) {
|
|
|
|
qWarning() << "Incorrect number of positional arguments";
|
|
|
|
return EXIT_INVALIDARGUMENTS;
|
|
|
|
}
|
|
|
|
pluginImportUri = positionalArgs[1];
|
|
|
|
pluginImportVersion = positionalArgs[2];
|
|
|
|
if (positionalArgs.size() >= 4)
|
|
|
|
pluginImportPath = positionalArgs[3];
|
2011-06-21 09:59:49 +00:00
|
|
|
} else if (action == Path) {
|
2011-04-27 12:13:26 +00:00
|
|
|
if (positionalArgs.size() != 2 && positionalArgs.size() != 3) {
|
|
|
|
qWarning() << "Incorrect number of positional arguments";
|
|
|
|
return EXIT_INVALIDARGUMENTS;
|
|
|
|
}
|
2011-04-28 10:22:30 +00:00
|
|
|
pluginImportPath = QDir::fromNativeSeparators(positionalArgs[1]);
|
2011-04-27 12:13:26 +00:00
|
|
|
if (positionalArgs.size() == 3)
|
|
|
|
pluginImportVersion = positionalArgs[2];
|
2011-06-21 09:59:49 +00:00
|
|
|
} else if (action == Builtins) {
|
|
|
|
if (positionalArgs.size() != 1) {
|
|
|
|
qWarning() << "Incorrect number of positional arguments";
|
|
|
|
return EXIT_INVALIDARGUMENTS;
|
|
|
|
}
|
2011-04-27 12:13:26 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-02-16 04:43:03 +00:00
|
|
|
QQmlEngine engine;
|
2011-06-29 12:00:34 +00:00
|
|
|
if (!pluginImportPath.isEmpty()) {
|
|
|
|
QDir cur = QDir::current();
|
|
|
|
cur.cd(pluginImportPath);
|
|
|
|
pluginImportPath = cur.absolutePath();
|
|
|
|
QDir::setCurrent(pluginImportPath);
|
2011-07-11 03:47:51 +00:00
|
|
|
engine.addImportPath(pluginImportPath);
|
2011-06-29 12:00:34 +00:00
|
|
|
}
|
2011-04-27 12:13:26 +00:00
|
|
|
|
2011-12-08 08:52:01 +00:00
|
|
|
// load the QtQuick 2 plugin
|
2011-08-26 08:47:13 +00:00
|
|
|
{
|
2011-12-08 08:52:01 +00:00
|
|
|
QByteArray code("import QtQuick 2.0\nQtObject {}");
|
2012-02-16 04:43:03 +00:00
|
|
|
QQmlComponent c(&engine);
|
2011-12-08 08:52:01 +00:00
|
|
|
c.setData(code, QUrl::fromLocalFile(pluginImportPath + "/loadqtquick2.qml"));
|
2011-08-26 08:47:13 +00:00
|
|
|
c.create();
|
|
|
|
if (!c.errors().isEmpty()) {
|
2012-02-16 04:43:03 +00:00
|
|
|
foreach (const QQmlError &error, c.errors())
|
2011-08-26 08:47:13 +00:00
|
|
|
qWarning() << error.toString();
|
|
|
|
return EXIT_IMPORTERROR;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-04-27 12:13:26 +00:00
|
|
|
// find all QMetaObjects reachable from the builtin module
|
2011-10-05 09:42:33 +00:00
|
|
|
QSet<const QMetaObject *> defaultReachable = collectReachableMetaObjects(&engine);
|
2012-02-16 04:43:03 +00:00
|
|
|
QList<QQmlType *> defaultTypes = QQmlMetaType::qmlTypes();
|
2011-04-27 12:13:26 +00:00
|
|
|
|
2011-10-06 10:02:56 +00:00
|
|
|
// add some otherwise unreachable QMetaObjects
|
2011-10-14 08:51:42 +00:00
|
|
|
defaultReachable.insert(&QQuickMouseEvent::staticMetaObject);
|
|
|
|
// QQuickKeyEvent, QQuickPinchEvent, QQuickDropEvent are not exported
|
2013-09-03 12:03:21 +00:00
|
|
|
QSet<QByteArray> defaultReachableNames;
|
2011-10-06 10:02:56 +00:00
|
|
|
|
2011-04-27 12:13:26 +00:00
|
|
|
// this will hold the meta objects we want to dump information of
|
|
|
|
QSet<const QMetaObject *> metas;
|
|
|
|
|
2011-06-21 09:59:49 +00:00
|
|
|
if (action == Builtins) {
|
2011-04-27 12:13:26 +00:00
|
|
|
metas = defaultReachable;
|
|
|
|
} else {
|
2011-07-14 07:04:17 +00:00
|
|
|
// find a valid QtQuick import
|
|
|
|
QByteArray importCode;
|
2012-02-16 04:43:03 +00:00
|
|
|
QQmlType *qtObjectType = QQmlMetaType::qmlType(&QObject::staticMetaObject);
|
2011-07-14 07:04:17 +00:00
|
|
|
if (!qtObjectType) {
|
|
|
|
qWarning() << "Could not find QtObject type";
|
|
|
|
importCode = QByteArray("import QtQuick 2.0\n");
|
|
|
|
} else {
|
2011-09-29 08:29:22 +00:00
|
|
|
QString module = qtObjectType->qmlTypeName();
|
|
|
|
module = module.mid(0, module.lastIndexOf(QLatin1Char('/')));
|
2011-07-14 07:04:17 +00:00
|
|
|
importCode = QString("import %1 %2.%3\n").arg(module,
|
|
|
|
QString::number(qtObjectType->majorVersion()),
|
|
|
|
QString::number(qtObjectType->minorVersion())).toUtf8();
|
|
|
|
}
|
|
|
|
|
2011-04-27 12:13:26 +00:00
|
|
|
// find all QMetaObjects reachable when the specified module is imported
|
2011-06-21 09:59:49 +00:00
|
|
|
if (action != Path) {
|
2012-05-03 12:42:53 +00:00
|
|
|
importCode += QString("import %0 %1\n").arg(pluginImportUri, pluginImportVersion).toLatin1();
|
2011-04-27 12:13:26 +00:00
|
|
|
} else {
|
|
|
|
// pluginImportVersion can be empty
|
2012-05-03 12:42:53 +00:00
|
|
|
importCode += QString("import \".\" %2\n").arg(pluginImportVersion).toLatin1();
|
2011-04-27 12:13:26 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// create a component with these imports to make sure the imports are valid
|
|
|
|
// and to populate the declarative meta type system
|
|
|
|
{
|
|
|
|
QByteArray code = importCode;
|
|
|
|
code += "QtObject {}";
|
2012-02-16 04:43:03 +00:00
|
|
|
QQmlComponent c(&engine);
|
2011-04-27 12:13:26 +00:00
|
|
|
|
2011-04-28 10:22:30 +00:00
|
|
|
c.setData(code, QUrl::fromLocalFile(pluginImportPath + "/typelist.qml"));
|
2011-04-27 12:13:26 +00:00
|
|
|
c.create();
|
|
|
|
if (!c.errors().isEmpty()) {
|
2012-02-16 04:43:03 +00:00
|
|
|
foreach (const QQmlError &error, c.errors())
|
2011-04-27 12:13:26 +00:00
|
|
|
qWarning() << error.toString();
|
|
|
|
return EXIT_IMPORTERROR;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-10-05 09:42:33 +00:00
|
|
|
QSet<const QMetaObject *> candidates = collectReachableMetaObjects(&engine, defaultTypes);
|
2011-04-27 12:13:26 +00:00
|
|
|
candidates.subtract(defaultReachable);
|
|
|
|
|
|
|
|
// 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, defaultReachable)
|
|
|
|
defaultReachableNames.insert(QByteArray(mo->className()));
|
|
|
|
foreach (const QMetaObject *mo, candidates) {
|
|
|
|
if (!defaultReachableNames.contains(mo->className()))
|
|
|
|
metas.insert(mo);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// setup static rewrites of type names
|
|
|
|
cppToId.insert("QString", "string");
|
2012-02-16 04:43:03 +00:00
|
|
|
cppToId.insert("QQmlEasingValueType::Type", "Type");
|
2011-04-27 12:13:26 +00:00
|
|
|
|
|
|
|
// start dumping data
|
|
|
|
QByteArray bytes;
|
|
|
|
QmlStreamWriter qml(&bytes);
|
|
|
|
|
|
|
|
qml.writeStartDocument();
|
2011-06-21 08:43:14 +00:00
|
|
|
qml.writeLibraryImport(QLatin1String("QtQuick.tooling"), 1, 1);
|
2012-07-03 14:13:46 +00:00
|
|
|
qml.write(QString("\n"
|
2011-04-27 12:13:26 +00:00
|
|
|
"// This file describes the plugin-supplied types contained in the library.\n"
|
|
|
|
"// It is used for QML tooling purposes only.\n"
|
2012-07-03 14:13:46 +00:00
|
|
|
"//\n"
|
|
|
|
"// This file was auto-generated with the command '%1'.\n"
|
|
|
|
"\n").arg(args.join(QLatin1String(" "))));
|
2011-04-27 12:13:26 +00:00
|
|
|
qml.writeStartObject("Module");
|
|
|
|
|
|
|
|
// 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)
|
2011-11-17 12:57:37 +00:00
|
|
|
nameToMeta.insert(convertToId(meta), meta);
|
2011-04-27 12:13:26 +00:00
|
|
|
|
|
|
|
Dumper dumper(&qml);
|
|
|
|
if (relocatable)
|
|
|
|
dumper.setRelocatableModuleUri(pluginImportUri);
|
|
|
|
foreach (const QMetaObject *meta, nameToMeta) {
|
|
|
|
dumper.dump(meta);
|
|
|
|
}
|
2013-09-03 12:03:21 +00:00
|
|
|
foreach (const QQmlType *compositeType, qmlTypesByCompositeName)
|
|
|
|
dumper.dumpComposite(&engine, compositeType, defaultReachableNames);
|
2011-04-27 12:13:26 +00:00
|
|
|
|
2012-02-16 04:43:03 +00:00
|
|
|
// define QEasingCurve as an extension of QQmlEasingValueType, this way
|
2011-04-27 12:13:26 +00:00
|
|
|
// properties using the QEasingCurve type get useful type information.
|
|
|
|
if (pluginImportUri.isEmpty())
|
|
|
|
dumper.writeEasingCurve();
|
|
|
|
|
|
|
|
qml.writeEndObject();
|
|
|
|
qml.writeEndDocument();
|
|
|
|
|
2011-11-03 09:19:33 +00:00
|
|
|
std::cout << bytes.constData() << std::flush;
|
2011-04-27 12:13:26 +00:00
|
|
|
|
|
|
|
// workaround to avoid crashes on exit
|
|
|
|
QTimer timer;
|
|
|
|
timer.setSingleShot(true);
|
|
|
|
timer.setInterval(0);
|
|
|
|
QObject::connect(&timer, SIGNAL(timeout()), &app, SLOT(quit()));
|
|
|
|
timer.start();
|
|
|
|
|
|
|
|
return app.exec();
|
|
|
|
}
|