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
|
|
|
|
2017-01-19 14:47:51 +00:00
|
|
|
#ifdef QT_WIDGETS_LIB
|
|
|
|
#include <QApplication>
|
|
|
|
#endif // QT_WIDGETS_LIB
|
|
|
|
|
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"
|
2020-10-02 10:52:05 +00:00
|
|
|
#include "qqmljsstreamwriter_p.h"
|
2011-04-27 12:13:26 +00:00
|
|
|
|
|
|
|
#ifdef QT_SIMULATOR
|
|
|
|
#include <QtGui/private/qsimulatorconnection_p.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;
|
2018-10-09 13:02:11 +00:00
|
|
|
const uint qtQmlMinorVersion = 0;
|
2016-12-01 10:02:36 +00:00
|
|
|
const uint qtQuickMajorVersion = 2;
|
2018-10-09 13:02:11 +00:00
|
|
|
const uint qtQuickMinorVersion = 0;
|
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("\\\"")));
|
|
|
|
}
|
|
|
|
|
2019-08-16 14:26:45 +00:00
|
|
|
struct QmlVersionInfo
|
2011-04-27 12:13:26 +00:00
|
|
|
{
|
2019-08-16 14:26:45 +00:00
|
|
|
QString pluginImportUri;
|
2020-01-22 12:12:56 +00:00
|
|
|
QTypeRevision version;
|
2019-09-26 09:21:13 +00:00
|
|
|
bool strict;
|
2019-08-16 14:26:45 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
static bool matchingImportUri(const QQmlType &ty, const QmlVersionInfo& versionInfo) {
|
2019-09-26 09:21:13 +00:00
|
|
|
if (versionInfo.strict) {
|
|
|
|
return (versionInfo.pluginImportUri == ty.module()
|
2020-01-22 12:12:56 +00:00
|
|
|
&& (ty.version().majorVersion() == versionInfo.version.majorVersion()
|
|
|
|
|| !ty.version().hasMajorVersion()))
|
2019-09-26 09:21:13 +00:00
|
|
|
|| ty.module().isEmpty();
|
|
|
|
}
|
|
|
|
return ty.module().isEmpty()
|
|
|
|
|| versionInfo.pluginImportUri == ty.module()
|
|
|
|
|| ty.module().startsWith(versionInfo.pluginImportUri + QLatin1Char('.'));
|
2019-08-16 14:26:45 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void collectReachableMetaObjects(const QMetaObject *meta, QSet<const QMetaObject *> *metas, const QmlVersionInfo &info, bool extended = false, bool alreadyChangedModule = false)
|
|
|
|
{
|
|
|
|
auto ty = QQmlMetaType::qmlType(meta);
|
2011-04-27 12:13:26 +00:00
|
|
|
if (! meta || metas->contains(meta))
|
|
|
|
return;
|
|
|
|
|
2019-08-16 14:26:45 +00:00
|
|
|
if (matchingImportUri(ty, info)) {
|
|
|
|
if (!alreadyChangedModule) {
|
|
|
|
// dynamic meta objects can break things badly
|
|
|
|
// but extended types are usually fine
|
|
|
|
const QMetaObjectPrivate *mop = reinterpret_cast<const QMetaObjectPrivate *>(meta->d.data);
|
|
|
|
if (extended || !(mop->flags & DynamicMetaObject))
|
|
|
|
metas->insert(meta);
|
|
|
|
} else if (!ty.module().isEmpty()) { // empty module (e.g. from an attached property) would cause a (false) match; do not warn about them
|
|
|
|
qWarning() << "Circular module dependency cannot be expressed in plugin.qmltypes file"
|
|
|
|
<< "Object was:" << meta->className()
|
|
|
|
<< ty.module() << info.pluginImportUri;
|
|
|
|
}
|
|
|
|
} else if (!ty.module().isEmpty()) {
|
|
|
|
alreadyChangedModule = true;
|
|
|
|
}
|
2011-04-27 12:13:26 +00:00
|
|
|
|
2019-08-16 14:26:45 +00:00
|
|
|
collectReachableMetaObjects(meta->superClass(), metas, info, /*extended=*/ false, alreadyChangedModule);
|
2011-04-27 12:13:26 +00:00
|
|
|
}
|
|
|
|
|
2019-08-16 14:26:45 +00:00
|
|
|
void collectReachableMetaObjects(QObject *object, QSet<const QMetaObject *> *metas, const QmlVersionInfo &info)
|
2011-04-27 12:13:26 +00:00
|
|
|
{
|
|
|
|
if (! object)
|
|
|
|
return;
|
|
|
|
|
|
|
|
const QMetaObject *meta = object->metaObject();
|
2011-06-21 09:59:49 +00:00
|
|
|
if (verbose)
|
2018-09-19 09:02:47 +00:00
|
|
|
std::cerr << "Processing object " << qPrintable( meta->className() ) << std::endl;
|
2019-08-16 14:26:45 +00:00
|
|
|
collectReachableMetaObjects(meta, metas, info);
|
2011-04-27 12:13:26 +00:00
|
|
|
|
|
|
|
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)
|
2018-09-19 09:02:47 +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()))
|
2019-08-16 14:26:45 +00:00
|
|
|
collectReachableMetaObjects(oo, metas, info);
|
2011-04-27 12:13:26 +00:00
|
|
|
currentProperty.clear();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-08-16 14:26:45 +00:00
|
|
|
void collectReachableMetaObjects(QQmlEnginePrivate *engine, const QQmlType &ty, QSet<const QMetaObject *> *metas, const QmlVersionInfo& info)
|
2011-04-27 12:13:26 +00:00
|
|
|
{
|
2019-08-16 14:26:45 +00:00
|
|
|
collectReachableMetaObjects(ty.baseMetaObject(), metas, info, ty.isExtendedType());
|
|
|
|
if (ty.attachedPropertiesType(engine) && matchingImportUri(ty, info)) {
|
|
|
|
collectReachableMetaObjects(ty.attachedPropertiesType(engine), metas, info);
|
|
|
|
}
|
2011-04-27 12:13:26 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* 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.
|
|
|
|
*/
|
2017-06-26 11:45:56 +00:00
|
|
|
static QHash<QByteArray, QSet<QQmlType> > qmlTypesByCppName;
|
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
|
2019-03-01 16:04:41 +00:00
|
|
|
void collectReachableMetaObjectsWithoutQmlName(QQmlEnginePrivate *engine, QSet<const QMetaObject *>& metas,
|
2019-09-27 13:55:36 +00:00
|
|
|
QMap<QString, QList<QQmlType>> &compositeTypes, const QmlVersionInfo &info) {
|
2016-08-11 10:37:27 +00:00
|
|
|
const auto qmlAllTypes = QQmlMetaType::qmlAllTypes();
|
2017-06-26 11:45:56 +00:00
|
|
|
for (const QQmlType &ty : qmlAllTypes) {
|
qmlplugindump: Properly handle extension types
Extension classes do augment the primary C++ class with additional
properties that should be part of the QML type. Anyhow, they should
not be visible in the API.
The old logic tried to emulate this by making the extension
class the actual C++ type, and 'inheriting' from the normal
class by setting it in the prototype. Anyhow, this failed for
e.g. Qt3D, where there are numerous types sharing the same
extension class.
Instead, this patch fixes the issue
a) hiding the extension class metainformation itself, and
b) printing properties of the extension class as part of the
main type.
In the QMetaObject collection phase, we now traverse the class
hierarchy using QQmlType::baseMetaObject instead of
QQmlType::metaObject.
In the generation phase, we explicitly resolve the extended type,
and dump additional properties and "DefaultProperty" information
into the main type description.
Note that the ExtendedType sets the DefaultProperty independent
of the version. Changing this would require either revisioning
the defaultProperty, or (again) splitting up the types, which
however brings other problems.
Task-number: QTBUG-70294
Change-Id: I324469152398a605fae9e5a35b619845444ac4e8
Reviewed-by: Marco Benelli <marco.benelli@qt.io>
2018-09-18 10:03:09 +00:00
|
|
|
if (!metas.contains(ty.baseMetaObject())) {
|
2017-06-26 11:45:56 +00:00
|
|
|
if (!ty.isComposite()) {
|
2019-08-16 14:26:45 +00:00
|
|
|
collectReachableMetaObjects(engine, ty, &metas, info);
|
|
|
|
} else if (matchingImportUri(ty, info)) {
|
2019-09-27 13:55:36 +00:00
|
|
|
compositeTypes[ty.elementName()].append(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,
|
2019-09-27 13:55:36 +00:00
|
|
|
QMap<QString, QList<QQmlType>> &compositeTypes,
|
2019-08-16 14:26:45 +00:00
|
|
|
const QmlVersionInfo &info,
|
|
|
|
const QList<QQmlType> &skip = QList<QQmlType>()
|
|
|
|
)
|
2011-04-27 12:13:26 +00:00
|
|
|
{
|
|
|
|
QSet<const QMetaObject *> metas;
|
2019-12-10 14:26:18 +00:00
|
|
|
metas.insert(&Qt::staticMetaObject);
|
2011-04-27 12:13:26 +00:00
|
|
|
|
2016-08-11 10:37:27 +00:00
|
|
|
const auto qmlTypes = QQmlMetaType::qmlTypes();
|
2017-06-26 11:45:56 +00:00
|
|
|
for (const QQmlType &ty : qmlTypes) {
|
2019-08-16 14:26:45 +00:00
|
|
|
if (!matchingImportUri(ty,info))
|
|
|
|
continue;
|
2017-06-26 11:45:56 +00:00
|
|
|
if (!ty.isCreatable())
|
qmlplugindump: Properly handle extension types
Extension classes do augment the primary C++ class with additional
properties that should be part of the QML type. Anyhow, they should
not be visible in the API.
The old logic tried to emulate this by making the extension
class the actual C++ type, and 'inheriting' from the normal
class by setting it in the prototype. Anyhow, this failed for
e.g. Qt3D, where there are numerous types sharing the same
extension class.
Instead, this patch fixes the issue
a) hiding the extension class metainformation itself, and
b) printing properties of the extension class as part of the
main type.
In the QMetaObject collection phase, we now traverse the class
hierarchy using QQmlType::baseMetaObject instead of
QQmlType::metaObject.
In the generation phase, we explicitly resolve the extended type,
and dump additional properties and "DefaultProperty" information
into the main type description.
Note that the ExtendedType sets the DefaultProperty independent
of the version. Changing this would require either revisioning
the defaultProperty, or (again) splitting up the types, which
however brings other problems.
Task-number: QTBUG-70294
Change-Id: I324469152398a605fae9e5a35b619845444ac4e8
Reviewed-by: Marco Benelli <marco.benelli@qt.io>
2018-09-18 10:03:09 +00:00
|
|
|
noncreatables.insert(ty.baseMetaObject());
|
2017-06-26 11:45:56 +00:00
|
|
|
if (ty.isSingleton())
|
qmlplugindump: Properly handle extension types
Extension classes do augment the primary C++ class with additional
properties that should be part of the QML type. Anyhow, they should
not be visible in the API.
The old logic tried to emulate this by making the extension
class the actual C++ type, and 'inheriting' from the normal
class by setting it in the prototype. Anyhow, this failed for
e.g. Qt3D, where there are numerous types sharing the same
extension class.
Instead, this patch fixes the issue
a) hiding the extension class metainformation itself, and
b) printing properties of the extension class as part of the
main type.
In the QMetaObject collection phase, we now traverse the class
hierarchy using QQmlType::baseMetaObject instead of
QQmlType::metaObject.
In the generation phase, we explicitly resolve the extended type,
and dump additional properties and "DefaultProperty" information
into the main type description.
Note that the ExtendedType sets the DefaultProperty independent
of the version. Changing this would require either revisioning
the defaultProperty, or (again) splitting up the types, which
however brings other problems.
Task-number: QTBUG-70294
Change-Id: I324469152398a605fae9e5a35b619845444ac4e8
Reviewed-by: Marco Benelli <marco.benelli@qt.io>
2018-09-18 10:03:09 +00:00
|
|
|
singletons.insert(ty.baseMetaObject());
|
2017-06-26 11:45:56 +00:00
|
|
|
if (!ty.isComposite()) {
|
qmlplugindump: Properly handle extension types
Extension classes do augment the primary C++ class with additional
properties that should be part of the QML type. Anyhow, they should
not be visible in the API.
The old logic tried to emulate this by making the extension
class the actual C++ type, and 'inheriting' from the normal
class by setting it in the prototype. Anyhow, this failed for
e.g. Qt3D, where there are numerous types sharing the same
extension class.
Instead, this patch fixes the issue
a) hiding the extension class metainformation itself, and
b) printing properties of the extension class as part of the
main type.
In the QMetaObject collection phase, we now traverse the class
hierarchy using QQmlType::baseMetaObject instead of
QQmlType::metaObject.
In the generation phase, we explicitly resolve the extended type,
and dump additional properties and "DefaultProperty" information
into the main type description.
Note that the ExtendedType sets the DefaultProperty independent
of the version. Changing this would require either revisioning
the defaultProperty, or (again) splitting up the types, which
however brings other problems.
Task-number: QTBUG-70294
Change-Id: I324469152398a605fae9e5a35b619845444ac4e8
Reviewed-by: Marco Benelli <marco.benelli@qt.io>
2018-09-18 10:03:09 +00:00
|
|
|
qmlTypesByCppName[ty.baseMetaObject()->className()].insert(ty);
|
2019-08-16 14:26:45 +00:00
|
|
|
collectReachableMetaObjects(QQmlEnginePrivate::get(engine), ty, &metas, info);
|
2013-09-03 12:03:21 +00:00
|
|
|
} else {
|
2019-09-27 13:55:36 +00:00
|
|
|
compositeTypes[ty.elementName()].append(ty);
|
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
|
2017-06-26 11:45:56 +00:00
|
|
|
for (const QQmlType &ty : qmlTypes) {
|
2019-08-16 14:26:45 +00:00
|
|
|
if (!matchingImportUri(ty, info))
|
|
|
|
continue;
|
2013-05-02 17:42:31 +00:00
|
|
|
if (skip.contains(ty))
|
|
|
|
continue;
|
2017-06-26 11:45:56 +00:00
|
|
|
if (ty.isExtendedType())
|
2013-05-02 17:42:31 +00:00
|
|
|
continue;
|
2017-06-26 11:45:56 +00:00
|
|
|
if (!ty.isCreatable())
|
2013-05-02 17:42:31 +00:00
|
|
|
continue;
|
2017-06-26 11:45:56 +00:00
|
|
|
if (ty.typeName() == "QQmlComponent")
|
2013-05-02 17:42:31 +00:00
|
|
|
continue;
|
|
|
|
|
2017-06-26 11:45:56 +00:00
|
|
|
QString tyName = ty.qmlTypeName();
|
2013-05-02 17:42:31 +00:00
|
|
|
tyName = tyName.mid(tyName.lastIndexOf(QLatin1Char('/')) + 1);
|
|
|
|
if (tyName.isEmpty())
|
|
|
|
continue;
|
|
|
|
|
|
|
|
inObjectInstantiation = tyName;
|
2018-02-21 09:41:54 +00:00
|
|
|
QObject *object = nullptr;
|
2013-05-02 17:42:31 +00:00
|
|
|
|
2017-06-26 11:45:56 +00:00
|
|
|
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)
|
2017-06-26 11:45:56 +00:00
|
|
|
<< "(" << qPrintable( QString::fromUtf8(ty.typeName()) ) << ")"
|
2014-01-22 18:19:54 +00:00
|
|
|
<< " is singleton, but has no singletonInstanceInfo" << std::endl;
|
2013-06-10 09:16:38 +00:00
|
|
|
continue;
|
|
|
|
}
|
2019-04-21 11:27:05 +00:00
|
|
|
if (ty.isQObjectSingleton()) {
|
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;
|
2019-08-16 14:26:45 +00:00
|
|
|
collectReachableMetaObjects(object, &metas, info);
|
2019-04-21 11:27:05 +00:00
|
|
|
object = QQmlEnginePrivate::get(engine)->singletonInstance<QObject*>(ty);
|
2013-05-02 17:42:31 +00:00
|
|
|
} 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 )
|
2017-06-26 11:45:56 +00:00
|
|
|
<< " (" << qPrintable( QString::fromUtf8(ty.typeName()) ) << ")" << std::endl;
|
|
|
|
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 )
|
2017-06-26 11:45:56 +00:00
|
|
|
<< " (" << qPrintable( QString::fromUtf8(ty.typeName()) ) << ")" << std::endl;
|
2019-08-16 14:26:45 +00:00
|
|
|
collectReachableMetaObjects(object, &metas, info);
|
2014-03-25 08:07:46 +00:00
|
|
|
object->deleteLater();
|
2013-06-10 09:16:38 +00:00
|
|
|
} else {
|
2018-09-19 09:02:47 +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
|
|
|
}
|
|
|
|
|
2019-08-16 14:26:45 +00:00
|
|
|
collectReachableMetaObjectsWithoutQmlName(QQmlEnginePrivate::get(engine), metas, compositeTypes, info);
|
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 {
|
2020-01-22 12:12:56 +00:00
|
|
|
QHash<QByteArray, QTypeRevision> m_properties;
|
|
|
|
QHash<QByteArray, QHash<int, QTypeRevision> > m_methods;
|
2014-04-09 13:42:06 +00:00
|
|
|
public:
|
2020-01-22 12:12:56 +00:00
|
|
|
bool knownMethod(const QByteArray &name, int nArgs, QTypeRevision revision)
|
2014-04-09 13:42:06 +00:00
|
|
|
{
|
|
|
|
if (m_methods.contains(name)) {
|
2020-01-22 12:12:56 +00:00
|
|
|
QHash<int, QTypeRevision> overloads = m_methods.value(name);
|
|
|
|
if (overloads.contains(nArgs) && overloads.value(nArgs).toEncodedVersion<quint16>() <= revision.toEncodedVersion<quint16>())
|
2014-04-09 13:42:06 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
m_methods[name][nArgs] = revision;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2020-01-22 12:12:56 +00:00
|
|
|
bool knownProperty(const QByteArray &name, QTypeRevision revision)
|
2014-04-09 13:42:06 +00:00
|
|
|
{
|
2020-01-22 12:12:56 +00:00
|
|
|
if (m_properties.contains(name) && m_properties.value(name).toEncodedVersion<quint16>() <= revision.toEncodedVersion<quint16>())
|
2014-04-09 13:42:06 +00:00
|
|
|
return true;
|
|
|
|
m_properties[name] = revision;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
};
|
2011-04-27 12:13:26 +00:00
|
|
|
|
|
|
|
class Dumper
|
|
|
|
{
|
2020-10-02 10:52:05 +00:00
|
|
|
QQmlJSStreamWriter *qml;
|
2011-04-27 12:13:26 +00:00
|
|
|
QString relocatableModuleUri;
|
|
|
|
|
|
|
|
public:
|
2020-10-02 10:52:05 +00:00
|
|
|
Dumper(QQmlJSStreamWriter *qml) : qml(qml) {}
|
2011-04-27 12:13:26 +00:00
|
|
|
|
|
|
|
void setRelocatableModuleUri(const QString &uri)
|
|
|
|
{
|
|
|
|
relocatableModuleUri = uri;
|
|
|
|
}
|
|
|
|
|
2019-10-11 16:03:52 +00:00
|
|
|
QString getExportString(const QQmlType &type, const QmlVersionInfo &versionInfo)
|
2013-09-03 12:03:21 +00:00
|
|
|
{
|
2019-10-11 16:03:52 +00:00
|
|
|
const QString module = type.module().isEmpty() ? versionInfo.pluginImportUri
|
|
|
|
: type.module();
|
2020-01-22 12:12:56 +00:00
|
|
|
QTypeRevision version = QTypeRevision::fromVersion(
|
|
|
|
type.version().hasMajorVersion() ? type.version().majorVersion()
|
|
|
|
: versionInfo.version.majorVersion(),
|
|
|
|
type.version().hasMinorVersion() ? type.version().minorVersion()
|
|
|
|
: versionInfo.version.minorVersion());
|
2019-10-11 16:03:52 +00:00
|
|
|
|
|
|
|
const QString versionedElement = type.elementName()
|
2020-01-22 12:12:56 +00:00
|
|
|
+ QString::fromLatin1(" %1.%2").arg(version.majorVersion()).arg(version.minorVersion());
|
2019-10-11 16:03:52 +00:00
|
|
|
|
|
|
|
return enquote((module == relocatableModuleUri)
|
|
|
|
? versionedElement
|
|
|
|
: module + QLatin1Char('/') + versionedElement);
|
2013-09-03 12:03:21 +00:00
|
|
|
}
|
|
|
|
|
2018-02-21 09:41:54 +00:00
|
|
|
void writeMetaContent(const QMetaObject *meta, KnownAttributes *knownAttributes = nullptr)
|
2013-09-03 12:03:21 +00:00
|
|
|
{
|
2020-01-22 12:12:56 +00:00
|
|
|
QSet<QString> implicitSignals = dumpMetaProperties(meta, QTypeRevision::zero(), knownAttributes);
|
2013-09-03 12:03:21 +00:00
|
|
|
|
|
|
|
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)
|
2020-01-22 12:12:56 +00:00
|
|
|
if (!knownAttributes || !knownAttributes->knownMethod(QByteArray("toString"), 0, QTypeRevision::zero())) {
|
2014-04-09 13:42:06 +00:00
|
|
|
qml->writeStartObject(QLatin1String("Method"));
|
|
|
|
qml->writeScriptBinding(QLatin1String("name"), enquote(QLatin1String("toString")));
|
|
|
|
qml->writeEndObject();
|
|
|
|
}
|
2020-01-22 12:12:56 +00:00
|
|
|
if (!knownAttributes || !knownAttributes->knownMethod(QByteArray("destroy"), 0, QTypeRevision::zero())) {
|
2014-04-09 13:42:06 +00:00
|
|
|
qml->writeStartObject(QLatin1String("Method"));
|
|
|
|
qml->writeScriptBinding(QLatin1String("name"), enquote(QLatin1String("destroy")));
|
|
|
|
qml->writeEndObject();
|
|
|
|
}
|
2020-01-22 12:12:56 +00:00
|
|
|
if (!knownAttributes || !knownAttributes->knownMethod(QByteArray("destroy"), 1, QTypeRevision::zero())) {
|
2014-04-09 13:42:06 +00:00
|
|
|
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
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-10-11 15:47:21 +00:00
|
|
|
QString getPrototypeNameForCompositeType(
|
|
|
|
const QMetaObject *metaObject, QList<const QMetaObject *> *objectsToMerge,
|
|
|
|
const QmlVersionInfo &versionInfo)
|
2013-09-03 12:03:21 +00:00
|
|
|
{
|
2019-09-25 11:49:10 +00:00
|
|
|
auto ty = QQmlMetaType::qmlType(metaObject);
|
2013-09-03 12:03:21 +00:00
|
|
|
QString prototypeName;
|
2019-09-25 11:49:10 +00:00
|
|
|
if (matchingImportUri(ty, versionInfo)) {
|
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();
|
2019-10-11 16:03:52 +00:00
|
|
|
if (!superMetaObject) {
|
2013-09-16 10:40:30 +00:00
|
|
|
prototypeName = "QObject";
|
2019-10-11 16:03:52 +00:00
|
|
|
} else {
|
|
|
|
QQmlType superType = QQmlMetaType::qmlType(superMetaObject);
|
|
|
|
if (superType.isValid() && !superType.isComposite())
|
|
|
|
return convertToId(superMetaObject->className());
|
2014-04-09 13:42:06 +00:00
|
|
|
prototypeName = getPrototypeNameForCompositeType(
|
2019-10-11 15:47:21 +00:00
|
|
|
superMetaObject, objectsToMerge, versionInfo);
|
2019-10-11 16:03:52 +00:00
|
|
|
}
|
2013-09-16 10:40:30 +00:00
|
|
|
} else {
|
|
|
|
prototypeName = convertToId(metaObject->className());
|
|
|
|
}
|
2013-09-03 12:03:21 +00:00
|
|
|
return prototypeName;
|
|
|
|
}
|
|
|
|
|
2019-10-11 15:47:21 +00:00
|
|
|
void dumpComposite(QQmlEngine *engine, const QList<QQmlType> &compositeType, const QmlVersionInfo &versionInfo)
|
2015-10-22 10:33:43 +00:00
|
|
|
{
|
2017-06-26 11:45:56 +00:00
|
|
|
for (const QQmlType &type : compositeType)
|
2019-10-11 15:47:21 +00:00
|
|
|
dumpCompositeItem(engine, type, versionInfo);
|
2015-10-22 10:33:43 +00:00
|
|
|
}
|
|
|
|
|
2019-10-11 15:47:21 +00:00
|
|
|
void dumpCompositeItem(QQmlEngine *engine, const QQmlType &compositeType, const QmlVersionInfo &versionInfo)
|
2013-09-03 12:03:21 +00:00
|
|
|
{
|
2017-06-26 11:45:56 +00:00
|
|
|
QQmlComponent e(engine, compositeType.sourceUrl());
|
2015-07-23 08:39:25 +00:00
|
|
|
if (!e.isReady()) {
|
2017-06-26 11:45:56 +00:00
|
|
|
std::cerr << "WARNING: skipping module " << compositeType.elementName().toStdString()
|
2015-07-23 08:39:25 +00:00
|
|
|
<< 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
|
2019-10-11 15:47:21 +00:00
|
|
|
QString prototypeName = getPrototypeNameForCompositeType(mainMeta, &objectsToMerge,
|
|
|
|
versionInfo);
|
2013-09-03 12:03:21 +00:00
|
|
|
qml->writeScriptBinding(QLatin1String("prototype"), enquote(prototypeName));
|
|
|
|
|
2017-06-26 11:45:56 +00:00
|
|
|
QString qmlTyName = compositeType.qmlTypeName();
|
2019-10-11 16:03:52 +00:00
|
|
|
const QString exportString = getExportString(compositeType, versionInfo);
|
|
|
|
|
|
|
|
// TODO: why don't we simply output the compositeType.elementName() here?
|
|
|
|
// That would make more sense, but it would change the format quite a bit.
|
2015-10-22 10:33:43 +00:00
|
|
|
qml->writeScriptBinding(QLatin1String("name"), exportString);
|
2019-10-11 16:03:52 +00:00
|
|
|
|
2013-09-03 12:03:21 +00:00
|
|
|
qml->writeArrayBinding(QLatin1String("exports"), QStringList() << exportString);
|
2020-01-22 12:12:56 +00:00
|
|
|
|
|
|
|
// TODO: shouldn't this be metaObjectRevision().value<quint16>()
|
|
|
|
// rather than version().minorVersion()
|
|
|
|
qml->writeArrayBinding(QLatin1String("exportMetaObjectRevisions"), QStringList()
|
|
|
|
<< QString::number(compositeType.version().minorVersion()));
|
|
|
|
|
2014-02-13 15:33:18 +00:00
|
|
|
qml->writeBooleanBinding(QLatin1String("isComposite"), true);
|
2013-09-03 12:03:21 +00:00
|
|
|
|
2017-06-26 11:45:56 +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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-07-01 09:04:39 +00:00
|
|
|
for (const QMetaObject *meta : qAsConst(objectsToMerge)) {
|
|
|
|
for (int index = meta->enumeratorOffset(); index < meta->enumeratorCount(); ++index)
|
|
|
|
dump(meta->enumerator(index));
|
|
|
|
|
2014-04-09 13:42:06 +00:00
|
|
|
writeMetaContent(meta, &knownAttributes);
|
2019-07-01 09:04:39 +00:00
|
|
|
}
|
2013-09-03 12:03:21 +00:00
|
|
|
|
|
|
|
qml->writeEndObject();
|
|
|
|
}
|
|
|
|
|
qmlplugindump: Properly handle extension types
Extension classes do augment the primary C++ class with additional
properties that should be part of the QML type. Anyhow, they should
not be visible in the API.
The old logic tried to emulate this by making the extension
class the actual C++ type, and 'inheriting' from the normal
class by setting it in the prototype. Anyhow, this failed for
e.g. Qt3D, where there are numerous types sharing the same
extension class.
Instead, this patch fixes the issue
a) hiding the extension class metainformation itself, and
b) printing properties of the extension class as part of the
main type.
In the QMetaObject collection phase, we now traverse the class
hierarchy using QQmlType::baseMetaObject instead of
QQmlType::metaObject.
In the generation phase, we explicitly resolve the extended type,
and dump additional properties and "DefaultProperty" information
into the main type description.
Note that the ExtendedType sets the DefaultProperty independent
of the version. Changing this would require either revisioning
the defaultProperty, or (again) splitting up the types, which
however brings other problems.
Task-number: QTBUG-70294
Change-Id: I324469152398a605fae9e5a35b619845444ac4e8
Reviewed-by: Marco Benelli <marco.benelli@qt.io>
2018-09-18 10:03:09 +00:00
|
|
|
QString getDefaultProperty(const QMetaObject *meta)
|
|
|
|
{
|
|
|
|
for (int index = meta->classInfoCount() - 1; index >= 0; --index) {
|
|
|
|
QMetaClassInfo classInfo = meta->classInfo(index);
|
|
|
|
if (QLatin1String(classInfo.name()) == QLatin1String("DefaultProperty")) {
|
|
|
|
return QLatin1String(classInfo.value());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return QString();
|
|
|
|
}
|
|
|
|
|
|
|
|
struct QmlTypeInfo {
|
|
|
|
QmlTypeInfo() {}
|
2020-01-22 12:12:56 +00:00
|
|
|
QmlTypeInfo(const QString &exportString, QTypeRevision revision, const QMetaObject *extendedObject, QByteArray attachedTypeId)
|
qmlplugindump: Properly handle extension types
Extension classes do augment the primary C++ class with additional
properties that should be part of the QML type. Anyhow, they should
not be visible in the API.
The old logic tried to emulate this by making the extension
class the actual C++ type, and 'inheriting' from the normal
class by setting it in the prototype. Anyhow, this failed for
e.g. Qt3D, where there are numerous types sharing the same
extension class.
Instead, this patch fixes the issue
a) hiding the extension class metainformation itself, and
b) printing properties of the extension class as part of the
main type.
In the QMetaObject collection phase, we now traverse the class
hierarchy using QQmlType::baseMetaObject instead of
QQmlType::metaObject.
In the generation phase, we explicitly resolve the extended type,
and dump additional properties and "DefaultProperty" information
into the main type description.
Note that the ExtendedType sets the DefaultProperty independent
of the version. Changing this would require either revisioning
the defaultProperty, or (again) splitting up the types, which
however brings other problems.
Task-number: QTBUG-70294
Change-Id: I324469152398a605fae9e5a35b619845444ac4e8
Reviewed-by: Marco Benelli <marco.benelli@qt.io>
2018-09-18 10:03:09 +00:00
|
|
|
: exportString(exportString), revision(revision), extendedObject(extendedObject), attachedTypeId(attachedTypeId) {}
|
|
|
|
QString exportString;
|
2020-01-22 12:12:56 +00:00
|
|
|
QTypeRevision revision = QTypeRevision::zero();
|
qmlplugindump: Properly handle extension types
Extension classes do augment the primary C++ class with additional
properties that should be part of the QML type. Anyhow, they should
not be visible in the API.
The old logic tried to emulate this by making the extension
class the actual C++ type, and 'inheriting' from the normal
class by setting it in the prototype. Anyhow, this failed for
e.g. Qt3D, where there are numerous types sharing the same
extension class.
Instead, this patch fixes the issue
a) hiding the extension class metainformation itself, and
b) printing properties of the extension class as part of the
main type.
In the QMetaObject collection phase, we now traverse the class
hierarchy using QQmlType::baseMetaObject instead of
QQmlType::metaObject.
In the generation phase, we explicitly resolve the extended type,
and dump additional properties and "DefaultProperty" information
into the main type description.
Note that the ExtendedType sets the DefaultProperty independent
of the version. Changing this would require either revisioning
the defaultProperty, or (again) splitting up the types, which
however brings other problems.
Task-number: QTBUG-70294
Change-Id: I324469152398a605fae9e5a35b619845444ac4e8
Reviewed-by: Marco Benelli <marco.benelli@qt.io>
2018-09-18 10:03:09 +00:00
|
|
|
const QMetaObject *extendedObject = nullptr;
|
|
|
|
QByteArray attachedTypeId;
|
|
|
|
};
|
|
|
|
|
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));
|
|
|
|
|
qmlplugindump: Properly handle extension types
Extension classes do augment the primary C++ class with additional
properties that should be part of the QML type. Anyhow, they should
not be visible in the API.
The old logic tried to emulate this by making the extension
class the actual C++ type, and 'inheriting' from the normal
class by setting it in the prototype. Anyhow, this failed for
e.g. Qt3D, where there are numerous types sharing the same
extension class.
Instead, this patch fixes the issue
a) hiding the extension class metainformation itself, and
b) printing properties of the extension class as part of the
main type.
In the QMetaObject collection phase, we now traverse the class
hierarchy using QQmlType::baseMetaObject instead of
QQmlType::metaObject.
In the generation phase, we explicitly resolve the extended type,
and dump additional properties and "DefaultProperty" information
into the main type description.
Note that the ExtendedType sets the DefaultProperty independent
of the version. Changing this would require either revisioning
the defaultProperty, or (again) splitting up the types, which
however brings other problems.
Task-number: QTBUG-70294
Change-Id: I324469152398a605fae9e5a35b619845444ac4e8
Reviewed-by: Marco Benelli <marco.benelli@qt.io>
2018-09-18 10:03:09 +00:00
|
|
|
// collect type information
|
|
|
|
QVector<QmlTypeInfo> typeInfo;
|
|
|
|
for (QQmlType type : qmlTypesByCppName.value(meta->className())) {
|
|
|
|
const QMetaObject *extendedObject = type.extensionFunction() ? type.metaObject() : nullptr;
|
|
|
|
QByteArray attachedTypeId;
|
|
|
|
if (const QMetaObject *attachedType = type.attachedPropertiesType(engine)) {
|
|
|
|
// Can happen when a type is registered that returns itself as attachedPropertiesType()
|
|
|
|
// because there is no creatable type to attach to.
|
|
|
|
if (attachedType != meta)
|
|
|
|
attachedTypeId = convertToId(attachedType);
|
|
|
|
}
|
2020-01-22 12:12:56 +00:00
|
|
|
const QString exportString = getExportString(type, { QString(), QTypeRevision(), false });
|
|
|
|
QTypeRevision metaObjectRevision = type.metaObjectRevision();
|
qmlplugindump: Properly handle extension types
Extension classes do augment the primary C++ class with additional
properties that should be part of the QML type. Anyhow, they should
not be visible in the API.
The old logic tried to emulate this by making the extension
class the actual C++ type, and 'inheriting' from the normal
class by setting it in the prototype. Anyhow, this failed for
e.g. Qt3D, where there are numerous types sharing the same
extension class.
Instead, this patch fixes the issue
a) hiding the extension class metainformation itself, and
b) printing properties of the extension class as part of the
main type.
In the QMetaObject collection phase, we now traverse the class
hierarchy using QQmlType::baseMetaObject instead of
QQmlType::metaObject.
In the generation phase, we explicitly resolve the extended type,
and dump additional properties and "DefaultProperty" information
into the main type description.
Note that the ExtendedType sets the DefaultProperty independent
of the version. Changing this would require either revisioning
the defaultProperty, or (again) splitting up the types, which
however brings other problems.
Task-number: QTBUG-70294
Change-Id: I324469152398a605fae9e5a35b619845444ac4e8
Reviewed-by: Marco Benelli <marco.benelli@qt.io>
2018-09-18 10:03:09 +00:00
|
|
|
if (extendedObject) {
|
|
|
|
// emulate custom metaobjectrevision out of import
|
2020-01-22 12:12:56 +00:00
|
|
|
metaObjectRevision = type.version();
|
qmlplugindump: Properly handle extension types
Extension classes do augment the primary C++ class with additional
properties that should be part of the QML type. Anyhow, they should
not be visible in the API.
The old logic tried to emulate this by making the extension
class the actual C++ type, and 'inheriting' from the normal
class by setting it in the prototype. Anyhow, this failed for
e.g. Qt3D, where there are numerous types sharing the same
extension class.
Instead, this patch fixes the issue
a) hiding the extension class metainformation itself, and
b) printing properties of the extension class as part of the
main type.
In the QMetaObject collection phase, we now traverse the class
hierarchy using QQmlType::baseMetaObject instead of
QQmlType::metaObject.
In the generation phase, we explicitly resolve the extended type,
and dump additional properties and "DefaultProperty" information
into the main type description.
Note that the ExtendedType sets the DefaultProperty independent
of the version. Changing this would require either revisioning
the defaultProperty, or (again) splitting up the types, which
however brings other problems.
Task-number: QTBUG-70294
Change-Id: I324469152398a605fae9e5a35b619845444ac4e8
Reviewed-by: Marco Benelli <marco.benelli@qt.io>
2018-09-18 10:03:09 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
QmlTypeInfo info = { exportString, metaObjectRevision, extendedObject, attachedTypeId };
|
|
|
|
typeInfo.append(info);
|
|
|
|
}
|
|
|
|
|
|
|
|
// sort to ensure stable output
|
|
|
|
std::sort(typeInfo.begin(), typeInfo.end(), [](const QmlTypeInfo &i1, const QmlTypeInfo &i2) {
|
2020-01-22 12:12:56 +00:00
|
|
|
return i1.revision.toEncodedVersion<quint16>() < i2.revision.toEncodedVersion<quint16>();
|
qmlplugindump: Properly handle extension types
Extension classes do augment the primary C++ class with additional
properties that should be part of the QML type. Anyhow, they should
not be visible in the API.
The old logic tried to emulate this by making the extension
class the actual C++ type, and 'inheriting' from the normal
class by setting it in the prototype. Anyhow, this failed for
e.g. Qt3D, where there are numerous types sharing the same
extension class.
Instead, this patch fixes the issue
a) hiding the extension class metainformation itself, and
b) printing properties of the extension class as part of the
main type.
In the QMetaObject collection phase, we now traverse the class
hierarchy using QQmlType::baseMetaObject instead of
QQmlType::metaObject.
In the generation phase, we explicitly resolve the extended type,
and dump additional properties and "DefaultProperty" information
into the main type description.
Note that the ExtendedType sets the DefaultProperty independent
of the version. Changing this would require either revisioning
the defaultProperty, or (again) splitting up the types, which
however brings other problems.
Task-number: QTBUG-70294
Change-Id: I324469152398a605fae9e5a35b619845444ac4e8
Reviewed-by: Marco Benelli <marco.benelli@qt.io>
2018-09-18 10:03:09 +00:00
|
|
|
});
|
|
|
|
|
|
|
|
// determine default property
|
|
|
|
// TODO: support revisioning of default property
|
|
|
|
QString defaultProperty = getDefaultProperty(meta);
|
|
|
|
if (defaultProperty.isEmpty()) {
|
|
|
|
for (const QmlTypeInfo &iter : typeInfo) {
|
|
|
|
if (iter.extendedObject) {
|
|
|
|
defaultProperty = getDefaultProperty(iter.extendedObject);
|
|
|
|
if (!defaultProperty.isEmpty())
|
|
|
|
break;
|
|
|
|
}
|
2011-04-27 12:13:26 +00:00
|
|
|
}
|
|
|
|
}
|
qmlplugindump: Properly handle extension types
Extension classes do augment the primary C++ class with additional
properties that should be part of the QML type. Anyhow, they should
not be visible in the API.
The old logic tried to emulate this by making the extension
class the actual C++ type, and 'inheriting' from the normal
class by setting it in the prototype. Anyhow, this failed for
e.g. Qt3D, where there are numerous types sharing the same
extension class.
Instead, this patch fixes the issue
a) hiding the extension class metainformation itself, and
b) printing properties of the extension class as part of the
main type.
In the QMetaObject collection phase, we now traverse the class
hierarchy using QQmlType::baseMetaObject instead of
QQmlType::metaObject.
In the generation phase, we explicitly resolve the extended type,
and dump additional properties and "DefaultProperty" information
into the main type description.
Note that the ExtendedType sets the DefaultProperty independent
of the version. Changing this would require either revisioning
the defaultProperty, or (again) splitting up the types, which
however brings other problems.
Task-number: QTBUG-70294
Change-Id: I324469152398a605fae9e5a35b619845444ac4e8
Reviewed-by: Marco Benelli <marco.benelli@qt.io>
2018-09-18 10:03:09 +00:00
|
|
|
if (!defaultProperty.isEmpty())
|
|
|
|
qml->writeScriptBinding(QLatin1String("defaultProperty"), enquote(defaultProperty));
|
2011-04-27 12:13:26 +00:00
|
|
|
|
|
|
|
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
|
|
|
|
qmlplugindump: Properly handle extension types
Extension classes do augment the primary C++ class with additional
properties that should be part of the QML type. Anyhow, they should
not be visible in the API.
The old logic tried to emulate this by making the extension
class the actual C++ type, and 'inheriting' from the normal
class by setting it in the prototype. Anyhow, this failed for
e.g. Qt3D, where there are numerous types sharing the same
extension class.
Instead, this patch fixes the issue
a) hiding the extension class metainformation itself, and
b) printing properties of the extension class as part of the
main type.
In the QMetaObject collection phase, we now traverse the class
hierarchy using QQmlType::baseMetaObject instead of
QQmlType::metaObject.
In the generation phase, we explicitly resolve the extended type,
and dump additional properties and "DefaultProperty" information
into the main type description.
Note that the ExtendedType sets the DefaultProperty independent
of the version. Changing this would require either revisioning
the defaultProperty, or (again) splitting up the types, which
however brings other problems.
Task-number: QTBUG-70294
Change-Id: I324469152398a605fae9e5a35b619845444ac4e8
Reviewed-by: Marco Benelli <marco.benelli@qt.io>
2018-09-18 10:03:09 +00:00
|
|
|
if (!typeInfo.isEmpty()) {
|
|
|
|
QMap<QString, QString> exports; // sort exports
|
|
|
|
for (const QmlTypeInfo &iter : typeInfo)
|
2020-01-22 12:12:56 +00:00
|
|
|
exports.insert(iter.exportString, QString::number(iter.revision.toEncodedVersion<quint16>()));
|
2011-04-27 12:13:26 +00:00
|
|
|
|
2011-09-21 10:54:10 +00:00
|
|
|
QStringList exportStrings = exports.keys();
|
qmlplugindump: Properly handle extension types
Extension classes do augment the primary C++ class with additional
properties that should be part of the QML type. Anyhow, they should
not be visible in the API.
The old logic tried to emulate this by making the extension
class the actual C++ type, and 'inheriting' from the normal
class by setting it in the prototype. Anyhow, this failed for
e.g. Qt3D, where there are numerous types sharing the same
extension class.
Instead, this patch fixes the issue
a) hiding the extension class metainformation itself, and
b) printing properties of the extension class as part of the
main type.
In the QMetaObject collection phase, we now traverse the class
hierarchy using QQmlType::baseMetaObject instead of
QQmlType::metaObject.
In the generation phase, we explicitly resolve the extended type,
and dump additional properties and "DefaultProperty" information
into the main type description.
Note that the ExtendedType sets the DefaultProperty independent
of the version. Changing this would require either revisioning
the defaultProperty, or (again) splitting up the types, which
however brings other problems.
Task-number: QTBUG-70294
Change-Id: I324469152398a605fae9e5a35b619845444ac4e8
Reviewed-by: Marco Benelli <marco.benelli@qt.io>
2018-09-18 10:03:09 +00:00
|
|
|
QStringList metaObjectRevisions = exports.values();
|
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
|
|
|
qml->writeArrayBinding(QLatin1String("exportMetaObjectRevisions"), metaObjectRevisions);
|
2011-04-27 12:13:26 +00:00
|
|
|
|
qmlplugindump: Properly handle extension types
Extension classes do augment the primary C++ class with additional
properties that should be part of the QML type. Anyhow, they should
not be visible in the API.
The old logic tried to emulate this by making the extension
class the actual C++ type, and 'inheriting' from the normal
class by setting it in the prototype. Anyhow, this failed for
e.g. Qt3D, where there are numerous types sharing the same
extension class.
Instead, this patch fixes the issue
a) hiding the extension class metainformation itself, and
b) printing properties of the extension class as part of the
main type.
In the QMetaObject collection phase, we now traverse the class
hierarchy using QQmlType::baseMetaObject instead of
QQmlType::metaObject.
In the generation phase, we explicitly resolve the extended type,
and dump additional properties and "DefaultProperty" information
into the main type description.
Note that the ExtendedType sets the DefaultProperty independent
of the version. Changing this would require either revisioning
the defaultProperty, or (again) splitting up the types, which
however brings other problems.
Task-number: QTBUG-70294
Change-Id: I324469152398a605fae9e5a35b619845444ac4e8
Reviewed-by: Marco Benelli <marco.benelli@qt.io>
2018-09-18 10:03:09 +00:00
|
|
|
for (const QmlTypeInfo &iter : typeInfo) {
|
|
|
|
if (!iter.attachedTypeId.isEmpty()) {
|
|
|
|
qml->writeScriptBinding(QLatin1String("attachedType"), enquote(iter.attachedTypeId));
|
|
|
|
break;
|
2011-11-29 07:52:14 +00:00
|
|
|
}
|
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
|
|
|
|
qmlplugindump: Properly handle extension types
Extension classes do augment the primary C++ class with additional
properties that should be part of the QML type. Anyhow, they should
not be visible in the API.
The old logic tried to emulate this by making the extension
class the actual C++ type, and 'inheriting' from the normal
class by setting it in the prototype. Anyhow, this failed for
e.g. Qt3D, where there are numerous types sharing the same
extension class.
Instead, this patch fixes the issue
a) hiding the extension class metainformation itself, and
b) printing properties of the extension class as part of the
main type.
In the QMetaObject collection phase, we now traverse the class
hierarchy using QQmlType::baseMetaObject instead of
QQmlType::metaObject.
In the generation phase, we explicitly resolve the extended type,
and dump additional properties and "DefaultProperty" information
into the main type description.
Note that the ExtendedType sets the DefaultProperty independent
of the version. Changing this would require either revisioning
the defaultProperty, or (again) splitting up the types, which
however brings other problems.
Task-number: QTBUG-70294
Change-Id: I324469152398a605fae9e5a35b619845444ac4e8
Reviewed-by: Marco Benelli <marco.benelli@qt.io>
2018-09-18 10:03:09 +00:00
|
|
|
// dump properties from extended metaobjects last
|
|
|
|
for (auto iter : typeInfo) {
|
|
|
|
if (iter.extendedObject)
|
|
|
|
dumpMetaProperties(iter.extendedObject, iter.revision);
|
|
|
|
}
|
|
|
|
|
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"));
|
|
|
|
}
|
|
|
|
|
2020-01-22 12:12:56 +00:00
|
|
|
void dump(const QMetaProperty &prop, QTypeRevision metaRevision = QTypeRevision(),
|
|
|
|
KnownAttributes *knownAttributes = nullptr)
|
2011-04-27 12:13:26 +00:00
|
|
|
{
|
2020-01-22 12:12:56 +00:00
|
|
|
// TODO: should that not be metaRevision.isValid() rather than comparing to zero()?
|
|
|
|
QTypeRevision revision = (metaRevision == QTypeRevision::zero())
|
|
|
|
? QTypeRevision::fromEncodedVersion(prop.revision())
|
|
|
|
: metaRevision;
|
2014-04-09 13:42:06 +00:00
|
|
|
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())));
|
2020-01-22 12:12:56 +00:00
|
|
|
if (revision != QTypeRevision::zero())
|
|
|
|
qml->writeScriptBinding(QLatin1String("revision"), QString::number(revision.toEncodedVersion<quint16>()));
|
2011-04-27 12:13:26 +00:00
|
|
|
writeTypeProperties(prop.typeName(), prop.isWritable());
|
|
|
|
|
|
|
|
qml->writeEndObject();
|
|
|
|
}
|
|
|
|
|
2020-01-22 12:12:56 +00:00
|
|
|
QSet<QString> dumpMetaProperties(const QMetaObject *meta, QTypeRevision metaRevision = QTypeRevision(),
|
|
|
|
KnownAttributes *knownAttributes = nullptr)
|
qmlplugindump: Properly handle extension types
Extension classes do augment the primary C++ class with additional
properties that should be part of the QML type. Anyhow, they should
not be visible in the API.
The old logic tried to emulate this by making the extension
class the actual C++ type, and 'inheriting' from the normal
class by setting it in the prototype. Anyhow, this failed for
e.g. Qt3D, where there are numerous types sharing the same
extension class.
Instead, this patch fixes the issue
a) hiding the extension class metainformation itself, and
b) printing properties of the extension class as part of the
main type.
In the QMetaObject collection phase, we now traverse the class
hierarchy using QQmlType::baseMetaObject instead of
QQmlType::metaObject.
In the generation phase, we explicitly resolve the extended type,
and dump additional properties and "DefaultProperty" information
into the main type description.
Note that the ExtendedType sets the DefaultProperty independent
of the version. Changing this would require either revisioning
the defaultProperty, or (again) splitting up the types, which
however brings other problems.
Task-number: QTBUG-70294
Change-Id: I324469152398a605fae9e5a35b619845444ac4e8
Reviewed-by: Marco Benelli <marco.benelli@qt.io>
2018-09-18 10:03:09 +00:00
|
|
|
{
|
|
|
|
QSet<QString> implicitSignals;
|
|
|
|
for (int index = meta->propertyOffset(); index < meta->propertyCount(); ++index) {
|
|
|
|
const QMetaProperty &property = meta->property(index);
|
|
|
|
dump(property, metaRevision, knownAttributes);
|
|
|
|
if (knownAttributes)
|
|
|
|
knownAttributes->knownMethod(QByteArray(property.name()).append("Changed"),
|
2020-01-22 12:12:56 +00:00
|
|
|
0, QTypeRevision::fromEncodedVersion(property.revision()));
|
qmlplugindump: Properly handle extension types
Extension classes do augment the primary C++ class with additional
properties that should be part of the QML type. Anyhow, they should
not be visible in the API.
The old logic tried to emulate this by making the extension
class the actual C++ type, and 'inheriting' from the normal
class by setting it in the prototype. Anyhow, this failed for
e.g. Qt3D, where there are numerous types sharing the same
extension class.
Instead, this patch fixes the issue
a) hiding the extension class metainformation itself, and
b) printing properties of the extension class as part of the
main type.
In the QMetaObject collection phase, we now traverse the class
hierarchy using QQmlType::baseMetaObject instead of
QQmlType::metaObject.
In the generation phase, we explicitly resolve the extended type,
and dump additional properties and "DefaultProperty" information
into the main type description.
Note that the ExtendedType sets the DefaultProperty independent
of the version. Changing this would require either revisioning
the defaultProperty, or (again) splitting up the types, which
however brings other problems.
Task-number: QTBUG-70294
Change-Id: I324469152398a605fae9e5a35b619845444ac4e8
Reviewed-by: Marco Benelli <marco.benelli@qt.io>
2018-09-18 10:03:09 +00:00
|
|
|
implicitSignals.insert(QString("%1Changed").arg(QString::fromUtf8(property.name())));
|
|
|
|
}
|
|
|
|
return implicitSignals;
|
|
|
|
}
|
|
|
|
|
2014-04-09 13:42:06 +00:00
|
|
|
void dump(const QMetaMethod &meth, const QSet<QString> &implicitSignals,
|
2018-02-21 09:41:54 +00:00
|
|
|
KnownAttributes *knownAttributes = nullptr)
|
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
|
|
|
|
2020-01-22 12:12:56 +00:00
|
|
|
QTypeRevision revision = QTypeRevision::fromEncodedVersion(meth.revision());
|
2014-04-09 13:42:06 +00:00
|
|
|
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));
|
|
|
|
|
2020-01-22 12:12:56 +00:00
|
|
|
if (revision != QTypeRevision::zero())
|
|
|
|
qml->writeScriptBinding(QLatin1String("revision"), QString::number(revision.toEncodedVersion<quint16>()));
|
2011-05-30 07:24:20 +00:00
|
|
|
|
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
|
|
|
|
};
|
|
|
|
|
|
|
|
void printUsage(const QString &appName)
|
|
|
|
{
|
2014-01-20 15:40:30 +00:00
|
|
|
std::cerr << qPrintable(QString(
|
2017-01-19 14:47:51 +00:00
|
|
|
"Usage: %1 [-v] [-qapp] [-noinstantiate] [-defaultplatform] [-[non]relocatable] [-dependencies <dependencies.json>] [-merge <file-to-merge.qmltypes>] [-output <output-file.qmltypes>] [-noforceqtquick] module.uri version [module/import/path]\n"
|
|
|
|
" %1 [-v] [-qapp] [-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")
|
2020-07-02 15:40:07 +00:00
|
|
|
<< QStringLiteral("type");
|
2016-08-11 10:37:27 +00:00
|
|
|
const auto deps = doc.array();
|
|
|
|
for (const QJsonValue &dep : deps) {
|
2015-03-17 15:33:14 +00:00
|
|
|
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();
|
2020-07-02 15:40:07 +00:00
|
|
|
if (name.isEmpty() || urisToSkip.contains(name))
|
2015-03-17 15:33:14 +00:00
|
|
|
continue;
|
2017-09-07 13:14:43 +00:00
|
|
|
if (name.contains(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;
|
2020-07-02 15:40:07 +00:00
|
|
|
dependencies->append(version.isEmpty() ? name
|
|
|
|
: (name + QLatin1Char(' ') + version));
|
2015-03-17 15:33:14 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
} 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
|
|
|
{
|
2018-10-09 07:27:02 +00:00
|
|
|
QString importScannerExe = QLatin1String("qmlimportscanner");
|
2015-03-17 15:33:14 +00:00
|
|
|
QFileInfo selfExe(QCoreApplication::applicationFilePath());
|
2018-10-09 07:27:02 +00:00
|
|
|
if (!selfExe.suffix().isEmpty())
|
|
|
|
importScannerExe += QLatin1String(".") + selfExe.suffix();
|
|
|
|
QString command = selfExe.absoluteDir().filePath(importScannerExe);
|
2015-03-17 15:33:14 +00:00
|
|
|
|
|
|
|
QStringList commandArgs = QStringList()
|
|
|
|
<< QLatin1String("-qmlFiles")
|
|
|
|
<< QLatin1String("-");
|
2017-02-16 14:58:09 +00:00
|
|
|
QStringList importPathList = engine.importPathList();
|
|
|
|
importPathList.removeOne(QStringLiteral("qrc:/qt-project.org/imports"));
|
2016-08-11 10:37:27 +00:00
|
|
|
for (const QString &path : importPathList)
|
2015-03-17 15:33:14 +00:00
|
|
|
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)) {
|
2017-01-31 13:47:53 +00:00
|
|
|
std::cerr << "failed to process output of qmlimportscanner" << std::endl;
|
2017-02-16 15:01:20 +00:00
|
|
|
if (importScanner.exitCode() != 0)
|
|
|
|
std::cerr << importScanner.readAllStandardError().toStdString();
|
2015-03-17 15:33:14 +00:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2020-07-02 15:40:07 +00:00
|
|
|
bool dependencyBetter(const QString &lhs, const QString &rhs)
|
2015-03-17 15:33:14 +00:00
|
|
|
{
|
2020-07-02 15:40:07 +00:00
|
|
|
QStringList leftSegments = lhs.split(QLatin1Char(' '), Qt::SkipEmptyParts);
|
|
|
|
QStringList rightSegments = rhs.split(QLatin1Char(' '), Qt::SkipEmptyParts);
|
|
|
|
|
|
|
|
if (leftSegments.isEmpty())
|
|
|
|
return false;
|
|
|
|
if (rightSegments.isEmpty())
|
|
|
|
return true;
|
|
|
|
|
|
|
|
const QString leftModule = leftSegments.first();
|
|
|
|
const QString rightModule = rightSegments.first();
|
|
|
|
|
|
|
|
if (leftModule < rightModule)
|
|
|
|
return true;
|
|
|
|
if (leftModule > rightModule)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
if (leftSegments.length() == 1)
|
2015-03-17 15:33:14 +00:00
|
|
|
return false;
|
2020-07-02 15:40:07 +00:00
|
|
|
if (rightSegments.length() == 1)
|
|
|
|
return true;
|
|
|
|
|
|
|
|
const QStringList leftVersion = leftSegments.at(1).split(QLatin1Char('.'));
|
|
|
|
const QStringList rightVersion = rightSegments.at(1).split(QLatin1Char('.'));
|
|
|
|
|
|
|
|
auto compareSegment = [&](int segmentIndex) {
|
|
|
|
if (leftVersion.length() <= segmentIndex)
|
|
|
|
return rightVersion.length() > segmentIndex ? 1 : 0;
|
|
|
|
if (rightVersion.length() <= segmentIndex)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
bool leftOk = false;
|
|
|
|
bool rightOk = false;
|
|
|
|
const int leftSegment = leftSegments[segmentIndex].toUShort(&leftOk);
|
|
|
|
const int rightSegment = rightSegments[segmentIndex].toUShort(&rightOk);
|
|
|
|
|
|
|
|
if (!leftOk)
|
|
|
|
return rightOk ? 1 : 0;
|
|
|
|
if (!rightOk)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
return rightSegment - leftSegment;
|
|
|
|
};
|
|
|
|
|
|
|
|
const int major = compareSegment(0);
|
|
|
|
return (major == 0) ? compareSegment(1) < 0 : major < 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
void compactDependencies(QStringList *dependencies)
|
|
|
|
{
|
|
|
|
std::sort(dependencies->begin(), dependencies->end(), dependencyBetter);
|
|
|
|
QString currentModule;
|
|
|
|
for (auto it = dependencies->begin(); it != dependencies->end();) {
|
|
|
|
QStringList segments = it->split(QLatin1Char(' '), Qt::SkipEmptyParts);
|
|
|
|
if (segments.isEmpty() || segments.first() == currentModule) {
|
|
|
|
it = dependencies->erase(it);
|
2015-03-17 15:33:14 +00:00
|
|
|
} else {
|
2020-07-02 15:40:07 +00:00
|
|
|
currentModule = segments.first();
|
|
|
|
++it;
|
2015-03-17 15:33:14 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
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.
|
|
|
|
}
|
|
|
|
|
2019-09-27 13:55:36 +00:00
|
|
|
QT_BEGIN_NAMESPACE
|
|
|
|
static bool operator<(const QQmlType &a, const QQmlType &b)
|
|
|
|
{
|
|
|
|
return a.qmlTypeName() < b.qmlTypeName()
|
|
|
|
|| (a.qmlTypeName() == b.qmlTypeName()
|
2020-01-22 12:12:56 +00:00
|
|
|
&& ((a.version().majorVersion() < b.version().majorVersion())
|
|
|
|
|| (a.version().majorVersion() == b.version().majorVersion()
|
|
|
|
&& a.version().minorVersion() < b.version().minorVersion())));
|
2019-09-27 13:55:36 +00:00
|
|
|
}
|
|
|
|
QT_END_NAMESPACE
|
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 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
|
|
|
|
2017-01-19 14:47:51 +00:00
|
|
|
// Check which kind of application should be instantiated.
|
|
|
|
bool useQApplication = false;
|
|
|
|
for (int i = 0; i < argc; ++i) {
|
2017-08-17 14:33:04 +00:00
|
|
|
QString arg = QLatin1String(argv[i]);
|
2017-01-19 14:47:51 +00:00
|
|
|
if (arg == QLatin1String("--qapp") || arg == QLatin1String("-qapp"))
|
|
|
|
useQApplication = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef QT_WIDGETS_LIB
|
|
|
|
QScopedPointer<QCoreApplication> app(useQApplication
|
|
|
|
? new QApplication(argc, argv)
|
|
|
|
: new QGuiApplication(argc, argv));
|
|
|
|
#else
|
2017-08-04 12:14:00 +00:00
|
|
|
Q_UNUSED(useQApplication);
|
2017-01-19 14:47:51 +00:00
|
|
|
QScopedPointer<QCoreApplication> app(new QGuiApplication(argc, argv));
|
|
|
|
#endif // QT_WIDGETS_LIB
|
|
|
|
|
2016-11-08 12:09:54 +00:00
|
|
|
QCoreApplication::setApplicationVersion(QLatin1String(QT_VERSION_STR));
|
2018-08-31 10:29:14 +00:00
|
|
|
QStringList args = app->arguments();
|
2017-01-19 14:47:51 +00:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2017-01-04 13:31:29 +00:00
|
|
|
QString outputFilename;
|
2011-04-27 12:13:26 +00:00
|
|
|
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;
|
2019-09-26 09:21:13 +00:00
|
|
|
bool strict = false;
|
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);
|
2018-08-31 10:29:14 +00:00
|
|
|
|
|
|
|
// Remove absolute path so that it does not show up in the
|
|
|
|
// printed command line inside the plugins.qmltypes file.
|
|
|
|
args[iArg] = QFileInfo(args.at(iArg)).fileName();
|
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;
|
2017-01-04 13:31:29 +00:00
|
|
|
} else if (arg == QLatin1String("--output")
|
|
|
|
|| arg == QLatin1String("-output")) {
|
|
|
|
if (++iArg == args.size()) {
|
|
|
|
std::cerr << "missing output file" << std::endl;
|
|
|
|
return EXIT_INVALIDARGUMENTS;
|
|
|
|
}
|
|
|
|
outputFilename = args.at(iArg);
|
2013-09-18 09:18:31 +00:00
|
|
|
} else if (arg == QLatin1String("--defaultplatform")
|
|
|
|
|| arg == QLatin1String("-defaultplatform")) {
|
|
|
|
continue;
|
2017-01-19 14:47:51 +00:00
|
|
|
} else if (arg == QLatin1String("--qapp")
|
|
|
|
|| arg == QLatin1String("-qapp")) {
|
|
|
|
continue;
|
2019-09-26 09:21:13 +00:00
|
|
|
} else if (arg == QLatin1String("--strict")
|
|
|
|
|| arg == QLatin1String("-strict")) {
|
|
|
|
strict = true;
|
|
|
|
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;
|
|
|
|
}
|
2016-08-15 10:30:48 +00:00
|
|
|
pluginImportUri = positionalArgs.at(1);
|
2011-04-27 12:13:26 +00:00
|
|
|
pluginImportVersion = positionalArgs[2];
|
|
|
|
if (positionalArgs.size() >= 4)
|
2016-08-15 10:30:48 +00:00
|
|
|
pluginImportPath = positionalArgs.at(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;
|
|
|
|
}
|
2016-08-15 10:30:48 +00:00
|
|
|
pluginImportPath = QDir::fromNativeSeparators(positionalArgs.at(1));
|
2011-04-27 12:13:26 +00:00
|
|
|
if (positionalArgs.size() == 3)
|
2016-08-15 10:30:48 +00:00
|
|
|
pluginImportVersion = positionalArgs.at(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()) {
|
2016-08-15 10:30:48 +00:00
|
|
|
const QStringList merge = readQmlTypes(mergeFile);
|
2016-01-08 10:25:47 +00:00
|
|
|
if (!merge.isEmpty()) {
|
|
|
|
QRegularExpression re("(\\w+\\.*\\w*\\s*\\d+\\.\\d+)");
|
|
|
|
QRegularExpressionMatchIterator i = re.globalMatch(merge[1]);
|
|
|
|
while (i.hasNext()) {
|
|
|
|
QRegularExpressionMatch m = i.next();
|
2018-11-29 17:40:10 +00:00
|
|
|
mergeDependencies << m.captured(1);
|
2016-01-08 10:25:47 +00:00
|
|
|
}
|
|
|
|
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();
|
2016-08-11 10:37:27 +00:00
|
|
|
const auto errors = c.errors();
|
|
|
|
if (!errors.isEmpty()) {
|
|
|
|
for (const QQmlError &error : 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;
|
2011-04-27 12:13:26 +00:00
|
|
|
|
|
|
|
// this will hold the meta objects we want to dump information of
|
|
|
|
QSet<const QMetaObject *> metas;
|
|
|
|
|
2019-03-01 16:15:12 +00:00
|
|
|
// composite types we want to dump information of
|
2019-09-27 13:55:36 +00:00
|
|
|
QMap<QString, QList<QQmlType>> compositeTypes;
|
2019-03-01 16:15:12 +00:00
|
|
|
|
2020-01-22 12:12:56 +00:00
|
|
|
QTypeRevision version = QTypeRevision::fromVersion(qtQmlMajorVersion, qtQmlMinorVersion);
|
2019-09-25 11:49:10 +00:00
|
|
|
QmlVersionInfo info;
|
2011-06-21 09:59:49 +00:00
|
|
|
if (action == Builtins) {
|
2019-09-27 13:55:36 +00:00
|
|
|
QMap<QString, QList<QQmlType>> defaultCompositeTypes;
|
2020-01-22 12:12:56 +00:00
|
|
|
QSet<const QMetaObject *> builtins = collectReachableMetaObjects(
|
|
|
|
&engine, uncreatableMetas, singletonMetas, defaultCompositeTypes,
|
|
|
|
{QLatin1String("Qt"), version, strict});
|
2019-08-16 14:26:45 +00:00
|
|
|
Q_ASSERT(builtins.size() == 1);
|
|
|
|
metas.insert(*builtins.begin());
|
2011-04-27 12:13:26 +00:00
|
|
|
} else {
|
2019-08-16 14:26:45 +00:00
|
|
|
auto versionSplitted = pluginImportVersion.split(".");
|
|
|
|
bool ok = versionSplitted.size() == 2;
|
|
|
|
if (!ok)
|
|
|
|
qCritical("Invalid version number");
|
|
|
|
else {
|
2020-01-22 12:12:56 +00:00
|
|
|
const int majorVersion = versionSplitted.at(0).toInt(&ok);
|
2019-08-16 14:26:45 +00:00
|
|
|
if (!ok)
|
|
|
|
qCritical("Invalid major version");
|
2020-01-22 12:12:56 +00:00
|
|
|
const int minorVersion = versionSplitted.at(1).toInt(&ok);
|
2019-08-16 14:26:45 +00:00
|
|
|
if (!ok)
|
|
|
|
qCritical("Invalid minor version");
|
2020-01-22 12:12:56 +00:00
|
|
|
version = QTypeRevision::fromVersion(majorVersion, minorVersion);
|
2019-08-16 14:26:45 +00:00
|
|
|
}
|
|
|
|
QList<QQmlType> defaultTypes = QQmlMetaType::qmlTypes();
|
2011-07-14 07:04:17 +00:00
|
|
|
// find a valid QtQuick import
|
|
|
|
QByteArray importCode;
|
2017-06-23 11:20:23 +00:00
|
|
|
QQmlType qtObjectType = QQmlMetaType::qmlType(&QObject::staticMetaObject);
|
|
|
|
if (!qtObjectType.isValid()) {
|
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 {
|
2017-06-23 11:20:23 +00:00
|
|
|
QString module = qtObjectType.qmlTypeName();
|
2011-09-29 08:29:22 +00:00
|
|
|
module = module.mid(0, module.lastIndexOf(QLatin1Char('/')));
|
2020-01-22 12:12:56 +00:00
|
|
|
importCode = QString("import %1 %2.%3").arg(
|
|
|
|
module, QString::number(qtObjectType.version().majorVersion()),
|
|
|
|
QString::number(qtObjectType.version().minorVersion())).toUtf8();
|
2015-03-17 15:33:14 +00:00
|
|
|
}
|
|
|
|
// 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();
|
2016-08-11 10:37:27 +00:00
|
|
|
const auto errors = c.errors();
|
|
|
|
if (!errors.isEmpty()) {
|
|
|
|
for (const QQmlError &error : 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;
|
|
|
|
}
|
|
|
|
}
|
2020-01-22 12:12:56 +00:00
|
|
|
info = {pluginImportUri, version, strict};
|
2019-09-25 11:49:10 +00:00
|
|
|
QSet<const QMetaObject *> candidates = collectReachableMetaObjects(&engine, uncreatableMetas, singletonMetas, compositeTypes, info, defaultTypes);
|
2011-04-27 12:13:26 +00:00
|
|
|
|
2019-09-27 13:55:36 +00:00
|
|
|
for (auto it = compositeTypes.begin(), end = compositeTypes.end(); it != end; ++it) {
|
|
|
|
std::sort(it->begin(), it->end());
|
|
|
|
it->erase(std::unique(it->begin(), it->end()), it->end());
|
2019-03-01 16:15:12 +00:00
|
|
|
}
|
|
|
|
|
2016-08-11 10:08:00 +00:00
|
|
|
for (const QMetaObject *mo : qAsConst(candidates)) {
|
2019-08-16 14:26:45 +00:00
|
|
|
if (mo->className() != QLatin1String("Qt"))
|
2011-04-27 12:13:26 +00:00
|
|
|
metas.insert(mo);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// setup static rewrites of type names
|
|
|
|
cppToId.insert("QString", "string");
|
|
|
|
|
|
|
|
// start dumping data
|
|
|
|
QByteArray bytes;
|
2020-10-02 10:52:05 +00:00
|
|
|
QQmlJSStreamWriter qml(&bytes);
|
2011-04-27 12:13:26 +00:00
|
|
|
|
|
|
|
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
|
|
|
|
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
|
|
|
|
2019-09-27 13:55:36 +00:00
|
|
|
QMap<QString, QList<QQmlType>>::const_iterator iter = compositeTypes.constBegin();
|
2019-03-01 16:04:41 +00:00
|
|
|
for (; iter != compositeTypes.constEnd(); ++iter)
|
2019-10-11 15:47:21 +00:00
|
|
|
dumper.dumpComposite(&engine, iter.value(), info);
|
2011-04-27 12:13:26 +00:00
|
|
|
|
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();
|
|
|
|
|
2017-01-04 13:31:29 +00:00
|
|
|
if (!outputFilename.isEmpty()) {
|
|
|
|
QFile file(outputFilename);
|
|
|
|
if (file.open(QIODevice::WriteOnly)) {
|
|
|
|
QTextStream stream(&file);
|
|
|
|
stream << bytes.constData();
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
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);
|
2017-01-19 14:47:51 +00:00
|
|
|
QObject::connect(&timer, SIGNAL(timeout()), app.data(), SLOT(quit()));
|
2011-04-27 12:13:26 +00:00
|
|
|
timer.start();
|
|
|
|
|
2017-01-19 14:47:51 +00:00
|
|
|
return app->exec();
|
2011-04-27 12:13:26 +00:00
|
|
|
}
|