2011-04-27 12:13:26 +00:00
|
|
|
/****************************************************************************
|
|
|
|
**
|
2016-01-19 11:23:05 +00:00
|
|
|
** Copyright (C) 2016 The Qt Company Ltd.
|
|
|
|
** Contact: https://www.qt.io/licensing/
|
2011-04-27 12:13:26 +00:00
|
|
|
**
|
|
|
|
** This file is part of the tools applications of the Qt Toolkit.
|
|
|
|
**
|
2016-01-19 11:23:05 +00:00
|
|
|
** $QT_BEGIN_LICENSE:GPL-EXCEPT$
|
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
|
2015-01-28 11:55:39 +00:00
|
|
|
** a written agreement between you and The Qt Company. For licensing terms
|
2016-01-19 11:23:05 +00:00
|
|
|
** and conditions see https://www.qt.io/terms-conditions. For further
|
|
|
|
** information use the contact form at https://www.qt.io/contact-us.
|
2012-09-20 05:21:40 +00:00
|
|
|
**
|
2016-01-19 11:23:05 +00:00
|
|
|
** GNU General Public License Usage
|
|
|
|
** Alternatively, this file may be used under the terms of the GNU
|
|
|
|
** General Public License version 3 as published by the Free Software
|
|
|
|
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
|
|
|
|
** included in the packaging of this file. Please review the following
|
|
|
|
** information to ensure the GNU General Public License requirements will
|
|
|
|
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
|
2011-04-27 12:13:26 +00:00
|
|
|
**
|
|
|
|
** $QT_END_LICENSE$
|
|
|
|
**
|
|
|
|
****************************************************************************/
|
|
|
|
|
2012-02-16 04:43:03 +00:00
|
|
|
#include <QtQml/qqmlengine.h>
|
2015-09-14 20:02:55 +00:00
|
|
|
#include <QtQml/private/qqmlengine_p.h>
|
2012-02-16 04:43:03 +00:00
|
|
|
#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>
|
2015-03-17 15:33:14 +00:00
|
|
|
#include <QtCore/QJsonDocument>
|
|
|
|
#include <QtCore/QJsonParseError>
|
|
|
|
#include <QtCore/QJsonValue>
|
|
|
|
#include <QtCore/QJsonArray>
|
|
|
|
#include <QtCore/QJsonObject>
|
|
|
|
#include <QtCore/QProcess>
|
2011-04-27 12:13:26 +00:00
|
|
|
#include <QtCore/private/qobject_p.h>
|
|
|
|
#include <QtCore/private/qmetaobject_p.h>
|
|
|
|
|
2016-01-08 10:25:47 +00:00
|
|
|
#include <QRegularExpression>
|
2011-04-27 12:13:26 +00:00
|
|
|
#include <iostream>
|
2013-09-12 09:06:59 +00:00
|
|
|
#include <algorithm>
|
2011-04-27 12:13:26 +00:00
|
|
|
|
2016-01-08 10:25:47 +00:00
|
|
|
#include "qmltypereader.h"
|
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
|
2014-07-30 12:49:26 +00:00
|
|
|
#ifdef Q_OS_WIN
|
2014-12-02 15:33:39 +00:00
|
|
|
# if !defined(Q_CC_MINGW)
|
|
|
|
# include <crtdbg.h>
|
|
|
|
# endif
|
2014-07-30 12:49:26 +00:00
|
|
|
#include <qt_windows.h>
|
|
|
|
#endif
|
2011-04-27 12:13:26 +00:00
|
|
|
|
2016-12-01 10:02:36 +00:00
|
|
|
namespace {
|
2015-11-10 15:23:16 +00:00
|
|
|
|
2016-12-01 10:02:36 +00:00
|
|
|
const uint qtQmlMajorVersion = 2;
|
|
|
|
const uint qtQmlMinorVersion = 2;
|
|
|
|
const uint qtQuickMajorVersion = 2;
|
|
|
|
const uint qtQuickMinorVersion = 8;
|
2016-04-13 12:58:28 +00:00
|
|
|
|
|
|
|
const QString qtQuickQualifiedName = QString::fromLatin1("QtQuick %1.%2")
|
|
|
|
.arg(qtQuickMajorVersion)
|
|
|
|
.arg(qtQuickMinorVersion);
|
2015-11-10 15:23:16 +00:00
|
|
|
|
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;
|
|
|
|
|
2016-12-01 10:02:36 +00:00
|
|
|
}
|
|
|
|
|
2015-03-17 15:33:14 +00:00
|
|
|
static QString enquote(const QString &string)
|
|
|
|
{
|
|
|
|
QString s = string;
|
|
|
|
return QString("\"%1\"").arg(s.replace(QLatin1Char('\\'), QLatin1String("\\\\"))
|
|
|
|
.replace(QLatin1Char('"'),QLatin1String("\\\"")));
|
|
|
|
}
|
|
|
|
|
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)
|
2014-01-22 18:19:54 +00:00
|
|
|
std::cerr << "Processing object" << qPrintable( meta->className() ) << std::endl;
|
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)
|
2014-01-22 18:19:54 +00:00
|
|
|
std::cerr << " Processing property" << qPrintable( prop.name() ) << std::endl;
|
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();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-09-14 20:02:55 +00:00
|
|
|
void collectReachableMetaObjects(QQmlEnginePrivate *engine, 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());
|
2015-09-14 20:02:55 +00:00
|
|
|
if (ty->attachedPropertiesType(engine))
|
|
|
|
collectReachableMetaObjects(ty->attachedPropertiesType(engine), metas);
|
2011-04-27 12:13:26 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* 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
|
|
|
|
2015-10-22 10:33:43 +00:00
|
|
|
/* A composite type is completely specified by name, major version and minor version.
|
|
|
|
*/
|
|
|
|
static QMap<QString, QSet<const QQmlType *> > qmlTypesByCompositeName;
|
2013-09-03 12:03:21 +00:00
|
|
|
|
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;
|
|
|
|
|
2014-01-22 18:19:54 +00:00
|
|
|
std::cerr << "Found a QMetaObject without a className, generating a random name" << std::endl;
|
2011-11-17 12:57:37 +00:00
|
|
|
className = QByteArray("error-unknown-name-");
|
|
|
|
className.append(QByteArray::number(generatedNames.size()));
|
|
|
|
generatedNames.insert(mo, className);
|
|
|
|
return className;
|
|
|
|
}
|
|
|
|
|
2014-01-20 17:37:32 +00:00
|
|
|
|
|
|
|
// Collect all metaobjects for types registered with qmlRegisterType() without parameters
|
2015-09-14 20:02:55 +00:00
|
|
|
void collectReachableMetaObjectsWithoutQmlName(QQmlEnginePrivate *engine, QSet<const QMetaObject *>& metas ) {
|
2014-01-20 17:37:32 +00:00
|
|
|
foreach (const QQmlType *ty, QQmlMetaType::qmlAllTypes()) {
|
|
|
|
if ( ! metas.contains(ty->metaObject()) ) {
|
|
|
|
if (!ty->isComposite()) {
|
2015-09-14 20:02:55 +00:00
|
|
|
collectReachableMetaObjects(engine, ty, &metas);
|
2014-01-20 17:37:32 +00:00
|
|
|
} else {
|
2015-10-22 10:33:43 +00:00
|
|
|
qmlTypesByCompositeName[ty->elementName()].insert(ty);
|
2014-01-20 17:37:32 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-01-20 15:40:30 +00:00
|
|
|
QSet<const QMetaObject *> collectReachableMetaObjects(QQmlEngine *engine,
|
|
|
|
QSet<const QMetaObject *> &noncreatables,
|
|
|
|
QSet<const QMetaObject *> &singletons,
|
|
|
|
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()) {
|
2014-01-20 15:40:30 +00:00
|
|
|
if (!ty->isCreatable())
|
|
|
|
noncreatables.insert(ty->metaObject());
|
|
|
|
if (ty->isSingleton())
|
|
|
|
singletons.insert(ty->metaObject());
|
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());
|
2015-09-14 20:02:55 +00:00
|
|
|
collectReachableMetaObjects(QQmlEnginePrivate::get(engine), ty, &metas);
|
2013-09-03 12:03:21 +00:00
|
|
|
} else {
|
2015-10-22 10:33:43 +00:00
|
|
|
qmlTypesByCompositeName[ty->elementName()].insert(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.
|
2016-01-15 12:23:25 +00:00
|
|
|
for (auto it = extensions.cbegin(), end = extensions.cend(); it != end; ++it) {
|
|
|
|
QSet<const QQmlType *> baseExports = qmlTypesByCppName.value(it.key());
|
2011-06-22 15:13:56 +00:00
|
|
|
|
2016-01-15 12:23:25 +00:00
|
|
|
const QSet<QByteArray> extensionCppNames = it.value();
|
2016-08-11 10:08:00 +00:00
|
|
|
for (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;
|
2016-08-11 10:08:00 +00:00
|
|
|
for (const QQmlType *baseExport : qAsConst(baseExports)) {
|
2011-06-22 15:13:56 +00:00
|
|
|
bool match = false;
|
2016-08-11 10:08:00 +00:00
|
|
|
for (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
|
|
|
}
|
2016-01-15 12:23:25 +00:00
|
|
|
qmlTypesByCppName[it.key()] = 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();
|
2013-06-10 09:16:38 +00:00
|
|
|
if (!siinfo) {
|
2014-01-22 18:19:54 +00:00
|
|
|
std::cerr << "Internal error, " << qPrintable(tyName)
|
|
|
|
<< "(" << qPrintable( QString::fromUtf8(ty->typeName()) ) << ")"
|
|
|
|
<< " is singleton, but has no singletonInstanceInfo" << std::endl;
|
2013-06-10 09:16:38 +00:00
|
|
|
continue;
|
|
|
|
}
|
2013-05-02 17:42:31 +00:00
|
|
|
if (siinfo->qobjectCallback) {
|
2013-06-10 09:16:38 +00:00
|
|
|
if (verbose)
|
2014-01-22 18:19:54 +00:00
|
|
|
std::cerr << "Trying to get singleton for " << qPrintable(tyName)
|
|
|
|
<< " (" << qPrintable( siinfo->typeName ) << ")" << std::endl;
|
2013-05-02 17:42:31 +00:00
|
|
|
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-06-10 09:16:38 +00:00
|
|
|
if (verbose)
|
2014-01-22 18:19:54 +00:00
|
|
|
std::cerr << "Trying to create object " << qPrintable( tyName )
|
|
|
|
<< " (" << qPrintable( QString::fromUtf8(ty->typeName()) ) << ")" << std::endl;
|
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-06-10 09:16:38 +00:00
|
|
|
if (object) {
|
|
|
|
if (verbose)
|
2014-01-22 18:19:54 +00:00
|
|
|
std::cerr << "Got " << qPrintable( tyName )
|
|
|
|
<< " (" << qPrintable( QString::fromUtf8(ty->typeName()) ) << ")" << std::endl;
|
2013-05-02 17:42:31 +00:00
|
|
|
collectReachableMetaObjects(object, &metas);
|
2014-03-25 08:07:46 +00:00
|
|
|
object->deleteLater();
|
2013-06-10 09:16:38 +00:00
|
|
|
} else {
|
2014-01-22 18:19:54 +00:00
|
|
|
std::cerr << "Could not create" << qPrintable(tyName) << std::endl;
|
2013-06-10 09:16:38 +00:00
|
|
|
}
|
2013-05-02 17:42:31 +00:00
|
|
|
}
|
2011-04-27 12:13:26 +00:00
|
|
|
}
|
|
|
|
|
2015-09-14 20:02:55 +00:00
|
|
|
collectReachableMetaObjectsWithoutQmlName(QQmlEnginePrivate::get(engine), metas);
|
2014-01-20 17:37:32 +00:00
|
|
|
|
2011-04-27 12:13:26 +00:00
|
|
|
return metas;
|
|
|
|
}
|
|
|
|
|
2014-04-09 13:42:06 +00:00
|
|
|
class KnownAttributes {
|
|
|
|
QHash<QByteArray, int> m_properties;
|
|
|
|
QHash<QByteArray, QHash<int, int> > m_methods;
|
|
|
|
public:
|
|
|
|
bool knownMethod(const QByteArray &name, int nArgs, int revision)
|
|
|
|
{
|
|
|
|
if (m_methods.contains(name)) {
|
|
|
|
QHash<int, int> overloads = m_methods.value(name);
|
|
|
|
if (overloads.contains(nArgs) && overloads.value(nArgs) <= revision)
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
m_methods[name][nArgs] = revision;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool knownProperty(const QByteArray &name, int revision)
|
|
|
|
{
|
|
|
|
if (m_properties.contains(name) && m_properties.value(name) <= revision)
|
|
|
|
return true;
|
|
|
|
m_properties[name] = revision;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
};
|
2011-04-27 12:13:26 +00:00
|
|
|
|
|
|
|
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);
|
|
|
|
}
|
2015-10-13 10:26:45 +00:00
|
|
|
if (qmlTyName.startsWith(QLatin1Char('/'))) {
|
2013-09-03 12:03:21 +00:00
|
|
|
qmlTyName.remove(0, 1);
|
|
|
|
}
|
|
|
|
const QString exportString = enquote(
|
|
|
|
QString("%1 %2.%3").arg(
|
|
|
|
qmlTyName,
|
|
|
|
QString::number(majorVersion),
|
|
|
|
QString::number(minorVersion)));
|
|
|
|
return exportString;
|
|
|
|
}
|
|
|
|
|
2014-04-09 13:42:06 +00:00
|
|
|
void writeMetaContent(const QMetaObject *meta, KnownAttributes *knownAttributes = 0)
|
2013-09-03 12:03:21 +00:00
|
|
|
{
|
|
|
|
QSet<QString> implicitSignals;
|
|
|
|
for (int index = meta->propertyOffset(); index < meta->propertyCount(); ++index) {
|
|
|
|
const QMetaProperty &property = meta->property(index);
|
2014-04-09 13:42:06 +00:00
|
|
|
dump(property, knownAttributes);
|
|
|
|
if (knownAttributes)
|
|
|
|
knownAttributes->knownMethod(QByteArray(property.name()).append("Changed"),
|
|
|
|
0, property.revision());
|
2013-09-03 12:03:21 +00:00
|
|
|
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;
|
2014-04-09 13:42:06 +00:00
|
|
|
dump(method, implicitSignals, knownAttributes);
|
2013-09-03 12:03:21 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// and add toString(), destroy() and destroy(int)
|
2014-04-09 13:42:06 +00:00
|
|
|
if (!knownAttributes || !knownAttributes->knownMethod(QByteArray("toString"), 0, 0)) {
|
|
|
|
qml->writeStartObject(QLatin1String("Method"));
|
|
|
|
qml->writeScriptBinding(QLatin1String("name"), enquote(QLatin1String("toString")));
|
|
|
|
qml->writeEndObject();
|
|
|
|
}
|
|
|
|
if (!knownAttributes || !knownAttributes->knownMethod(QByteArray("destroy"), 0, 0)) {
|
|
|
|
qml->writeStartObject(QLatin1String("Method"));
|
|
|
|
qml->writeScriptBinding(QLatin1String("name"), enquote(QLatin1String("destroy")));
|
|
|
|
qml->writeEndObject();
|
|
|
|
}
|
|
|
|
if (!knownAttributes || !knownAttributes->knownMethod(QByteArray("destroy"), 1, 0)) {
|
|
|
|
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();
|
|
|
|
}
|
2013-09-03 12:03:21 +00:00
|
|
|
} else {
|
|
|
|
for (int index = meta->methodOffset(); index < meta->methodCount(); ++index)
|
2014-04-09 13:42:06 +00:00
|
|
|
dump(meta->method(index), implicitSignals, knownAttributes);
|
2013-09-03 12:03:21 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-04-09 13:42:06 +00:00
|
|
|
QString getPrototypeNameForCompositeType(const QMetaObject *metaObject, QSet<QByteArray> &defaultReachableNames,
|
|
|
|
QList<const QMetaObject *> *objectsToMerge)
|
2013-09-03 12:03:21 +00:00
|
|
|
{
|
|
|
|
QString prototypeName;
|
2013-09-16 10:40:30 +00:00
|
|
|
if (!defaultReachableNames.contains(metaObject->className())) {
|
2014-04-09 13:42:06 +00:00
|
|
|
// dynamic meta objects can break things badly
|
|
|
|
// but extended types are usually fine
|
|
|
|
const QMetaObjectPrivate *mop = reinterpret_cast<const QMetaObjectPrivate *>(metaObject->d.data);
|
|
|
|
if (!(mop->flags & DynamicMetaObject) && objectsToMerge
|
|
|
|
&& !objectsToMerge->contains(metaObject))
|
|
|
|
objectsToMerge->append(metaObject);
|
2013-09-16 10:40:30 +00:00
|
|
|
const QMetaObject *superMetaObject = metaObject->superClass();
|
|
|
|
if (!superMetaObject)
|
|
|
|
prototypeName = "QObject";
|
|
|
|
else
|
2014-04-09 13:42:06 +00:00
|
|
|
prototypeName = getPrototypeNameForCompositeType(
|
|
|
|
superMetaObject, defaultReachableNames, objectsToMerge);
|
2013-09-16 10:40:30 +00:00
|
|
|
} else {
|
|
|
|
prototypeName = convertToId(metaObject->className());
|
|
|
|
}
|
2013-09-03 12:03:21 +00:00
|
|
|
return prototypeName;
|
|
|
|
}
|
|
|
|
|
2015-10-22 10:33:43 +00:00
|
|
|
void dumpComposite(QQmlEngine *engine, const QSet<const QQmlType *> &compositeType, QSet<QByteArray> &defaultReachableNames)
|
|
|
|
{
|
2016-08-11 10:08:00 +00:00
|
|
|
for (const QQmlType *type : compositeType)
|
2015-10-22 10:33:43 +00:00
|
|
|
dumpCompositeItem(engine, type, defaultReachableNames);
|
|
|
|
}
|
|
|
|
|
|
|
|
void dumpCompositeItem(QQmlEngine *engine, const QQmlType *compositeType, QSet<QByteArray> &defaultReachableNames)
|
2013-09-03 12:03:21 +00:00
|
|
|
{
|
|
|
|
QQmlComponent e(engine, compositeType->sourceUrl());
|
2015-07-23 08:39:25 +00:00
|
|
|
if (!e.isReady()) {
|
|
|
|
std::cerr << "WARNING: skipping module " << compositeType->elementName().toStdString()
|
|
|
|
<< std::endl << e.errorString().toStdString() << std::endl;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2013-09-03 12:03:21 +00:00
|
|
|
QObject *object = e.create();
|
|
|
|
|
|
|
|
if (!object)
|
|
|
|
return;
|
|
|
|
|
|
|
|
qml->writeStartObject("Component");
|
|
|
|
|
|
|
|
const QMetaObject *mainMeta = object->metaObject();
|
|
|
|
|
2014-04-09 13:42:06 +00:00
|
|
|
QList<const QMetaObject *> objectsToMerge;
|
|
|
|
KnownAttributes knownAttributes;
|
2013-09-03 12:03:21 +00:00
|
|
|
// Get C++ base class name for the composite type
|
2014-04-09 13:42:06 +00:00
|
|
|
QString prototypeName = getPrototypeNameForCompositeType(mainMeta, defaultReachableNames,
|
|
|
|
&objectsToMerge);
|
2013-09-03 12:03:21 +00:00
|
|
|
qml->writeScriptBinding(QLatin1String("prototype"), enquote(prototypeName));
|
|
|
|
|
|
|
|
QString qmlTyName = compositeType->qmlTypeName();
|
|
|
|
const QString exportString = getExportString(qmlTyName, compositeType->majorVersion(), compositeType->minorVersion());
|
2015-10-22 10:33:43 +00:00
|
|
|
qml->writeScriptBinding(QLatin1String("name"), exportString);
|
2013-09-03 12:03:21 +00:00
|
|
|
qml->writeArrayBinding(QLatin1String("exports"), QStringList() << exportString);
|
|
|
|
qml->writeArrayBinding(QLatin1String("exportMetaObjectRevisions"), QStringList() << QString::number(compositeType->minorVersion()));
|
2014-02-13 15:33:18 +00:00
|
|
|
qml->writeBooleanBinding(QLatin1String("isComposite"), true);
|
2013-09-03 12:03:21 +00:00
|
|
|
|
2014-04-09 13:39:05 +00:00
|
|
|
if (compositeType->isSingleton()) {
|
2014-02-13 15:32:17 +00:00
|
|
|
qml->writeBooleanBinding(QLatin1String("isCreatable"), false);
|
|
|
|
qml->writeBooleanBinding(QLatin1String("isSingleton"), true);
|
2014-04-09 13:39:05 +00:00
|
|
|
}
|
2014-01-20 15:40:30 +00:00
|
|
|
|
2013-09-03 12:03:21 +00:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-08-11 10:08:00 +00:00
|
|
|
for (const QMetaObject *meta : qAsConst(objectsToMerge))
|
2014-04-09 13:42:06 +00:00
|
|
|
writeMetaContent(meta, &knownAttributes);
|
2013-09-03 12:03:21 +00:00
|
|
|
|
|
|
|
qml->writeEndObject();
|
|
|
|
}
|
|
|
|
|
2015-09-14 20:02:55 +00:00
|
|
|
void dump(QQmlEnginePrivate *engine, const QMetaObject *meta, bool isUncreatable, bool isSingleton)
|
2011-04-27 12:13:26 +00:00
|
|
|
{
|
|
|
|
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
|
|
|
|
2016-08-11 10:08:00 +00:00
|
|
|
const 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
|
|
|
|
2016-08-11 10:08:00 +00:00
|
|
|
for (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);
|
|
|
|
|
2014-01-20 15:40:30 +00:00
|
|
|
if (isUncreatable)
|
2014-02-13 15:32:17 +00:00
|
|
|
qml->writeBooleanBinding(QLatin1String("isCreatable"), false);
|
2014-01-20 15:40:30 +00:00
|
|
|
|
|
|
|
if (isSingleton)
|
2014-02-13 15:32:17 +00:00
|
|
|
qml->writeBooleanBinding(QLatin1String("isSingleton"), true);
|
2014-01-20 15:40:30 +00:00
|
|
|
|
2013-04-10 09:26:16 +00:00
|
|
|
// write meta object revisions
|
2011-09-21 10:54:10 +00:00
|
|
|
QStringList metaObjectRevisions;
|
2016-08-11 10:08:00 +00:00
|
|
|
for (const QString &exportString : qAsConst(exportStrings)) {
|
2011-09-21 10:54:10 +00:00
|
|
|
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
|
|
|
|
2015-09-14 20:02:55 +00:00
|
|
|
if (const QMetaObject *attachedType = (*qmlTypes.begin())->attachedPropertiesType(engine)) {
|
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:
|
|
|
|
|
|
|
|
/* 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"));
|
|
|
|
}
|
|
|
|
|
2014-04-09 13:42:06 +00:00
|
|
|
void dump(const QMetaProperty &prop, KnownAttributes *knownAttributes = 0)
|
2011-04-27 12:13:26 +00:00
|
|
|
{
|
2014-04-09 13:42:06 +00:00
|
|
|
int revision = prop.revision();
|
|
|
|
QByteArray propName = prop.name();
|
|
|
|
if (knownAttributes && knownAttributes->knownProperty(propName, revision))
|
|
|
|
return;
|
2011-04-27 12:13:26 +00:00
|
|
|
qml->writeStartObject("Property");
|
|
|
|
qml->writeScriptBinding(QLatin1String("name"), enquote(QString::fromUtf8(prop.name())));
|
2014-04-09 13:42:06 +00:00
|
|
|
if (revision)
|
2011-05-30 07:24:20 +00:00
|
|
|
qml->writeScriptBinding(QLatin1String("revision"), QString::number(revision));
|
2011-04-27 12:13:26 +00:00
|
|
|
writeTypeProperties(prop.typeName(), prop.isWritable());
|
|
|
|
|
|
|
|
qml->writeEndObject();
|
|
|
|
}
|
|
|
|
|
2014-04-09 13:42:06 +00:00
|
|
|
void dump(const QMetaMethod &meth, const QSet<QString> &implicitSignals,
|
|
|
|
KnownAttributes *knownAttributes = 0)
|
2011-04-27 12:13:26 +00:00
|
|
|
{
|
|
|
|
if (meth.methodType() == QMetaMethod::Signal) {
|
2013-09-18 07:32:45 +00:00
|
|
|
if (meth.access() != QMetaMethod::Public)
|
2011-04-27 12:13:26 +00:00
|
|
|
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
|
|
|
|
2014-04-09 13:42:06 +00:00
|
|
|
int revision = meth.revision();
|
|
|
|
if (knownAttributes && knownAttributes->knownMethod(name, meth.parameterNames().size(), revision))
|
|
|
|
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));
|
|
|
|
|
2014-04-09 13:42:06 +00:00
|
|
|
if (revision)
|
2011-05-30 07:24:20 +00:00
|
|
|
qml->writeScriptBinding(QLatin1String("revision"), QString::number(revision));
|
|
|
|
|
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;
|
2015-06-06 15:57:33 +00:00
|
|
|
const int keyCount = e.keyCount();
|
|
|
|
namesValues.reserve(keyCount);
|
|
|
|
for (int index = 0; index < keyCount; ++index) {
|
2011-04-27 12:13:26 +00:00
|
|
|
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)
|
|
|
|
{
|
2014-01-20 15:40:30 +00:00
|
|
|
std::cerr << qPrintable(QString(
|
2016-04-13 12:58:28 +00:00
|
|
|
"Usage: %1 [-v] [-noinstantiate] [-defaultplatform] [-[non]relocatable] [-dependencies <dependencies.json>] [-merge <file-to-merge.qmltypes>] [-noforceqtquick] module.uri version [module/import/path]\n"
|
2013-05-02 17:42:31 +00:00
|
|
|
" %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(
|
2014-01-20 15:40:30 +00:00
|
|
|
appName)) << std::endl;
|
2011-04-27 12:13:26 +00:00
|
|
|
}
|
|
|
|
|
2015-03-17 15:33:14 +00:00
|
|
|
static bool readDependenciesData(QString dependenciesFile, const QByteArray &fileData,
|
2016-04-13 12:58:28 +00:00
|
|
|
QStringList *dependencies, const QStringList &urisToSkip,
|
|
|
|
bool forceQtQuickDependency = true) {
|
2015-03-17 15:33:14 +00:00
|
|
|
if (verbose) {
|
|
|
|
std::cerr << "parsing "
|
|
|
|
<< qPrintable( dependenciesFile ) << " skipping";
|
2016-08-11 10:08:00 +00:00
|
|
|
for (const QString &uriToSkip : urisToSkip)
|
2015-10-13 10:26:45 +00:00
|
|
|
std::cerr << ' ' << qPrintable(uriToSkip);
|
2015-03-17 15:33:14 +00:00
|
|
|
std::cerr << std::endl;
|
|
|
|
}
|
|
|
|
QJsonParseError parseError;
|
|
|
|
parseError.error = QJsonParseError::NoError;
|
|
|
|
QJsonDocument doc = QJsonDocument::fromJson(fileData, &parseError);
|
|
|
|
if (parseError.error != QJsonParseError::NoError) {
|
|
|
|
std::cerr << "Error parsing dependencies file " << dependenciesFile.toStdString()
|
|
|
|
<< ":" << parseError.errorString().toStdString() << " at " << parseError.offset
|
|
|
|
<< std::endl;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
if (doc.isArray()) {
|
2016-08-11 10:08:00 +00:00
|
|
|
const QStringList requiredKeys = QStringList() << QStringLiteral("name")
|
|
|
|
<< QStringLiteral("type")
|
|
|
|
<< QStringLiteral("version");
|
2015-03-17 15:33:14 +00:00
|
|
|
foreach (const QJsonValue &dep, doc.array()) {
|
|
|
|
if (dep.isObject()) {
|
|
|
|
QJsonObject obj = dep.toObject();
|
2016-08-11 10:08:00 +00:00
|
|
|
for (const QString &requiredKey : requiredKeys)
|
2015-03-17 15:33:14 +00:00
|
|
|
if (!obj.contains(requiredKey) || obj.value(requiredKey).isString())
|
|
|
|
continue;
|
|
|
|
if (obj.value(QStringLiteral("type")).toString() != QLatin1String("module"))
|
|
|
|
continue;
|
|
|
|
QString name = obj.value((QStringLiteral("name"))).toString();
|
|
|
|
QString version = obj.value(QStringLiteral("version")).toString();
|
|
|
|
if (name.isEmpty() || urisToSkip.contains(name) || version.isEmpty())
|
|
|
|
continue;
|
2016-04-15 08:18:51 +00:00
|
|
|
if (name.endsWith(QLatin1String("Private"), Qt::CaseInsensitive)) {
|
2015-03-17 15:33:14 +00:00
|
|
|
if (verbose)
|
|
|
|
std::cerr << "skipping private dependecy "
|
|
|
|
<< qPrintable( name ) << " " << qPrintable(version) << std::endl;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if (verbose)
|
|
|
|
std::cerr << "appending dependency "
|
|
|
|
<< qPrintable( name ) << " " << qPrintable(version) << std::endl;
|
|
|
|
dependencies->append(name + QLatin1Char(' ')+version);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
std::cerr << "Error parsing dependencies file " << dependenciesFile.toStdString()
|
|
|
|
<< ": expected an array" << std::endl;
|
|
|
|
return false;
|
|
|
|
}
|
2016-01-06 11:49:02 +00:00
|
|
|
// Workaround for avoiding conflicting types when no dependency has been found.
|
|
|
|
//
|
|
|
|
// qmlplugindump used to import QtQuick, so all types defined in QtQuick used to be skipped when dumping.
|
|
|
|
// Now that it imports only Qt, it is no longer the case: if no dependency is found all the types defined
|
|
|
|
// in QtQuick will be dumped, causing conflicts.
|
2016-04-13 12:58:28 +00:00
|
|
|
if (forceQtQuickDependency && dependencies->isEmpty())
|
|
|
|
dependencies->push_back(qtQuickQualifiedName);
|
2015-03-17 15:33:14 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2016-01-18 19:53:49 +00:00
|
|
|
static bool readDependenciesFile(const QString &dependenciesFile, QStringList *dependencies,
|
2015-03-17 15:33:14 +00:00
|
|
|
const QStringList &urisToSkip) {
|
2016-01-18 19:53:49 +00:00
|
|
|
if (!QFileInfo::exists(dependenciesFile)) {
|
2015-03-17 15:33:14 +00:00
|
|
|
std::cerr << "non existing dependencies file " << dependenciesFile.toStdString()
|
|
|
|
<< std::endl;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
QFile f(dependenciesFile);
|
|
|
|
if (!f.open(QFileDevice::ReadOnly)) {
|
|
|
|
std::cerr << "non existing dependencies file " << dependenciesFile.toStdString()
|
|
|
|
<< ", " << f.errorString().toStdString() << std::endl;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
QByteArray fileData = f.readAll();
|
2016-04-13 12:58:28 +00:00
|
|
|
return readDependenciesData(dependenciesFile, fileData, dependencies, urisToSkip, false);
|
2015-03-17 15:33:14 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static bool getDependencies(const QQmlEngine &engine, const QString &pluginImportUri,
|
2016-04-13 12:58:28 +00:00
|
|
|
const QString &pluginImportVersion, QStringList *dependencies,
|
|
|
|
bool forceQtQuickDependency)
|
2015-03-17 15:33:14 +00:00
|
|
|
{
|
|
|
|
QFileInfo selfExe(QCoreApplication::applicationFilePath());
|
|
|
|
QString command = selfExe.absoluteDir().filePath(QLatin1String("qmlimportscanner")
|
|
|
|
+ selfExe.suffix());
|
|
|
|
|
|
|
|
QStringList commandArgs = QStringList()
|
|
|
|
<< QLatin1String("-qmlFiles")
|
|
|
|
<< QLatin1String("-");
|
|
|
|
foreach (const QString &path, engine.importPathList())
|
|
|
|
commandArgs << QLatin1String("-importPath") << path;
|
|
|
|
|
|
|
|
QProcess importScanner;
|
|
|
|
importScanner.start(command, commandArgs, QProcess::ReadWrite);
|
|
|
|
if (!importScanner.waitForStarted())
|
|
|
|
return false;
|
|
|
|
|
|
|
|
importScanner.write("import ");
|
|
|
|
importScanner.write(pluginImportUri.toUtf8());
|
|
|
|
importScanner.write(" ");
|
|
|
|
importScanner.write(pluginImportVersion.toUtf8());
|
|
|
|
importScanner.write("\nQtObject{}\n");
|
|
|
|
importScanner.closeWriteChannel();
|
|
|
|
|
|
|
|
if (!importScanner.waitForFinished()) {
|
|
|
|
std::cerr << "failure to start " << qPrintable(command);
|
2016-08-11 10:08:00 +00:00
|
|
|
for (const QString &arg : qAsConst(commandArgs))
|
2015-10-13 10:26:45 +00:00
|
|
|
std::cerr << ' ' << qPrintable(arg);
|
2015-03-17 15:33:14 +00:00
|
|
|
std::cerr << std::endl;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
QByteArray depencenciesData = importScanner.readAllStandardOutput();
|
|
|
|
if (!readDependenciesData(QLatin1String("<outputOfQmlimportscanner>"), depencenciesData,
|
2016-04-13 12:58:28 +00:00
|
|
|
dependencies, QStringList(pluginImportUri), forceQtQuickDependency)) {
|
2015-03-17 15:33:14 +00:00
|
|
|
std::cerr << "failed to proecess output of qmlimportscanner" << std::endl;
|
|
|
|
return false;
|
|
|
|
}
|
2015-10-15 15:26:04 +00:00
|
|
|
|
|
|
|
QStringList aux;
|
2016-08-11 10:08:00 +00:00
|
|
|
for (const QString &str : qAsConst(*dependencies)) {
|
2015-10-15 15:26:04 +00:00
|
|
|
if (!str.startsWith("Qt.test.qtestroot"))
|
|
|
|
aux += str;
|
|
|
|
}
|
|
|
|
*dependencies = aux;
|
|
|
|
|
2015-03-17 15:33:14 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool compactDependencies(QStringList *dependencies)
|
|
|
|
{
|
|
|
|
if (dependencies->isEmpty())
|
|
|
|
return false;
|
|
|
|
dependencies->sort();
|
|
|
|
QStringList oldDep = dependencies->first().split(QLatin1Char(' '));
|
|
|
|
Q_ASSERT(oldDep.size() == 2);
|
|
|
|
int oldPos = 0;
|
|
|
|
for (int idep = 1; idep < dependencies->size(); ++idep) {
|
|
|
|
QString depStr = dependencies->at(idep);
|
|
|
|
const QStringList newDep = depStr.split(QLatin1Char(' '));
|
|
|
|
Q_ASSERT(newDep.size() == 2);
|
|
|
|
if (newDep.first() != oldDep.first()) {
|
|
|
|
if (++oldPos != idep)
|
|
|
|
dependencies->replace(oldPos, depStr);
|
|
|
|
oldDep = newDep;
|
|
|
|
} else {
|
|
|
|
QStringList v1 = oldDep.last().split(QLatin1Char('.'));
|
|
|
|
QStringList v2 = newDep.last().split(QLatin1Char('.'));
|
|
|
|
Q_ASSERT(v1.size() == 2);
|
|
|
|
Q_ASSERT(v2.size() == 2);
|
|
|
|
bool ok;
|
|
|
|
int major1 = v1.first().toInt(&ok);
|
|
|
|
Q_ASSERT(ok);
|
|
|
|
int major2 = v2.first().toInt(&ok);
|
|
|
|
Q_ASSERT(ok);
|
|
|
|
if (major1 != major2) {
|
|
|
|
std::cerr << "Found a dependency on " << qPrintable(oldDep.first())
|
|
|
|
<< " with two major versions:" << qPrintable(oldDep.last())
|
|
|
|
<< " and " << qPrintable(newDep.last())
|
|
|
|
<< " which is unsupported, discarding smaller version" << std::endl;
|
|
|
|
if (major1 < major2)
|
|
|
|
dependencies->replace(oldPos, depStr);
|
|
|
|
} else {
|
|
|
|
int minor1 = v1.last().toInt(&ok);
|
|
|
|
Q_ASSERT(ok);
|
|
|
|
int minor2 = v2.last().toInt(&ok);
|
|
|
|
Q_ASSERT(ok);
|
|
|
|
if (minor1 < minor2)
|
|
|
|
dependencies->replace(oldPos, depStr);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (++oldPos < dependencies->size()) {
|
|
|
|
*dependencies = dependencies->mid(0, oldPos);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2014-02-05 10:26:32 +00:00
|
|
|
inline std::wostream &operator<<(std::wostream &str, const QString &s)
|
|
|
|
{
|
|
|
|
#ifdef Q_OS_WIN
|
|
|
|
str << reinterpret_cast<const wchar_t *>(s.utf16());
|
|
|
|
#else
|
|
|
|
str << s.toStdWString();
|
|
|
|
#endif
|
|
|
|
return str;
|
|
|
|
}
|
|
|
|
|
|
|
|
void printDebugMessage(QtMsgType, const QMessageLogContext &, const QString &msg)
|
|
|
|
{
|
|
|
|
std::wcerr << msg << std::endl;
|
|
|
|
// In case of QtFatalMsg the calling code will abort() when appropriate.
|
|
|
|
}
|
|
|
|
|
2015-07-23 08:39:25 +00:00
|
|
|
|
2011-04-27 12:13:26 +00:00
|
|
|
int main(int argc, char *argv[])
|
|
|
|
{
|
2014-09-19 09:59:42 +00:00
|
|
|
#if defined(Q_OS_WIN) && !defined(Q_CC_MINGW)
|
2014-07-30 12:49:26 +00:00
|
|
|
// we do not want windows popping up if the module loaded triggers an assert
|
|
|
|
SetErrorMode(SEM_NOGPFAULTERRORBOX);
|
|
|
|
_CrtSetReportMode(_CRT_ASSERT, _CRTDBG_MODE_DEBUG);
|
|
|
|
_CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_DEBUG);
|
|
|
|
_CrtSetReportMode(_CRT_ERROR, _CRTDBG_MODE_DEBUG);
|
2014-09-19 09:59:42 +00:00
|
|
|
#endif // Q_OS_WIN && !Q_CC_MINGW
|
2014-02-05 10:26:32 +00:00
|
|
|
// The default message handler might not print to console on some systems. Enforce this.
|
|
|
|
qInstallMessageHandler(printDebugMessage);
|
2011-04-27 12:13:26 +00:00
|
|
|
#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
|
2013-09-18 09:18:31 +00:00
|
|
|
bool requireWindowManager = false;
|
|
|
|
for (int index = 1; index < argc; ++index) {
|
|
|
|
if (QString::fromLocal8Bit(argv[index]) == "--defaultplatform"
|
|
|
|
|| QString::fromLocal8Bit(argv[index]) == "-defaultplatform") {
|
|
|
|
requireWindowManager = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-07-19 20:00:54 +00:00
|
|
|
if (!requireWindowManager && qEnvironmentVariableIsEmpty("QT_QPA_PLATFORM"))
|
2013-09-18 09:18:31 +00:00
|
|
|
qputenv("QT_QPA_PLATFORM", QByteArrayLiteral("minimal"));
|
2016-06-28 11:17:30 +00:00
|
|
|
else
|
|
|
|
QCoreApplication::setAttribute(Qt::AA_ShareOpenGLContexts, true);
|
2012-11-30 09:55:07 +00:00
|
|
|
|
2011-12-08 08:52:01 +00:00
|
|
|
QGuiApplication app(argc, argv);
|
2016-11-08 12:09:54 +00:00
|
|
|
QCoreApplication::setApplicationVersion(QLatin1String(QT_VERSION_STR));
|
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;
|
2015-03-17 15:33:14 +00:00
|
|
|
QString dependenciesFile;
|
2016-01-08 10:25:47 +00:00
|
|
|
QString mergeFile;
|
2016-04-13 12:58:28 +00:00
|
|
|
bool forceQtQuickDependency = 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;
|
2015-03-17 15:33:14 +00:00
|
|
|
|
|
|
|
for (int iArg = 0; iArg < args.size(); ++iArg) {
|
|
|
|
const QString &arg = args.at(iArg);
|
2011-04-27 12:13:26 +00:00
|
|
|
if (!arg.startsWith(QLatin1Char('-'))) {
|
|
|
|
positionalArgs.append(arg);
|
|
|
|
continue;
|
|
|
|
}
|
2015-03-17 15:33:14 +00:00
|
|
|
if (arg == QLatin1String("--dependencies")
|
|
|
|
|| arg == QLatin1String("-dependencies")) {
|
|
|
|
if (++iArg == args.size()) {
|
|
|
|
std::cerr << "missing dependencies file" << std::endl;
|
|
|
|
return EXIT_INVALIDARGUMENTS;
|
|
|
|
}
|
|
|
|
dependenciesFile = args.at(iArg);
|
2016-01-08 10:25:47 +00:00
|
|
|
} else if (arg == QLatin1String("--merge")
|
|
|
|
|| arg == QLatin1String("-merge")) {
|
|
|
|
if (++iArg == args.size()) {
|
|
|
|
std::cerr << "missing merge file" << std::endl;
|
|
|
|
return EXIT_INVALIDARGUMENTS;
|
|
|
|
}
|
|
|
|
mergeFile = args.at(iArg);
|
2015-03-17 15:33:14 +00:00
|
|
|
} else 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;
|
2016-04-13 12:58:28 +00:00
|
|
|
} else if (arg == QLatin1String("--noforceqtquick")
|
|
|
|
|| arg == QLatin1String("-noforceqtquick")){
|
|
|
|
forceQtQuickDependency = false;
|
2013-09-18 09:18:31 +00:00
|
|
|
} else if (arg == QLatin1String("--defaultplatform")
|
|
|
|
|| arg == QLatin1String("-defaultplatform")) {
|
|
|
|
continue;
|
2011-04-27 12:13:26 +00:00
|
|
|
} else {
|
2014-01-20 15:40:30 +00:00
|
|
|
std::cerr << "Invalid argument: " << qPrintable(arg) << std::endl;
|
2011-04-27 12:13:26 +00:00
|
|
|
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) {
|
2014-01-20 15:40:30 +00:00
|
|
|
std::cerr << "Incorrect number of positional arguments" << std::endl;
|
2011-04-27 12:13:26 +00:00
|
|
|
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) {
|
2014-01-20 15:40:30 +00:00
|
|
|
std::cerr << "Incorrect number of positional arguments" << std::endl;
|
2011-04-27 12:13:26 +00:00
|
|
|
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) {
|
2014-01-20 15:40:30 +00:00
|
|
|
std::cerr << "Incorrect number of positional arguments" << std::endl;
|
2011-06-21 09:59:49 +00:00
|
|
|
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);
|
2014-01-20 15:40:30 +00:00
|
|
|
pluginImportPath = cur.canonicalPath();
|
2011-06-29 12:00:34 +00:00
|
|
|
QDir::setCurrent(pluginImportPath);
|
2011-07-11 03:47:51 +00:00
|
|
|
engine.addImportPath(pluginImportPath);
|
2011-06-29 12:00:34 +00:00
|
|
|
}
|
2016-01-08 10:25:47 +00:00
|
|
|
|
|
|
|
// Merge file.
|
|
|
|
QStringList mergeDependencies;
|
|
|
|
QString mergeComponents;
|
|
|
|
if (!mergeFile.isEmpty()) {
|
|
|
|
QStringList merge = readQmlTypes(mergeFile);
|
|
|
|
if (!merge.isEmpty()) {
|
|
|
|
QRegularExpression re("(\\w+\\.*\\w*\\s*\\d+\\.\\d+)");
|
|
|
|
QRegularExpressionMatchIterator i = re.globalMatch(merge[1]);
|
|
|
|
while (i.hasNext()) {
|
|
|
|
QRegularExpressionMatch m = i.next();
|
|
|
|
QString d = m.captured(1);
|
|
|
|
mergeDependencies << m.captured(1);
|
|
|
|
}
|
|
|
|
mergeComponents = merge [2];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Dependencies.
|
|
|
|
|
2015-03-17 15:33:14 +00:00
|
|
|
bool calculateDependencies = !pluginImportUri.isEmpty() && !pluginImportVersion.isEmpty();
|
|
|
|
QStringList dependencies;
|
|
|
|
if (!dependenciesFile.isEmpty())
|
|
|
|
calculateDependencies = !readDependenciesFile(dependenciesFile, &dependencies,
|
|
|
|
QStringList(pluginImportUri)) && calculateDependencies;
|
|
|
|
if (calculateDependencies)
|
2016-04-13 12:58:28 +00:00
|
|
|
getDependencies(engine, pluginImportUri, pluginImportVersion, &dependencies,
|
|
|
|
forceQtQuickDependency);
|
|
|
|
|
2015-03-17 15:33:14 +00:00
|
|
|
compactDependencies(&dependencies);
|
2015-07-23 08:39:25 +00:00
|
|
|
|
2016-04-13 12:58:28 +00:00
|
|
|
|
2015-11-10 15:23:16 +00:00
|
|
|
QString qtQmlImportString = QString::fromLatin1("import QtQml %1.%2")
|
|
|
|
.arg(qtQmlMajorVersion)
|
|
|
|
.arg(qtQmlMinorVersion);
|
|
|
|
|
|
|
|
// load the QtQml builtins and the dependencies
|
2011-08-26 08:47:13 +00:00
|
|
|
{
|
2015-11-10 15:23:16 +00:00
|
|
|
QByteArray code(qtQmlImportString.toUtf8());
|
2016-08-11 10:08:00 +00:00
|
|
|
for (const QString &moduleToImport : qAsConst(dependencies)) {
|
2015-03-17 15:33:14 +00:00
|
|
|
code.append("\nimport ");
|
|
|
|
code.append(moduleToImport.toUtf8());
|
|
|
|
}
|
|
|
|
code.append("\nQtObject {}");
|
2012-02-16 04:43:03 +00:00
|
|
|
QQmlComponent c(&engine);
|
2015-03-17 15:33:14 +00:00
|
|
|
c.setData(code, QUrl::fromLocalFile(pluginImportPath + "/loaddependencies.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())
|
2014-01-22 18:19:54 +00:00
|
|
|
std::cerr << qPrintable( error.toString() ) << std::endl;
|
2011-08-26 08:47:13 +00:00
|
|
|
return EXIT_IMPORTERROR;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-04-27 12:13:26 +00:00
|
|
|
// find all QMetaObjects reachable from the builtin module
|
2014-01-20 15:40:30 +00:00
|
|
|
QSet<const QMetaObject *> uncreatableMetas;
|
|
|
|
QSet<const QMetaObject *> singletonMetas;
|
|
|
|
QSet<const QMetaObject *> defaultReachable = collectReachableMetaObjects(&engine, uncreatableMetas, singletonMetas);
|
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) {
|
2016-08-11 10:08:00 +00:00
|
|
|
for (const QMetaObject *m : qAsConst(defaultReachable)) {
|
2015-11-10 15:23:16 +00:00
|
|
|
if (m->className() == QLatin1String("Qt")) {
|
|
|
|
metas.insert(m);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else if (pluginImportUri == QLatin1String("QtQml")) {
|
|
|
|
bool ok = false;
|
|
|
|
const uint major = pluginImportVersion.split('.')[0].toUInt(&ok, 10);
|
|
|
|
if (!ok) {
|
|
|
|
std::cerr << "Malformed version string \""<< qPrintable(pluginImportVersion) << "\"."
|
|
|
|
<< std::endl;
|
|
|
|
return EXIT_INVALIDARGUMENTS;
|
|
|
|
}
|
|
|
|
if (major != qtQmlMajorVersion) {
|
|
|
|
std::cerr << "Unsupported version \"" << qPrintable(pluginImportVersion)
|
|
|
|
<< "\": Major version number must be \"" << qtQmlMajorVersion << "\"."
|
|
|
|
<< std::endl;
|
|
|
|
return EXIT_INVALIDARGUMENTS;
|
|
|
|
}
|
2011-04-27 12:13:26 +00:00
|
|
|
metas = defaultReachable;
|
2016-08-11 10:08:00 +00:00
|
|
|
for (const QMetaObject *m : qAsConst(defaultReachable)) {
|
2015-11-10 15:23:16 +00:00
|
|
|
if (m->className() == QLatin1String("Qt")) {
|
|
|
|
metas.remove(m);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2011-04-27 12:13:26 +00:00
|
|
|
} 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) {
|
2014-01-22 18:19:54 +00:00
|
|
|
std::cerr << "Could not find QtObject type" << std::endl;
|
2015-11-10 15:23:16 +00:00
|
|
|
importCode = qtQmlImportString.toUtf8();
|
2011-07-14 07:04:17 +00:00
|
|
|
} else {
|
2011-09-29 08:29:22 +00:00
|
|
|
QString module = qtObjectType->qmlTypeName();
|
|
|
|
module = module.mid(0, module.lastIndexOf(QLatin1Char('/')));
|
2015-03-17 15:33:14 +00:00
|
|
|
importCode = QString("import %1 %2.%3").arg(module,
|
|
|
|
QString::number(qtObjectType->majorVersion()),
|
|
|
|
QString::number(qtObjectType->minorVersion())).toUtf8();
|
|
|
|
}
|
|
|
|
// avoid importing dependencies?
|
2016-08-11 10:08:00 +00:00
|
|
|
for (const QString &moduleToImport : qAsConst(dependencies)) {
|
2015-03-17 15:33:14 +00:00
|
|
|
importCode.append("\nimport ");
|
|
|
|
importCode.append(moduleToImport.toUtf8());
|
2011-07-14 07:04:17 +00:00
|
|
|
}
|
|
|
|
|
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) {
|
2015-03-17 15:33:14 +00:00
|
|
|
importCode += QString("\nimport %0 %1\n").arg(pluginImportUri, pluginImportVersion).toLatin1();
|
2011-04-27 12:13:26 +00:00
|
|
|
} else {
|
|
|
|
// pluginImportVersion can be empty
|
2015-03-17 15:33:14 +00:00
|
|
|
importCode += QString("\nimport \".\" %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;
|
2015-03-17 15:33:14 +00:00
|
|
|
code += "\nQtObject {}";
|
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())
|
2014-01-22 18:19:54 +00:00
|
|
|
std::cerr << qPrintable( error.toString() ) << std::endl;
|
2011-04-27 12:13:26 +00:00
|
|
|
return EXIT_IMPORTERROR;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-01-20 15:40:30 +00:00
|
|
|
QSet<const QMetaObject *> candidates = collectReachableMetaObjects(&engine, uncreatableMetas, singletonMetas, 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.
|
2016-08-11 10:08:00 +00:00
|
|
|
for (const QMetaObject *mo : qAsConst(defaultReachable))
|
2011-04-27 12:13:26 +00:00
|
|
|
defaultReachableNames.insert(QByteArray(mo->className()));
|
2016-08-11 10:08:00 +00:00
|
|
|
for (const QMetaObject *mo : qAsConst(candidates)) {
|
2011-04-27 12:13:26 +00:00
|
|
|
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();
|
2015-03-17 15:33:14 +00:00
|
|
|
qml.writeLibraryImport(QLatin1String("QtQuick.tooling"), 1, 2);
|
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"
|
2013-09-18 09:25:45 +00:00
|
|
|
"// This file was auto-generated by:\n"
|
|
|
|
"// '%1 %2'\n"
|
2015-09-17 12:18:07 +00:00
|
|
|
"\n").arg(QFileInfo(args.at(0)).baseName(), args.mid(1).join(QLatin1Char(' '))));
|
2011-04-27 12:13:26 +00:00
|
|
|
qml.writeStartObject("Module");
|
2016-01-08 10:25:47 +00:00
|
|
|
|
|
|
|
// Insert merge dependencies.
|
|
|
|
if (!mergeDependencies.isEmpty()) {
|
|
|
|
dependencies << mergeDependencies;
|
|
|
|
}
|
|
|
|
compactDependencies(&dependencies);
|
|
|
|
|
2015-03-17 15:33:14 +00:00
|
|
|
QStringList quotedDependencies;
|
2016-08-11 10:08:00 +00:00
|
|
|
for (const QString &dep : qAsConst(dependencies))
|
2015-03-17 15:33:14 +00:00
|
|
|
quotedDependencies << enquote(dep);
|
|
|
|
qml.writeArrayBinding("dependencies", quotedDependencies);
|
2011-04-27 12:13:26 +00:00
|
|
|
|
|
|
|
// put the metaobjects into a map so they are always dumped in the same order
|
|
|
|
QMap<QString, const QMetaObject *> nameToMeta;
|
2016-08-11 10:08:00 +00:00
|
|
|
for (const QMetaObject *meta : qAsConst(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);
|
2016-08-11 10:08:00 +00:00
|
|
|
for (const QMetaObject *meta : qAsConst(nameToMeta)) {
|
2015-09-14 20:02:55 +00:00
|
|
|
dumper.dump(QQmlEnginePrivate::get(&engine), meta, uncreatableMetas.contains(meta), singletonMetas.contains(meta));
|
2011-04-27 12:13:26 +00:00
|
|
|
}
|
2015-10-22 10:33:43 +00:00
|
|
|
|
|
|
|
QMap<QString, QSet<const QQmlType *> >::const_iterator iter = qmlTypesByCompositeName.constBegin();
|
|
|
|
for (; iter != qmlTypesByCompositeName.constEnd(); ++iter)
|
|
|
|
dumper.dumpComposite(&engine, iter.value(), 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();
|
|
|
|
|
2016-01-08 10:25:47 +00:00
|
|
|
// Insert merge file.
|
|
|
|
qml.write(mergeComponents);
|
|
|
|
|
2011-04-27 12:13:26 +00:00
|
|
|
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();
|
|
|
|
}
|