Introduce qmlRegisterModule()
This is particularly useful for keeping the versions of related modules in sync. For example, when QtQuick.Controls introduces new types or revisions and bumps up the minor version, qmlRegisterModule() can be used to make the same version available for QtQuick.Controls.Styles in case it doesn't have new types or revisions to register. [ChangeLog][QtQml] Introduced qmlRegisterModule() that can be used to make a certain module version available, even if no types or revisions are registered for that version. Change-Id: I5ec457465cd778bb0adda55771d195f69cd4b31a Reviewed-by: Mitch Curtis <mitch.curtis@qt.io> Reviewed-by: Simon Hausmann <simon.hausmann@qt.io>
This commit is contained in:
parent
0cbda65924
commit
c56cc0c6c2
|
@ -544,3 +544,15 @@
|
|||
in order to be found.
|
||||
*/
|
||||
|
||||
/*!
|
||||
\since 5.9
|
||||
\fn void qmlRegisterModule(const char* uri, int versionMajor, int versionMinor);
|
||||
\relates QQmlEngine
|
||||
|
||||
This function registers a module in a particular \a uri with a version specified
|
||||
in \a versionMajor and \a versionMinor.
|
||||
|
||||
This can be used to make a certain module version available, even if no types
|
||||
are registered for that version. This is particularly useful for keeping the
|
||||
versions of related modules in sync.
|
||||
*/
|
||||
|
|
|
@ -526,6 +526,7 @@ QT_WARNING_POP
|
|||
|
||||
//The C++ version of protected namespaces in qmldir
|
||||
Q_QML_EXPORT bool qmlProtectModule(const char* uri, int majVersion);
|
||||
Q_QML_EXPORT void qmlRegisterModule(const char *uri, int versionMajor, int versionMinor);
|
||||
|
||||
template<typename T>
|
||||
QObject *qmlAttachedPropertiesObject(const QObject *obj, bool create = true)
|
||||
|
|
|
@ -1267,6 +1267,19 @@ bool checkRegistration(QQmlType::RegistrationType typeType, QQmlMetaTypeData *da
|
|||
return true;
|
||||
}
|
||||
|
||||
// NOTE: caller must hold a QMutexLocker on "data"
|
||||
QQmlTypeModule *getTypeModule(const QHashedString &uri, int majorVersion, QQmlMetaTypeData *data)
|
||||
{
|
||||
QQmlMetaTypeData::VersionedUri versionedUri(uri, majorVersion);
|
||||
QQmlTypeModule *module = data->uriToModule.value(versionedUri);
|
||||
if (!module) {
|
||||
module = new QQmlTypeModule;
|
||||
module->d->uri = versionedUri;
|
||||
data->uriToModule.insert(versionedUri, module);
|
||||
}
|
||||
return module;
|
||||
}
|
||||
|
||||
// NOTE: caller must hold a QMutexLocker on "data"
|
||||
void addTypeToData(QQmlType* type, QQmlMetaTypeData *data)
|
||||
{
|
||||
|
@ -1293,13 +1306,8 @@ void addTypeToData(QQmlType* type, QQmlMetaTypeData *data)
|
|||
if (!type->module().isEmpty()) {
|
||||
const QHashedString &mod = type->module();
|
||||
|
||||
QQmlMetaTypeData::VersionedUri versionedUri(mod, type->majorVersion());
|
||||
QQmlTypeModule *module = data->uriToModule.value(versionedUri);
|
||||
if (!module) {
|
||||
module = new QQmlTypeModule;
|
||||
module->d->uri = versionedUri;
|
||||
data->uriToModule.insert(versionedUri, module);
|
||||
}
|
||||
QQmlTypeModule *module = getTypeModule(mod, type->majorVersion(), data);
|
||||
Q_ASSERT(module);
|
||||
module->d->add(type);
|
||||
}
|
||||
}
|
||||
|
@ -1442,6 +1450,20 @@ bool qmlProtectModule(const char *uri, int majVersion)
|
|||
return false;
|
||||
}
|
||||
|
||||
//From qqml.h
|
||||
void qmlRegisterModule(const char *uri, int versionMajor, int versionMinor)
|
||||
{
|
||||
QMutexLocker lock(metaTypeDataLock());
|
||||
QQmlMetaTypeData *data = metaTypeData();
|
||||
|
||||
QQmlTypeModule *module = getTypeModule(QString::fromUtf8(uri), versionMajor, data);
|
||||
Q_ASSERT(module);
|
||||
|
||||
QQmlTypeModulePrivate *p = QQmlTypeModulePrivate::get(module);
|
||||
p->minMinorVersion = qMin(p->minMinorVersion, versionMinor);
|
||||
p->maxMinorVersion = qMax(p->maxMinorVersion, versionMinor);
|
||||
}
|
||||
|
||||
bool QQmlMetaType::namespaceContainsRegistrations(const QString &uri, int majorVersion)
|
||||
{
|
||||
const QQmlMetaTypeData *data = metaTypeData();
|
||||
|
|
|
@ -266,6 +266,7 @@ public:
|
|||
|
||||
private:
|
||||
//Used by register functions and creates the QQmlTypeModule for them
|
||||
friend QQmlTypeModule *getTypeModule(const QHashedString &uri, int majorVersion, QQmlMetaTypeData *data);
|
||||
friend void addTypeToData(QQmlType* type, QQmlMetaTypeData *data);
|
||||
friend struct QQmlMetaTypeData;
|
||||
friend Q_QML_EXPORT void qmlClearTypeRegistrations();
|
||||
|
|
|
@ -0,0 +1,3 @@
|
|||
import org.qtproject.AutoTestQmlPluginType 2.2
|
||||
|
||||
MyPluginType { valueOnlyIn2: 123 }
|
|
@ -0,0 +1,12 @@
|
|||
TEMPLATE = lib
|
||||
CONFIG += plugin
|
||||
SOURCES = plugin.cpp
|
||||
QT = core qml
|
||||
DESTDIR = ../imports/org/qtproject/AutoTestQmlPluginType.2.2
|
||||
|
||||
QT += core-private gui-private qml-private
|
||||
|
||||
IMPORT_FILES = \
|
||||
qmldir
|
||||
|
||||
include (../../../shared/imports.pri)
|
|
@ -0,0 +1,72 @@
|
|||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2016 The Qt Company Ltd.
|
||||
** Contact: https://www.qt.io/licensing/
|
||||
**
|
||||
** This file is part of the test suite of the Qt Toolkit.
|
||||
**
|
||||
** $QT_BEGIN_LICENSE:GPL-EXCEPT$
|
||||
** Commercial License Usage
|
||||
** Licensees holding valid commercial Qt licenses may use this file in
|
||||
** accordance with the commercial license agreement provided with the
|
||||
** Software or, alternatively, in accordance with the terms contained in
|
||||
** a written agreement between you and The Qt Company. For licensing terms
|
||||
** and conditions see https://www.qt.io/terms-conditions. For further
|
||||
** information use the contact form at https://www.qt.io/contact-us.
|
||||
**
|
||||
** 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.
|
||||
**
|
||||
** $QT_END_LICENSE$
|
||||
**
|
||||
****************************************************************************/
|
||||
#include <QStringList>
|
||||
#include <QtQml/qqmlextensionplugin.h>
|
||||
#include <QtQml/qqml.h>
|
||||
#include <QDebug>
|
||||
|
||||
class MyPluginType : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(int value READ value WRITE setValue)
|
||||
Q_PROPERTY(int valueOnlyIn2 READ value WRITE setValue)
|
||||
|
||||
public:
|
||||
MyPluginType(QObject *parent=0) : QObject(parent)
|
||||
{
|
||||
qWarning("import2.2 worked");
|
||||
}
|
||||
|
||||
int value() const { return v; }
|
||||
void setValue(int i) { v = i; }
|
||||
|
||||
private:
|
||||
int v;
|
||||
};
|
||||
|
||||
|
||||
class MyPlugin : public QQmlExtensionPlugin
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_PLUGIN_METADATA(IID QQmlExtensionInterface_iid)
|
||||
|
||||
public:
|
||||
MyPlugin()
|
||||
{
|
||||
qWarning("plugin2.2 created");
|
||||
}
|
||||
|
||||
void registerTypes(const char *uri)
|
||||
{
|
||||
Q_ASSERT(QLatin1String(uri) == "org.qtproject.AutoTestQmlPluginType");
|
||||
qmlRegisterType<MyPluginType>(uri, 2, 0, "MyPluginType");
|
||||
qmlRegisterModule(uri, 2, 2);
|
||||
}
|
||||
};
|
||||
|
||||
#include "plugin.moc"
|
|
@ -0,0 +1 @@
|
|||
plugin plugin
|
|
@ -20,7 +20,8 @@ SUBDIRS =\
|
|||
protectedModule\
|
||||
plugin/childplugin\
|
||||
plugin.2/childplugin\
|
||||
plugin.2.1/childplugin
|
||||
plugin.2.1/childplugin\
|
||||
plugin.2.2
|
||||
|
||||
tst_qqmlmoduleplugin_pro.depends += plugin
|
||||
SUBDIRS += tst_qqmlmoduleplugin.pro
|
||||
|
|
|
@ -52,8 +52,7 @@ public:
|
|||
private slots:
|
||||
virtual void initTestCase();
|
||||
void importsPlugin();
|
||||
void importsPlugin2();
|
||||
void importsPlugin21();
|
||||
void importsPlugin_data();
|
||||
void importsMixedQmlCppPlugin();
|
||||
void incorrectPluginCase();
|
||||
void importPluginWithQmlFile();
|
||||
|
@ -70,6 +69,7 @@ private slots:
|
|||
void importStrictModule();
|
||||
void importStrictModule_data();
|
||||
void importProtectedModule();
|
||||
void importVersionedModule();
|
||||
void importsChildPlugin();
|
||||
void importsChildPlugin2();
|
||||
void importsChildPlugin21();
|
||||
|
@ -130,12 +130,15 @@ void tst_qqmlmoduleplugin::initTestCase()
|
|||
|
||||
void tst_qqmlmoduleplugin::importsPlugin()
|
||||
{
|
||||
QFETCH(QString, suffix);
|
||||
QFETCH(QString, qmlFile);
|
||||
|
||||
QQmlEngine engine;
|
||||
engine.addImportPath(m_importsDirectory);
|
||||
QTest::ignoreMessage(QtWarningMsg, "plugin created");
|
||||
QTest::ignoreMessage(QtWarningMsg, "import worked");
|
||||
QTest::ignoreMessage(QtWarningMsg, qPrintable(QString("plugin%1 created").arg(suffix)));
|
||||
QTest::ignoreMessage(QtWarningMsg, qPrintable(QString("import%1 worked").arg(suffix)));
|
||||
QTest::ignoreMessage(QtWarningMsg, "Module 'org.qtproject.AutoTestQmlPluginType' does not contain a module identifier directive - it cannot be protected from external registrations.");
|
||||
QQmlComponent component(&engine, testFileUrl(QStringLiteral("works.qml")));
|
||||
QQmlComponent component(&engine, testFileUrl(qmlFile));
|
||||
foreach (QQmlError err, component.errors())
|
||||
qWarning() << err;
|
||||
VERIFY_ERRORS(0);
|
||||
|
@ -145,38 +148,15 @@ void tst_qqmlmoduleplugin::importsPlugin()
|
|||
delete object;
|
||||
}
|
||||
|
||||
void tst_qqmlmoduleplugin::importsPlugin2()
|
||||
void tst_qqmlmoduleplugin::importsPlugin_data()
|
||||
{
|
||||
QQmlEngine engine;
|
||||
engine.addImportPath(m_importsDirectory);
|
||||
QTest::ignoreMessage(QtWarningMsg, "plugin2 created");
|
||||
QTest::ignoreMessage(QtWarningMsg, "import2 worked");
|
||||
QTest::ignoreMessage(QtWarningMsg, "Module 'org.qtproject.AutoTestQmlPluginType' does not contain a module identifier directive - it cannot be protected from external registrations.");
|
||||
QQmlComponent component(&engine, testFileUrl(QStringLiteral("works2.qml")));
|
||||
foreach (QQmlError err, component.errors())
|
||||
qWarning() << err;
|
||||
VERIFY_ERRORS(0);
|
||||
QObject *object = component.create();
|
||||
QVERIFY(object != 0);
|
||||
QCOMPARE(object->property("value").toInt(),123);
|
||||
delete object;
|
||||
}
|
||||
QTest::addColumn<QString>("suffix");
|
||||
QTest::addColumn<QString>("qmlFile");
|
||||
|
||||
void tst_qqmlmoduleplugin::importsPlugin21()
|
||||
{
|
||||
QQmlEngine engine;
|
||||
engine.addImportPath(m_importsDirectory);
|
||||
QTest::ignoreMessage(QtWarningMsg, "plugin2.1 created");
|
||||
QTest::ignoreMessage(QtWarningMsg, "import2.1 worked");
|
||||
QTest::ignoreMessage(QtWarningMsg, "Module 'org.qtproject.AutoTestQmlPluginType' does not contain a module identifier directive - it cannot be protected from external registrations.");
|
||||
QQmlComponent component(&engine, testFileUrl(QStringLiteral("works21.qml")));
|
||||
foreach (QQmlError err, component.errors())
|
||||
qWarning() << err;
|
||||
VERIFY_ERRORS(0);
|
||||
QObject *object = component.create();
|
||||
QVERIFY(object != 0);
|
||||
QCOMPARE(object->property("value").toInt(),123);
|
||||
delete object;
|
||||
QTest::newRow("1.0") << "" << "works.qml";
|
||||
QTest::newRow("2.0") << "2" << "works2.qml";
|
||||
QTest::newRow("2.1") << "2.1" << "works21.qml";
|
||||
QTest::newRow("2.2") << "2.2" << "works22.qml";
|
||||
}
|
||||
|
||||
void tst_qqmlmoduleplugin::incorrectPluginCase()
|
||||
|
@ -578,6 +558,32 @@ void tst_qqmlmoduleplugin::importProtectedModule()
|
|||
QVERIFY(object != 0);
|
||||
}
|
||||
|
||||
void tst_qqmlmoduleplugin::importVersionedModule()
|
||||
{
|
||||
qmlRegisterType<QObject>("org.qtproject.VersionedModule", 1, 0, "TestType");
|
||||
qmlRegisterModule("org.qtproject.VersionedModule", 1, 1);
|
||||
|
||||
QQmlEngine engine;
|
||||
engine.addImportPath(m_importsDirectory);
|
||||
|
||||
QUrl url(testFileUrl("empty.qml"));
|
||||
|
||||
QQmlComponent component(&engine);
|
||||
component.setData("import org.qtproject.VersionedModule 1.0\n TestType {}\n", url);
|
||||
QScopedPointer<QObject> object10(component.create());
|
||||
QVERIFY(!object10.isNull());
|
||||
|
||||
component.setData("import org.qtproject.VersionedModule 1.1\n TestType {}\n", url);
|
||||
QScopedPointer<QObject> object11(component.create());
|
||||
QVERIFY(!object11.isNull());
|
||||
|
||||
component.setData("import org.qtproject.VersionedModule 1.2\n TestType {}\n", url);
|
||||
QTest::ignoreMessage(QtWarningMsg, "QQmlComponent: Component is not ready");
|
||||
QScopedPointer<QObject> object12(component.create());
|
||||
QVERIFY(object12.isNull());
|
||||
QCOMPARE(component.errorString(), QString("%1:1 module \"org.qtproject.VersionedModule\" version 1.2 is not installed\n").arg(url.toString()));
|
||||
}
|
||||
|
||||
void tst_qqmlmoduleplugin::importsChildPlugin()
|
||||
{
|
||||
QQmlEngine engine;
|
||||
|
|
Loading…
Reference in New Issue