Allow dynamic and static registration of same URI in any order
Previously, a static registration would not go through if a dynamic registration was carried out before the first type of the statically registered module was referenced. Change-Id: Icf6a2b78dff7d0e5b29138501e04723510d6a668 Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io>
This commit is contained in:
parent
bc3700d746
commit
2fae1d7e8f
|
@ -602,49 +602,57 @@ bool QQmlTypeLoader::Blob::addImport(QQmlTypeLoader::Blob::PendingImportPtr impo
|
|||
scriptImported(blob, import->location, script.nameSpace, import->qualifier);
|
||||
}
|
||||
}
|
||||
} else if (
|
||||
// Major version of module already registered:
|
||||
// We believe that the registration is complete.
|
||||
QQmlMetaType::typeModule(import->uri, import->majorVersion)
|
||||
|
||||
// Otherwise, try to register further module types.
|
||||
|| (qmldirResult != QQmlImports::QmldirInterceptedToRemote
|
||||
&& QQmlMetaType::qmlRegisterModuleTypes(import->uri, import->majorVersion))
|
||||
|
||||
// Otherwise, there is no way to register any further types.
|
||||
// Try with any module of that name.
|
||||
|| QQmlMetaType::isAnyModule(import->uri)) {
|
||||
|
||||
if (!m_importCache.addLibraryImport(
|
||||
importDatabase, import->uri, import->qualifier, import->majorVersion,
|
||||
import->minorVersion, QString(), QString(), false, errors)) {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
// Is this a module?
|
||||
if (QQmlMetaType::isAnyModule(import->uri)
|
||||
|| (qmldirResult != QQmlImports::QmldirInterceptedToRemote
|
||||
&& QQmlMetaType::qmlRegisterModuleTypes(import->uri,
|
||||
import->majorVersion))) {
|
||||
// We haven't yet resolved this import
|
||||
m_unresolvedImports << import;
|
||||
|
||||
QQmlAbstractUrlInterceptor *interceptor = typeLoader()->engine()->urlInterceptor();
|
||||
|
||||
// Query any network import paths for this library.
|
||||
// Interceptor might redirect local paths.
|
||||
QStringList remotePathList = importDatabase->importPathList(
|
||||
interceptor ? QQmlImportDatabase::LocalOrRemote
|
||||
: QQmlImportDatabase::Remote);
|
||||
if (!remotePathList.isEmpty()) {
|
||||
// Add this library and request the possible locations for it
|
||||
if (!m_importCache.addLibraryImport(importDatabase, import->uri, import->qualifier, import->majorVersion,
|
||||
import->minorVersion, QString(), QString(), false, errors))
|
||||
import->minorVersion, QString(), QString(), true, errors))
|
||||
return false;
|
||||
} else {
|
||||
// We haven't yet resolved this import
|
||||
m_unresolvedImports << import;
|
||||
|
||||
QQmlAbstractUrlInterceptor *interceptor = typeLoader()->engine()->urlInterceptor();
|
||||
|
||||
// Query any network import paths for this library.
|
||||
// Interceptor might redirect local paths.
|
||||
QStringList remotePathList = importDatabase->importPathList(
|
||||
interceptor ? QQmlImportDatabase::LocalOrRemote
|
||||
: QQmlImportDatabase::Remote);
|
||||
if (!remotePathList.isEmpty()) {
|
||||
// Add this library and request the possible locations for it
|
||||
if (!m_importCache.addLibraryImport(importDatabase, import->uri, import->qualifier, import->majorVersion,
|
||||
import->minorVersion, QString(), QString(), true, errors))
|
||||
return false;
|
||||
|
||||
// Probe for all possible locations
|
||||
int priority = 0;
|
||||
const QStringList qmlDirPaths = QQmlImports::completeQmldirPaths(import->uri, remotePathList, import->majorVersion, import->minorVersion);
|
||||
for (const QString &qmldirPath : qmlDirPaths) {
|
||||
if (interceptor) {
|
||||
QUrl url = interceptor->intercept(
|
||||
QQmlImports::urlFromLocalFileOrQrcOrUrl(qmldirPath),
|
||||
QQmlAbstractUrlInterceptor::QmldirFile);
|
||||
if (!QQmlFile::isLocalFile(url)
|
||||
&& !fetchQmldir(url, import, ++priority, errors)) {
|
||||
return false;
|
||||
}
|
||||
} else if (!fetchQmldir(QUrl(qmldirPath), import, ++priority, errors)) {
|
||||
// Probe for all possible locations
|
||||
int priority = 0;
|
||||
const QStringList qmlDirPaths = QQmlImports::completeQmldirPaths(import->uri, remotePathList, import->majorVersion, import->minorVersion);
|
||||
for (const QString &qmldirPath : qmlDirPaths) {
|
||||
if (interceptor) {
|
||||
QUrl url = interceptor->intercept(
|
||||
QQmlImports::urlFromLocalFileOrQrcOrUrl(qmldirPath),
|
||||
QQmlAbstractUrlInterceptor::QmldirFile);
|
||||
if (!QQmlFile::isLocalFile(url)
|
||||
&& !fetchQmldir(url, import, ++priority, errors)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
} else if (!fetchQmldir(QUrl(qmldirPath), import, ++priority, errors)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,27 @@
|
|||
import QtQuick 2.12
|
||||
import io.qt.bugreports 2.0
|
||||
Item {
|
||||
InterfaceConsumer2 {
|
||||
objectName: "a1"
|
||||
i: A2 {
|
||||
property int i: 42
|
||||
}
|
||||
}
|
||||
|
||||
InterfaceConsumer2 {
|
||||
objectName: "a2"
|
||||
property A2 a: A2 {
|
||||
property int i: 43
|
||||
}
|
||||
i: a
|
||||
}
|
||||
|
||||
InterfaceConsumer2 {
|
||||
objectName: "a3"
|
||||
property A2 a: A2 {
|
||||
id : aa
|
||||
property int i: 44
|
||||
}
|
||||
i: aa
|
||||
}
|
||||
}
|
|
@ -0,0 +1,160 @@
|
|||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2020 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$
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef INTERFACES_H
|
||||
#define INTERFACES_H
|
||||
|
||||
#include <QtQml/qqml.h>
|
||||
|
||||
struct Interface {
|
||||
};
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
#define MyInterface_iid "io.qt.bugreports.Interface"
|
||||
Q_DECLARE_INTERFACE(Interface, MyInterface_iid);
|
||||
QT_END_NAMESPACE
|
||||
|
||||
class A : public QObject, Interface {
|
||||
Q_OBJECT
|
||||
Q_INTERFACES(Interface)
|
||||
};
|
||||
|
||||
class B : public QObject, Interface {
|
||||
Q_OBJECT
|
||||
Q_INTERFACES(Interface)
|
||||
};
|
||||
|
||||
class C : public QObject {
|
||||
Q_OBJECT
|
||||
};
|
||||
|
||||
struct Interface2
|
||||
{
|
||||
Q_GADGET
|
||||
};
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
#define MyInterface2_iid "io.qt.bugreports.Interface2"
|
||||
Q_DECLARE_INTERFACE(Interface2, MyInterface2_iid);
|
||||
QT_END_NAMESPACE
|
||||
|
||||
class A2 : public QObject, Interface2 {
|
||||
Q_OBJECT
|
||||
QML_ELEMENT
|
||||
Q_INTERFACES(Interface2)
|
||||
};
|
||||
|
||||
class B2 : public QObject, Interface2 {
|
||||
Q_OBJECT
|
||||
QML_ELEMENT
|
||||
Q_INTERFACES(Interface2)
|
||||
};
|
||||
|
||||
class C2 : public QObject {
|
||||
Q_OBJECT
|
||||
QML_ELEMENT
|
||||
};
|
||||
|
||||
class InterfaceConsumer : public QObject {
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(Interface *i READ interface WRITE setInterface NOTIFY interfaceChanged)
|
||||
Q_PROPERTY(int testValue READ testValue NOTIFY testValueChanged)
|
||||
|
||||
public:
|
||||
|
||||
Interface* interface() const
|
||||
{
|
||||
return m_interface;
|
||||
}
|
||||
void setInterface(Interface* interface)
|
||||
{
|
||||
QObject* object = reinterpret_cast<QObject*>(interface);
|
||||
m_testValue = object->property("i").toInt();
|
||||
emit testValueChanged();
|
||||
if (m_interface == interface)
|
||||
return;
|
||||
|
||||
m_interface = interface;
|
||||
emit interfaceChanged();
|
||||
}
|
||||
|
||||
int testValue() {
|
||||
return m_testValue;
|
||||
}
|
||||
|
||||
signals:
|
||||
void interfaceChanged();
|
||||
void testValueChanged();
|
||||
|
||||
private:
|
||||
Interface* m_interface = nullptr;
|
||||
int m_testValue = 0;
|
||||
};
|
||||
|
||||
|
||||
class InterfaceConsumer2 : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
Q_PROPERTY(Interface2 *i READ interface WRITE setInterface NOTIFY interfaceChanged)
|
||||
Q_PROPERTY(int testValue READ testValue NOTIFY testValueChanged)
|
||||
|
||||
QML_ELEMENT
|
||||
|
||||
public:
|
||||
|
||||
Interface2* interface() const
|
||||
{
|
||||
return m_interface;
|
||||
}
|
||||
void setInterface(Interface2* interface2)
|
||||
{
|
||||
QObject* object = reinterpret_cast<QObject*>(interface2);
|
||||
m_testValue = object->property("i").toInt();
|
||||
emit testValueChanged();
|
||||
if (m_interface == interface2)
|
||||
return;
|
||||
|
||||
m_interface = interface2;
|
||||
emit interfaceChanged();
|
||||
}
|
||||
|
||||
int testValue() {
|
||||
return m_testValue;
|
||||
}
|
||||
|
||||
signals:
|
||||
void interfaceChanged();
|
||||
void testValueChanged();
|
||||
|
||||
private:
|
||||
Interface2 *m_interface = nullptr;
|
||||
int m_testValue = 0;
|
||||
};
|
||||
|
||||
#endif // INTERFACES_H
|
|
@ -1,7 +1,10 @@
|
|||
CONFIG += testcase
|
||||
CONFIG += testcase qmltypes
|
||||
TARGET = tst_qqmlproperty
|
||||
macx:CONFIG -= app_bundle
|
||||
|
||||
QML_IMPORT_NAME = io.qt.bugreports
|
||||
QML_IMPORT_VERSION = 2.0
|
||||
|
||||
SOURCES += tst_qqmlproperty.cpp
|
||||
|
||||
include (../../shared/util.pri)
|
||||
|
@ -9,3 +12,6 @@ include (../../shared/util.pri)
|
|||
TESTDATA = data/*
|
||||
|
||||
QT += core-private gui-private qml-private testlib
|
||||
|
||||
HEADERS += \
|
||||
interfaces.h
|
||||
|
|
|
@ -25,6 +25,8 @@
|
|||
** $QT_END_LICENSE$
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#include "interfaces.h"
|
||||
#include <qtest.h>
|
||||
#include <QtQml/qqmlengine.h>
|
||||
#include <QtQml/qqmlcomponent.h>
|
||||
|
@ -2090,74 +2092,22 @@ void tst_qqmlproperty::nullPropertyBinding()
|
|||
QMetaObject::invokeMethod(root.get(), "tog");
|
||||
}
|
||||
|
||||
struct Interface {
|
||||
};
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
#define MyInterface_iid "io.qt.bugreports.Interface"
|
||||
Q_DECLARE_INTERFACE(Interface, MyInterface_iid);
|
||||
QT_END_NAMESPACE
|
||||
|
||||
class A : public QObject, Interface {
|
||||
Q_OBJECT
|
||||
Q_INTERFACES(Interface)
|
||||
};
|
||||
|
||||
class B : public QObject, Interface {
|
||||
Q_OBJECT
|
||||
Q_INTERFACES(Interface)
|
||||
};
|
||||
|
||||
class C : public QObject {
|
||||
Q_OBJECT
|
||||
};
|
||||
|
||||
class InterfaceConsumer : public QObject {
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(Interface* i READ interface WRITE setInterface NOTIFY interfaceChanged)
|
||||
Q_PROPERTY(int testValue READ testValue NOTIFY testValueChanged)
|
||||
|
||||
|
||||
public:
|
||||
|
||||
Interface* interface() const
|
||||
{
|
||||
return m_interface;
|
||||
}
|
||||
void setInterface(Interface* interface)
|
||||
{
|
||||
QObject* object = reinterpret_cast<QObject*>(interface);
|
||||
m_testValue = object->property("i").toInt();
|
||||
emit testValueChanged();
|
||||
if (m_interface == interface)
|
||||
return;
|
||||
|
||||
m_interface = interface;
|
||||
emit interfaceChanged();
|
||||
}
|
||||
|
||||
int testValue() {
|
||||
return m_testValue;
|
||||
}
|
||||
|
||||
signals:
|
||||
void interfaceChanged();
|
||||
void testValueChanged();
|
||||
|
||||
private:
|
||||
Interface* m_interface = nullptr;
|
||||
int m_testValue = 0;
|
||||
};
|
||||
void tst_qqmlproperty::interfaceBinding()
|
||||
{
|
||||
qmlRegisterInterface<Interface>("Interface");
|
||||
qmlRegisterType<A>("io.qt.bugreports", 1, 0, "A");
|
||||
qmlRegisterType<B>("io.qt.bugreports", 1, 0, "B");
|
||||
qmlRegisterType<C>("io.qt.bugreports", 1, 0, "C");
|
||||
qmlRegisterType<InterfaceConsumer>("io.qt.bugreports", 1, 0, "InterfaceConsumer");
|
||||
|
||||
qmlRegisterInterface<Interface>("Interface");
|
||||
qmlRegisterType<A>("io.qt.bugreports", 1, 0, "A");
|
||||
qmlRegisterType<B>("io.qt.bugreports", 1, 0, "B");
|
||||
qmlRegisterType<C>("io.qt.bugreports", 1, 0, "C");
|
||||
qmlRegisterType<InterfaceConsumer>("io.qt.bugreports", 1, 0, "InterfaceConsumer");
|
||||
qmlRegisterInterface<Interface2>("Interface2");
|
||||
|
||||
const QUrl url = testFileUrl("interfaceBinding.qml");
|
||||
const QVector<QUrl> urls = {
|
||||
testFileUrl("interfaceBinding.qml"),
|
||||
testFileUrl("interfaceBinding2.qml")
|
||||
};
|
||||
|
||||
for (const QUrl &url : urls) {
|
||||
QQmlEngine engine;
|
||||
QQmlComponent component(&engine, url);
|
||||
QScopedPointer<QObject> root(component.create());
|
||||
|
@ -2165,6 +2115,7 @@ void tst_qqmlproperty::interfaceBinding()
|
|||
QCOMPARE(root->findChild<QObject*>("a1")->property("testValue").toInt(), 42);
|
||||
QCOMPARE(root->findChild<QObject*>("a2")->property("testValue").toInt(), 43);
|
||||
QCOMPARE(root->findChild<QObject*>("a3")->property("testValue").toInt(), 44);
|
||||
}
|
||||
}
|
||||
|
||||
void tst_qqmlproperty::floatToStringPrecision_data()
|
||||
|
|
Loading…
Reference in New Issue