diff options
Diffstat (limited to 'tests')
129 files changed, 1680 insertions, 217 deletions
diff --git a/tests/auto/qml/qmlcachegen/retain.qrc b/tests/auto/qml/qmlcachegen/data/retain.qrc index e5eed9b12f..e1b9045fbe 100644 --- a/tests/auto/qml/qmlcachegen/retain.qrc +++ b/tests/auto/qml/qmlcachegen/data/retain.qrc @@ -1,5 +1,5 @@ <RCC> <qresource prefix="/"> - <file alias="Retain.qml">data/Retain.qml</file> + <file alias="Retain.qml">Retain.qml</file> </qresource> </RCC> diff --git a/tests/auto/qml/qmlcachegen/qmlcachegen.pro b/tests/auto/qml/qmlcachegen/qmlcachegen.pro index 53b26ccfae..1a334b68ce 100644 --- a/tests/auto/qml/qmlcachegen/qmlcachegen.pro +++ b/tests/auto/qml/qmlcachegen/qmlcachegen.pro @@ -27,7 +27,7 @@ workerscripts_test.prefix = /workerscripts RESOURCES += \ workerscripts_test \ trickypaths.qrc \ - retain.qrc + data/retain.qrc # QTBUG-46375 !win32: RESOURCES += trickypaths_umlaut.qrc diff --git a/tests/auto/qml/qmlcachegen/tst_qmlcachegen.cpp b/tests/auto/qml/qmlcachegen/tst_qmlcachegen.cpp index f89982f782..5d87c319f3 100644 --- a/tests/auto/qml/qmlcachegen/tst_qmlcachegen.cpp +++ b/tests/auto/qml/qmlcachegen/tst_qmlcachegen.cpp @@ -361,7 +361,7 @@ static QQmlPrivate::CachedQmlUnit *temporaryModifiedCachedUnit = nullptr; void tst_qmlcachegen::versionChecksForAheadOfTimeUnits() { QVERIFY(QFile::exists(":/data/versionchecks.qml")); - QCOMPARE(QFileInfo(":/data/versionchecks.qml").size(), 0); + QVERIFY(QFileInfo(":/data/versionchecks.qml").size() > 0); Q_ASSERT(!temporaryModifiedCachedUnit); QQmlMetaType::CachedUnitLookupError error = QQmlMetaType::CachedUnitLookupError::NoError; @@ -388,12 +388,8 @@ void tst_qmlcachegen::versionChecksForAheadOfTimeUnits() { QQmlEngine engine; - QQmlComponent component(&engine, QUrl("qrc:/data/versionchecks.qml")); - QCOMPARE(component.status(), QQmlComponent::Error); - QCOMPARE(component.errorString(), - QString("qrc:/data/versionchecks.qml:-1 File was compiled ahead of time with an " - "incompatible version of Qt and the original file cannot be found. Please " - "recompile\n")); + CleanlyLoadingComponent component(&engine, QUrl("qrc:/data/versionchecks.qml")); + QCOMPARE(component.status(), QQmlComponent::Ready); } Q_ASSERT(temporaryModifiedCachedUnit); @@ -415,7 +411,7 @@ void tst_qmlcachegen::workerScripts() { QVERIFY(QFile::exists(":/workerscripts/data/worker.js")); QVERIFY(QFile::exists(":/workerscripts/data/worker.qml")); - QCOMPARE(QFileInfo(":/workerscripts/data/worker.js").size(), 0); + QVERIFY(QFileInfo(":/workerscripts/data/worker.js").size() > 0); QQmlEngine engine; CleanlyLoadingComponent component(&engine, QUrl("qrc:///workerscripts/data/worker.qml")); @@ -504,7 +500,7 @@ void tst_qmlcachegen::trickyPaths() { QFETCH(QString, filePath); QVERIFY2(QFile::exists(filePath), qPrintable(filePath)); - QCOMPARE(QFileInfo(filePath).size(), 0); + QVERIFY(QFileInfo(filePath).size() > 0); QQmlEngine engine; QQmlComponent component(&engine, QUrl("qrc" + filePath)); QScopedPointer<QObject> obj(component.create()); @@ -585,7 +581,7 @@ void tst_qmlcachegen::moduleScriptImport() QTRY_VERIFY(obj->property("ok").toBool()); QVERIFY(QFile::exists(":/data/script.mjs")); - QCOMPARE(QFileInfo(":/data/script.mjs").size(), 0); + QVERIFY(QFileInfo(":/data/script.mjs").size() > 0); { auto componentPrivate = QQmlComponentPrivate::get(&component); @@ -608,7 +604,6 @@ void tst_qmlcachegen::moduleScriptImport() void tst_qmlcachegen::esModulesViaQJSEngine() { - QCOMPARE(QFileInfo(":/data/module.mjs").size(), 0); QJSEngine engine; QJSValue module = engine.importModule(":/data/module.mjs"); QJSValue result = module.property("entry").call(); @@ -627,7 +622,7 @@ void tst_qmlcachegen::enums() void tst_qmlcachegen::sourceFileIndices() { QVERIFY(QFile::exists(":/data/versionchecks.qml")); - QCOMPARE(QFileInfo(":/data/versionchecks.qml").size(), 0); + QVERIFY(QFileInfo(":/data/versionchecks.qml").size() > 0); QQmlMetaType::CachedUnitLookupError error = QQmlMetaType::CachedUnitLookupError::NoError; const QV4::CompiledData::Unit *unitFromResources = QQmlMetaType::findCachedCompilationUnit( @@ -642,8 +637,7 @@ void tst_qmlcachegen::reproducibleCache_data() QTest::addColumn<QString>("filePath"); QDir dir(dataDirectory()); - for (const QString &entry : dir.entryList(QDir::Files)) { - QVERIFY(entry.endsWith(".qml") || entry.endsWith(".js") || entry.endsWith(".mjs")); + for (const QString &entry : dir.entryList((QStringList() << "*.qml" << "*.js" << "*.mjs"), QDir::Files)) { QTest::newRow(entry.toUtf8().constData()) << dir.filePath(entry); } } diff --git a/tests/auto/qml/qmllint/data/Form.ui.qml b/tests/auto/qml/qmllint/data/Form.ui.qml new file mode 100644 index 0000000000..459c82afbb --- /dev/null +++ b/tests/auto/qml/qmllint/data/Form.ui.qml @@ -0,0 +1,4 @@ +import QtQuick 2.0 + +Item { +} diff --git a/tests/auto/qml/qmllint/data/FormUser.qml b/tests/auto/qml/qmllint/data/FormUser.qml new file mode 100644 index 0000000000..ea3621586f --- /dev/null +++ b/tests/auto/qml/qmllint/data/FormUser.qml @@ -0,0 +1,7 @@ +import QtQuick 2.0 + +Form { + x: 12 + y: 13 + objectName: "horst" +} diff --git a/tests/auto/qml/qmllint/data/ImportWithPrefix.qml b/tests/auto/qml/qmllint/data/ImportWithPrefix.qml new file mode 100644 index 0000000000..6d070da21a --- /dev/null +++ b/tests/auto/qml/qmllint/data/ImportWithPrefix.qml @@ -0,0 +1,5 @@ +import "." as MyStuff + +MyStuff.Simple { + property bool something: contains(Qt.point(12, 34)) +} diff --git a/tests/auto/qml/qmllint/data/MethodInItem.qml b/tests/auto/qml/qmllint/data/MethodInItem.qml new file mode 100644 index 0000000000..dbdaf8bcc1 --- /dev/null +++ b/tests/auto/qml/qmllint/data/MethodInItem.qml @@ -0,0 +1,5 @@ +import QtQml 2.0 + +QtObject { + function doThings() { console.log("things") } +} diff --git a/tests/auto/qml/qmllint/data/MethodInScope.qml b/tests/auto/qml/qmllint/data/MethodInScope.qml new file mode 100644 index 0000000000..7ba0829f61 --- /dev/null +++ b/tests/auto/qml/qmllint/data/MethodInScope.qml @@ -0,0 +1,5 @@ +import QtQml 2.0 + +MethodInItem { + Component.onCompleted: doThings() +} diff --git a/tests/auto/qml/qmllint/data/Things/SomethingElse.qml b/tests/auto/qml/qmllint/data/Things/SomethingElse.qml new file mode 100644 index 0000000000..0e69012662 --- /dev/null +++ b/tests/auto/qml/qmllint/data/Things/SomethingElse.qml @@ -0,0 +1,2 @@ +import QtQml 2.0 +QtObject {} diff --git a/tests/auto/qml/qmllint/data/Things/plugins.qmltypes b/tests/auto/qml/qmllint/data/Things/plugins.qmltypes new file mode 100644 index 0000000000..00cda191cc --- /dev/null +++ b/tests/auto/qml/qmllint/data/Things/plugins.qmltypes @@ -0,0 +1,16 @@ +import QtQuick.tooling 1.2 +Module { + dependencies: [] + Component { + name: "SomethingEntirelyStrange" + prototype: "QObject" + Enum { + name: "AnEnum" + values: { + "AAA": 0, + "BBB": 1, + "CCC": 2 + } + } + } +} diff --git a/tests/auto/qml/qmllint/data/Things/qmldir b/tests/auto/qml/qmllint/data/Things/qmldir new file mode 100644 index 0000000000..c53af3a340 --- /dev/null +++ b/tests/auto/qml/qmllint/data/Things/qmldir @@ -0,0 +1,3 @@ +module Things +Something 1.0 SomethingElse.qml +plugin doesNotExistPlugin diff --git a/tests/auto/qml/qmllint/data/UnmatchedSignalHandler.qml b/tests/auto/qml/qmllint/data/UnmatchedSignalHandler.qml new file mode 100644 index 0000000000..064444e182 --- /dev/null +++ b/tests/auto/qml/qmllint/data/UnmatchedSignalHandler.qml @@ -0,0 +1,15 @@ +import QtQuick 2.12 + +Item { + width: 640 + height: 480 + + MouseArea { + anchors.fill: parent + onClicked: console.log("okok") + + Connections { + onClicked: console.log(mouse.x) + } + } +} diff --git a/tests/auto/qml/qmllint/data/forLoop.qml b/tests/auto/qml/qmllint/data/forLoop.qml new file mode 100644 index 0000000000..be8b12409b --- /dev/null +++ b/tests/auto/qml/qmllint/data/forLoop.qml @@ -0,0 +1,9 @@ +import QtQml 2.0 + +QtObject { + Component.onCompleted: { + var stuff = [1, 2, 3, 4] + for (var a in stuff) + console.log(a); + } +} diff --git a/tests/auto/qml/qmllint/data/qmldirAndQmltypes.qml b/tests/auto/qml/qmllint/data/qmldirAndQmltypes.qml new file mode 100644 index 0000000000..4847fc9196 --- /dev/null +++ b/tests/auto/qml/qmllint/data/qmldirAndQmltypes.qml @@ -0,0 +1,6 @@ +import Things 1.0 + +Something { + property var a: SomethingEntirelyStrange {} + property var b: SomethingEntirelyStrange.AAA +} diff --git a/tests/auto/qml/qmllint/tst_qmllint.cpp b/tests/auto/qml/qmllint/tst_qmllint.cpp index 582f146dca..04f554ac48 100644 --- a/tests/auto/qml/qmllint/tst_qmllint.cpp +++ b/tests/auto/qml/qmllint/tst_qmllint.cpp @@ -38,13 +38,21 @@ class TestQmllint: public QQmlDataTest private Q_SLOTS: void initTestCase() override; - void test(); - void test_data(); + void testUnqualified(); void testUnqualified_data(); + + void cleanQmlCode_data(); + void cleanQmlCode(); + + void dirtyQmlCode_data(); + void dirtyQmlCode(); + void testUnqualifiedNoSpuriousParentWarning(); - void catchIdentifierNoFalsePositive(); + private: + QString runQmllint(const QString &fileToLint, bool shouldSucceed); + QString m_qmllintPath; }; @@ -61,37 +69,14 @@ void TestQmllint::initTestCase() } } -void TestQmllint::test_data() -{ - QTest::addColumn<QString>("filename"); - QTest::addColumn<bool>("isValid"); - - // Valid files: - QTest::newRow("Simple_QML") << QStringLiteral("Simple.qml") << true; - QTest::newRow("QML_importing_JS") << QStringLiteral("importing_js.qml") << true; - QTest::newRow("QTBUG-45916_JS_with_pragma_and_import") << QStringLiteral("QTBUG-45916.js") << true; - - // Invalid files: - QTest::newRow("Invalid_syntax_QML") << QStringLiteral("failure1.qml") << false; - QTest::newRow("Invalid_syntax_JS") << QStringLiteral("failure1.js") << false; -} - void TestQmllint::testUnqualified() { - auto qmlImportDir = QLibraryInfo::location(QLibraryInfo::Qml2ImportsPath); QFETCH(QString, filename); QFETCH(QString, warningMessage); QFETCH(int, warningLine); QFETCH(int, warningColumn); - QStringList args; - args << QStringLiteral("-U") << testFile(filename) << QStringLiteral("-I") << qmlImportDir; - - QProcess process; - process.start(m_qmllintPath, args); - QVERIFY(process.waitForFinished()); - QVERIFY(process.exitStatus() == QProcess::NormalExit); - QVERIFY(process.exitCode()); - QString output = process.readAllStandardError(); + + const QString output = runQmllint(filename, false); QVERIFY(output.contains(QString::asprintf("Warning: unqualified access at %d:%d", warningLine, warningColumn))); QVERIFY(output.contains(warningMessage)); } @@ -118,56 +103,97 @@ void TestQmllint::testUnqualified_data() QTest::newRow("SignalHandlerShort2") << QStringLiteral("SignalHandler.qml") << QStringLiteral("onPressAndHold: (mouse) => {...") << 12 << 34; // access catch identifier outside catch block QTest::newRow("CatchStatement") << QStringLiteral("CatchStatement.qml") << QStringLiteral("err") << 6 << 21; + + QTest::newRow("NonSpuriousParent") << QStringLiteral("nonSpuriousParentWarning.qml") << QStringLiteral("property int x: <id>.parent.x") << 6 << 25; } void TestQmllint::testUnqualifiedNoSpuriousParentWarning() { - auto qmlImportDir = QLibraryInfo::location(QLibraryInfo::Qml2ImportsPath); - { - QString filename = testFile("spuriousParentWarning.qml"); - QStringList args; - args << QStringLiteral("-U") << filename << QStringLiteral("-I") << qmlImportDir; - QProcess process; - process.start(m_qmllintPath, args); - QVERIFY(process.waitForFinished()); - QVERIFY(process.exitStatus() == QProcess::NormalExit); - QVERIFY(process.exitCode() == 0); - } - { - QString filename = testFile("nonSpuriousParentWarning.qml"); - QStringList args; - args << QStringLiteral("-U") << filename << QStringLiteral("-I") << qmlImportDir; - QProcess process; - process.start(m_qmllintPath, args); - QVERIFY(process.waitForFinished()); - QVERIFY(process.exitStatus() == QProcess::NormalExit); - QVERIFY(process.exitCode()); - } + const QString unknownNotFound = runQmllint("spuriousParentWarning.qml", true); + QVERIFY(unknownNotFound.contains( + QStringLiteral("warning: Unknown was not found. Did you add all import paths?"))); } -void TestQmllint::catchIdentifierNoFalsePositive() +void TestQmllint::dirtyQmlCode_data() { - auto qmlImportDir = QLibraryInfo::location(QLibraryInfo::Qml2ImportsPath); - QString filename = QLatin1String("catchIdentifierNoWarning.qml"); - filename.prepend(QStringLiteral("data/")); - QStringList args; - args << QStringLiteral("-U") << filename << QStringLiteral("-I") << qmlImportDir; - QProcess process; - process.start(m_qmllintPath, args); - QVERIFY(process.waitForFinished()); - QVERIFY(process.exitStatus() == QProcess::NormalExit); - QVERIFY(process.exitCode() == 0); + QTest::addColumn<QString>("filename"); + QTest::addColumn<QString>("warningMessage"); + QTest::addColumn<QString>("notContained"); + + QTest::newRow("Invalid_syntax_QML") + << QStringLiteral("failure1.qml") + << QStringLiteral("failure1.qml:4 : Expected token `:'") + << QString(); + QTest::newRow("Invalid_syntax_JS") + << QStringLiteral("failure1.js") + << QStringLiteral("failure1.js:4 : Expected token `;'") + << QString(); + QTest::newRow("UnmatchedSignalHandler") + << QStringLiteral("UnmatchedSignalHandler.qml") + << QString("Warning: no matching signal found for handler \"onClicked\" at 12:13") + << QStringLiteral("onMouseXChanged"); } -void TestQmllint::test() +void TestQmllint::dirtyQmlCode() { QFETCH(QString, filename); - QFETCH(bool, isValid); - QStringList args; - args << QStringLiteral("--silent") << testFile(filename); + QFETCH(QString, warningMessage); + QFETCH(QString, notContained); + + const QString output = runQmllint(filename, false); + QVERIFY(output.contains(warningMessage)); + if (!notContained.isEmpty()) + QVERIFY(!output.contains(notContained)); +} + +void TestQmllint::cleanQmlCode_data() +{ + QTest::addColumn<QString>("filename"); + QTest::newRow("Simple_QML") << QStringLiteral("Simple.qml"); + QTest::newRow("QML_importing_JS") << QStringLiteral("importing_js.qml"); + QTest::newRow("JS_with_pragma_and_import") << QStringLiteral("QTBUG-45916.js"); + QTest::newRow("uiQml") << QStringLiteral("FormUser.qml"); + QTest::newRow("methodInScope") << QStringLiteral("MethodInScope.qml"); + QTest::newRow("importWithPrefix") << QStringLiteral("ImportWithPrefix.qml"); + QTest::newRow("catchIdentifier") << QStringLiteral("catchIdentifierNoWarning.qml"); + QTest::newRow("qmldirAndQmltypes") << QStringLiteral("qmldirAndQmltypes.qml"); + QTest::newRow("forLoop") << QStringLiteral("forLoop.qml"); +} + +void TestQmllint::cleanQmlCode() +{ + QFETCH(QString, filename); + const QString warnings = runQmllint(filename, true); + QVERIFY(warnings.isEmpty()); +} - bool success = QProcess::execute(m_qmllintPath, args) == 0; - QCOMPARE(success, isValid); +QString TestQmllint::runQmllint(const QString &fileToLint, bool shouldSucceed) +{ + auto qmlImportDir = QLibraryInfo::location(QLibraryInfo::Qml2ImportsPath); + QStringList args; + args << QStringLiteral("-U") << testFile(fileToLint) + << QStringLiteral("-I") << qmlImportDir + << QStringLiteral("-I") << dataDirectory() + << QStringLiteral("--silent"); + QString errors; + auto verify = [&](bool isSilent) { + QProcess process; + process.start(m_qmllintPath, args); + QVERIFY(process.waitForFinished()); + QCOMPARE(process.exitStatus(), QProcess::NormalExit); + if (shouldSucceed) + QCOMPARE(process.exitCode(), 0); + else + QVERIFY(process.exitCode() != 0); + errors = process.readAllStandardError(); + + if (isSilent) + QVERIFY(errors.isEmpty()); + }; + verify(true); + args.removeLast(); + verify(false); + return errors; } QTEST_MAIN(TestQmllint) diff --git a/tests/auto/qml/qmlmin/tst_qmlmin.cpp b/tests/auto/qml/qmlmin/tst_qmlmin.cpp index cae833cd60..79a73299a4 100644 --- a/tests/auto/qml/qmlmin/tst_qmlmin.cpp +++ b/tests/auto/qml/qmlmin/tst_qmlmin.cpp @@ -130,6 +130,8 @@ void tst_qmlmin::initTestCase() invalidFiles << "tests/auto/qml/qjsengine/script/com/trolltech/syntaxerror/__init__.js"; invalidFiles << "tests/auto/qml/debugger/qqmlpreview/data/broken.qml"; invalidFiles << "tests/auto/qml/qqmllanguage/data/fuzzed.2.qml"; + invalidFiles << "tests/auto/qml/qqmllanguage/data/requiredProperties.2.qml"; + invalidFiles << "tests/auto/qml/qqmllanguage/data/requiredProperties.3.qml"; // generatorFunction.qml is not invalid per se, but the minifier cannot handle yield statements invalidFiles << "tests/auto/qml/qqmlecmascript/data/generatorFunction.qml"; #endif diff --git a/tests/auto/qml/qqmlcomponent/data/AliasToSubcomponentRequiredBase.qml b/tests/auto/qml/qqmlcomponent/data/AliasToSubcomponentRequiredBase.qml new file mode 100644 index 0000000000..f693cb4c2e --- /dev/null +++ b/tests/auto/qml/qqmlcomponent/data/AliasToSubcomponentRequiredBase.qml @@ -0,0 +1,10 @@ +import QtQuick 2.13 + +Item { + property alias i_alias: sub.i + + Item { + id: sub + required property int i + } +} diff --git a/tests/auto/qml/qqmlcomponent/data/BaseWithRequired.qml b/tests/auto/qml/qqmlcomponent/data/BaseWithRequired.qml new file mode 100644 index 0000000000..0ce61c8d9d --- /dev/null +++ b/tests/auto/qml/qqmlcomponent/data/BaseWithRequired.qml @@ -0,0 +1,6 @@ +import QtQuick 2.14 + +Item { + id: base + required property int i +} diff --git a/tests/auto/qml/qqmlcomponent/data/aliasToSubcomponentNotSet.qml b/tests/auto/qml/qqmlcomponent/data/aliasToSubcomponentNotSet.qml new file mode 100644 index 0000000000..527eb417e5 --- /dev/null +++ b/tests/auto/qml/qqmlcomponent/data/aliasToSubcomponentNotSet.qml @@ -0,0 +1,4 @@ +import QtQuick 2.13 + +AliasToSubcomponentRequiredBase { +} diff --git a/tests/auto/qml/qqmlcomponent/data/createdFromQml.qml b/tests/auto/qml/qqmlcomponent/data/createdFromQml.qml new file mode 100644 index 0000000000..60a2077606 --- /dev/null +++ b/tests/auto/qml/qqmlcomponent/data/createdFromQml.qml @@ -0,0 +1,11 @@ +import QtQuick 2.14 + +Item { + id: root + property Item it + Component.onCompleted: function() { + let component = Qt.createComponent("requiredNotSet.qml", Component.PreferSynchronous, root) + console.assert(component.status == Component.Ready) + it = component.createObject(component, {i: 42}) + } +} diff --git a/tests/auto/qml/qqmlcomponent/data/createdFromQmlFail.qml b/tests/auto/qml/qqmlcomponent/data/createdFromQmlFail.qml new file mode 100644 index 0000000000..e09ddcccc1 --- /dev/null +++ b/tests/auto/qml/qqmlcomponent/data/createdFromQmlFail.qml @@ -0,0 +1,11 @@ +import QtQuick 2.14 + +Item { + id: root + property Item it + Component.onCompleted: function() { + let component = Qt.createComponent("requiredNotSet.qml", Component.PreferSynchronous, root) + console.assert(component.status == Component.Ready) + root.it = component.createObject(component) + } +} diff --git a/tests/auto/qml/qqmlcomponent/data/requiredNotSet.qml b/tests/auto/qml/qqmlcomponent/data/requiredNotSet.qml new file mode 100644 index 0000000000..c0b5d695f1 --- /dev/null +++ b/tests/auto/qml/qqmlcomponent/data/requiredNotSet.qml @@ -0,0 +1,5 @@ +import QtQuick 2.14 + +Item { + required property int i +} diff --git a/tests/auto/qml/qqmlcomponent/data/requiredSetInSameFile.qml b/tests/auto/qml/qqmlcomponent/data/requiredSetInSameFile.qml new file mode 100644 index 0000000000..76dfcd87e5 --- /dev/null +++ b/tests/auto/qml/qqmlcomponent/data/requiredSetInSameFile.qml @@ -0,0 +1,6 @@ +import QtQuick 2.14 + +Item { + required property int i + i: 42 +} diff --git a/tests/auto/qml/qqmlcomponent/data/requiredSetLater.qml b/tests/auto/qml/qqmlcomponent/data/requiredSetLater.qml new file mode 100644 index 0000000000..3b7811e453 --- /dev/null +++ b/tests/auto/qml/qqmlcomponent/data/requiredSetLater.qml @@ -0,0 +1,5 @@ +import QtQuick 2.14 + +BaseWithRequired { + i: 13 +} diff --git a/tests/auto/qml/qqmlcomponent/data/requiredSetViaAliasAfterSameFile.qml b/tests/auto/qml/qqmlcomponent/data/requiredSetViaAliasAfterSameFile.qml new file mode 100644 index 0000000000..163616bc8a --- /dev/null +++ b/tests/auto/qml/qqmlcomponent/data/requiredSetViaAliasAfterSameFile.qml @@ -0,0 +1,8 @@ +import QtQuick 2.14 + +Item { + id: withAlias + j: 42 + required property int i + property alias j: withAlias.i +} diff --git a/tests/auto/qml/qqmlcomponent/data/requiredSetViaAliasBeforeSameFile.qml b/tests/auto/qml/qqmlcomponent/data/requiredSetViaAliasBeforeSameFile.qml new file mode 100644 index 0000000000..e59bccf379 --- /dev/null +++ b/tests/auto/qml/qqmlcomponent/data/requiredSetViaAliasBeforeSameFile.qml @@ -0,0 +1,8 @@ +import QtQuick 2.14 + +Item { + id: withAlias + required property int i + j: 42 + property alias j: withAlias.i +} diff --git a/tests/auto/qml/qqmlcomponent/data/requiredSetViaAliasParentFile.qml b/tests/auto/qml/qqmlcomponent/data/requiredSetViaAliasParentFile.qml new file mode 100644 index 0000000000..0bc2f8a7df --- /dev/null +++ b/tests/auto/qml/qqmlcomponent/data/requiredSetViaAliasParentFile.qml @@ -0,0 +1,7 @@ +import QtQuick 2.14 + +BaseWithRequired { + id: withAlias + property alias j: withAlias.i + j: 42 +} diff --git a/tests/auto/qml/qqmlcomponent/data/requiredSetViaChainedAlias.qml b/tests/auto/qml/qqmlcomponent/data/requiredSetViaChainedAlias.qml new file mode 100644 index 0000000000..45cf02d3d8 --- /dev/null +++ b/tests/auto/qml/qqmlcomponent/data/requiredSetViaChainedAlias.qml @@ -0,0 +1,9 @@ +import QtQml 2.12 + +QtObject { + id: stuff + required property int x; + property alias y: stuff.x + property alias z: stuff.y + z: 5 +} diff --git a/tests/auto/qml/qqmlcomponent/data/setViaAliasToSubcomponent.qml b/tests/auto/qml/qqmlcomponent/data/setViaAliasToSubcomponent.qml new file mode 100644 index 0000000000..2dc182ea82 --- /dev/null +++ b/tests/auto/qml/qqmlcomponent/data/setViaAliasToSubcomponent.qml @@ -0,0 +1,5 @@ +import QtQuick 2.13 + +AliasToSubcomponentRequiredBase { + i_alias: 42 +} diff --git a/tests/auto/qml/qqmlcomponent/data/shadowing.qml b/tests/auto/qml/qqmlcomponent/data/shadowing.qml new file mode 100644 index 0000000000..4d119d8884 --- /dev/null +++ b/tests/auto/qml/qqmlcomponent/data/shadowing.qml @@ -0,0 +1,5 @@ +import QtQuick 2.14 + +BaseWithRequired { + property int i: 13 +} diff --git a/tests/auto/qml/qqmlcomponent/tst_qqmlcomponent.cpp b/tests/auto/qml/qqmlcomponent/tst_qqmlcomponent.cpp index 1d2fa42b75..2acc62ca28 100644 --- a/tests/auto/qml/qqmlcomponent/tst_qqmlcomponent.cpp +++ b/tests/auto/qml/qqmlcomponent/tst_qqmlcomponent.cpp @@ -121,6 +121,9 @@ private slots: void relativeUrl_data(); void relativeUrl(); void setDataNoEngineNoSegfault(); + void testRequiredProperties_data(); + void testRequiredProperties(); + void testRequiredPropertiesFromQml(); void testSetInitialProperties(); private: @@ -668,35 +671,80 @@ void tst_qqmlcomponent::setDataNoEngineNoSegfault() QVERIFY(!c); } -void tst_qqmlcomponent::testSetInitialProperties() +void tst_qqmlcomponent::testRequiredProperties_data() +{ + QTest::addColumn<QUrl>("testFile"); + QTest::addColumn<bool>("shouldSucceed"); + QTest::addColumn<QString>("errorMsg"); + + QTest::addRow("requiredSetViaChainedAlias") << testFileUrl("requiredSetViaChainedAlias.qml") << true << ""; + QTest::addRow("requiredNotSet") << testFileUrl("requiredNotSet.qml") << false << "Required property i was not initialized"; + QTest::addRow("requiredSetInSameFile") << testFileUrl("requiredSetInSameFile.qml") << true << ""; + QTest::addRow("requiredSetViaAlias1") << testFileUrl("requiredSetViaAliasBeforeSameFile.qml") << true << ""; + QTest::addRow("requiredSetViaAlias2") << testFileUrl("requiredSetViaAliasAfterSameFile.qml") << true << ""; + QTest::addRow("requiredSetViaAlias3") << testFileUrl("requiredSetViaAliasParentFile.qml") << true << ""; + QTest::addRow("shadowing") << testFileUrl("shadowing.qml") << false << "Required property i was not initialized"; + QTest::addRow("setLater") << testFileUrl("requiredSetLater.qml") << true << ""; + QTest::addRow("setViaAliasToSubcomponent") << testFileUrl("setViaAliasToSubcomponent.qml") << true << ""; + QTest::addRow("aliasToSubcomponentNotSet") << testFileUrl("aliasToSubcomponentNotSet.qml") << false << "It can be set via the alias property i_alias"; +} + + +void tst_qqmlcomponent::testRequiredProperties() +{ + QQmlEngine eng; + using QScopedObjPointer = QScopedPointer<QObject>; + QFETCH(QUrl, testFile); + QFETCH(bool, shouldSucceed); + QQmlComponent comp(&eng); + comp.loadUrl(testFile); + QScopedObjPointer obj {comp.create()}; + if (shouldSucceed) + QVERIFY(obj); + else { + QVERIFY(!obj); + QFETCH(QString, errorMsg); + QVERIFY(comp.errorString().contains(errorMsg)); + } +} + +void tst_qqmlcomponent::testRequiredPropertiesFromQml() { QQmlEngine eng; { - // JSON based initialization QQmlComponent comp(&eng); - comp.loadUrl(testFileUrl("allJSONTypes.qml")); - QScopedPointer<QObject> obj { comp.beginCreate(eng.rootContext()) }; + comp.loadUrl(testFileUrl("createdFromQml.qml")); + QScopedPointer<QObject> obj { comp.create() }; QVERIFY(obj); - comp.setInitialProperties(obj.get(), QVariantMap { - {QLatin1String("i"), 42}, - {QLatin1String("b"), true}, - {QLatin1String("d"), 3.1416}, - {QLatin1String("s"), QLatin1String("hello world")}, - {QLatin1String("nothing"), QVariant::fromValue(nullptr)} - }); - comp.completeCreate(); - if (!comp.errors().empty()) - qDebug() << comp.errorString() << comp.errors(); - QVERIFY(comp.errors().empty()); - QCOMPARE(obj->property("i"), 42); - QCOMPARE(obj->property("b"), true); - QCOMPARE(obj->property("d"), 3.1416); - QCOMPARE(obj->property("s"), QLatin1String("hello world")); - QCOMPARE(obj->property("nothing"), QVariant::fromValue(nullptr)); + auto root = qvariant_cast<QQuickItem*>(obj->property("it")); + QVERIFY(root); + QCOMPARE(root->property("i").toInt(), 42); } { - // QVariant + QTest::ignoreMessage(QtMsgType::QtWarningMsg, QRegularExpression(".*requiredNotSet.qml:4:5: Required property i was not initialized")); QQmlComponent comp(&eng); + comp.loadUrl(testFileUrl("createdFromQmlFail.qml")); + QScopedPointer<QObject> obj { comp.create() }; + QVERIFY(obj); + QCOMPARE(qvariant_cast<QQuickItem *>(obj->property("it")), nullptr); + } +} + +struct ComponentWithPublicSetInitial : QQmlComponent +{ + using QQmlComponent::QQmlComponent; + void setInitialProperties(QObject *o, QVariantMap map) + { + QQmlComponent::setInitialProperties(o, map); + } +}; + +void tst_qqmlcomponent::testSetInitialProperties() +{ + QQmlEngine eng; + { + // QVariant + ComponentWithPublicSetInitial comp(&eng); comp.loadUrl(testFileUrl("variantBasedInitialization.qml")); QScopedPointer<QObject> obj { comp.beginCreate(eng.rootContext()) }; QVERIFY(obj); @@ -728,8 +776,6 @@ void tst_qqmlcomponent::testSetInitialProperties() }); #undef ASJSON comp.completeCreate(); - if (!comp.errors().empty()) - qDebug() << comp.errorString() << comp.errors(); QVERIFY(comp.errors().empty()); QCOMPARE(obj->property("i"), 42); QCOMPARE(obj->property("b"), true); @@ -751,13 +797,20 @@ void tst_qqmlcomponent::testSetInitialProperties() } { + // createWithInitialProperties convenience function + QQmlComponent comp(&eng); + comp.loadUrl(testFileUrl("requiredNotSet.qml")); + QScopedPointer<QObject> obj {comp.createWithInitialProperties( QVariantMap { {QLatin1String("i"), QJsonValue{42}} })}; + QVERIFY(obj); + QCOMPARE(obj->property("i"), 42); + } + { // createWithInitialProperties: setting a nonexistent property QQmlComponent comp(&eng); comp.loadUrl(testFileUrl("allJSONTypes.qml")); QScopedPointer<QObject> obj { comp.createWithInitialProperties(QVariantMap { {"notThePropertiesYoureLookingFor", 42} }) }; - qDebug() << comp.errorString(); QVERIFY(obj); QVERIFY(comp.errorString().contains("Could not set property notThePropertiesYoureLookingFor")); } diff --git a/tests/auto/qml/qqmlconsole/data/logging.qml b/tests/auto/qml/qqmlconsole/data/logging.qml index 1f929d311b..f5eaeb442a 100644 --- a/tests/auto/qml/qqmlconsole/data/logging.qml +++ b/tests/auto/qml/qqmlconsole/data/logging.qml @@ -31,6 +31,8 @@ import QtQuick 2.0 QtObject { id:root + required property var customObject + required property var stringListProperty function consoleCount() { console.count("console.count", "Ignore additional argument"); @@ -67,7 +69,7 @@ QtObject { console.log(1, "pong!", new Object); console.log(1, ["ping","pong"], new Object, 2); - console.log(contextStringListProperty); + console.log(stringListProperty); console.log(customObject); console.log([[1,2,3,[2,2,2,2],4],[5,6,7,8]]); diff --git a/tests/auto/qml/qqmlconsole/tst_qqmlconsole.cpp b/tests/auto/qml/qqmlconsole/tst_qqmlconsole.cpp index b157314071..48613d04f1 100644 --- a/tests/auto/qml/qqmlconsole/tst_qqmlconsole.cpp +++ b/tests/auto/qml/qqmlconsole/tst_qqmlconsole.cpp @@ -95,16 +95,16 @@ void tst_qqmlconsole::logging() QTest::ignoreMessage(QtDebugMsg, "QVariant(CustomObject, MY OBJECT)"); QTest::ignoreMessage(QtDebugMsg, "[[1,2,3,[2,2,2,2],4],[5,6,7,8]]"); - QScopedPointer<QQmlContext> loggingContext(new QQmlContext(engine.rootContext())); QStringList stringList; stringList << QStringLiteral("Hello") << QStringLiteral("World"); - loggingContext->setContextProperty("contextStringListProperty", stringList); CustomObject customObject; QVERIFY(QMetaType::registerDebugStreamOperator<CustomObject>()); - loggingContext->setContextProperty("customObject", QVariant::fromValue(customObject)); QQmlComponent component(&engine, testUrl); - QScopedPointer<QObject> object(component.create(loggingContext.data())); + QScopedPointer<QObject> object(component.createWithInitialProperties({ + {"customObject", QVariant::fromValue(customObject)}, + {"stringListProperty", stringList} + })); QVERIFY(object != nullptr); } diff --git a/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp b/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp index 8824dfd019..f4de83eb87 100644 --- a/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp +++ b/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp @@ -6437,6 +6437,8 @@ void tst_qqmlecmascript::topLevelGeneratorFunction() QQmlComponent component(&engine, testFileUrl("generatorFunction.qml")); QScopedPointer<QObject> o {component.create()}; + if (!o) + qDebug() << component.errorString(); QVERIFY(o != nullptr); // check that generator works correctly in QML diff --git a/tests/auto/qml/qqmlengine/data/testEmptyAggregateEmptyComponent.1.qml b/tests/auto/qml/qqmlengine/data/testEmptyAggregateEmptyComponent.1.qml index 812242f146..a37461a173 100644 --- a/tests/auto/qml/qqmlengine/data/testEmptyAggregateEmptyComponent.1.qml +++ b/tests/auto/qml/qqmlengine/data/testEmptyAggregateEmptyComponent.1.qml @@ -2,6 +2,7 @@ import QtQuick 2.0 Item { property bool success: false + required property QtObject componentCache function reportError(s) { console.warn(s) } diff --git a/tests/auto/qml/qqmlengine/data/testEmptyAggregateEmptyComponent.2.qml b/tests/auto/qml/qqmlengine/data/testEmptyAggregateEmptyComponent.2.qml index a171ee6b28..1dc06ee6ae 100644 --- a/tests/auto/qml/qqmlengine/data/testEmptyAggregateEmptyComponent.2.qml +++ b/tests/auto/qml/qqmlengine/data/testEmptyAggregateEmptyComponent.2.qml @@ -2,6 +2,7 @@ import QtQuick 2.0 Item { property bool success: false + required property QtObject componentCache function reportError(s) { console.warn(s) } diff --git a/tests/auto/qml/qqmlengine/data/testEmptyAggregateVMEComponent.1.qml b/tests/auto/qml/qqmlengine/data/testEmptyAggregateVMEComponent.1.qml index de40284452..ea945eebb0 100644 --- a/tests/auto/qml/qqmlengine/data/testEmptyAggregateVMEComponent.1.qml +++ b/tests/auto/qml/qqmlengine/data/testEmptyAggregateVMEComponent.1.qml @@ -2,6 +2,7 @@ import QtQuick 2.0 Item { property bool success: false + required property QtObject componentCache function reportError(s) { console.warn(s) } diff --git a/tests/auto/qml/qqmlengine/data/testEmptyAggregateVMEComponent.2.qml b/tests/auto/qml/qqmlengine/data/testEmptyAggregateVMEComponent.2.qml index 4939087b31..9a4fc53833 100644 --- a/tests/auto/qml/qqmlengine/data/testEmptyAggregateVMEComponent.2.qml +++ b/tests/auto/qml/qqmlengine/data/testEmptyAggregateVMEComponent.2.qml @@ -2,6 +2,7 @@ import QtQuick 2.0 Item { property bool success: false + required property QtObject componentCache function reportError(s) { console.warn(s) } diff --git a/tests/auto/qml/qqmlengine/data/testEmptyComponent.1.qml b/tests/auto/qml/qqmlengine/data/testEmptyComponent.1.qml index 5cee0341fe..155dbdcb91 100644 --- a/tests/auto/qml/qqmlengine/data/testEmptyComponent.1.qml +++ b/tests/auto/qml/qqmlengine/data/testEmptyComponent.1.qml @@ -2,6 +2,7 @@ import QtQuick 2.0 Item { property bool success: false + required property QtObject componentCache function reportError(s) { console.warn(s) } diff --git a/tests/auto/qml/qqmlengine/data/testEmptyComponent.2.qml b/tests/auto/qml/qqmlengine/data/testEmptyComponent.2.qml index 2a13822fab..940d54be90 100644 --- a/tests/auto/qml/qqmlengine/data/testEmptyComponent.2.qml +++ b/tests/auto/qml/qqmlengine/data/testEmptyComponent.2.qml @@ -2,6 +2,7 @@ import QtQuick 2.0 Item { property bool success: false + required property QtObject componentCache function reportError(s) { console.warn(s) } diff --git a/tests/auto/qml/qqmlengine/data/testEmptyExtendEmptyComponent.1.qml b/tests/auto/qml/qqmlengine/data/testEmptyExtendEmptyComponent.1.qml index 2f238175fa..46d20e38bb 100644 --- a/tests/auto/qml/qqmlengine/data/testEmptyExtendEmptyComponent.1.qml +++ b/tests/auto/qml/qqmlengine/data/testEmptyExtendEmptyComponent.1.qml @@ -2,6 +2,7 @@ import QtQuick 2.0 Item { property bool success: false + required property QtObject componentCache function reportError(s) { console.warn(s) } diff --git a/tests/auto/qml/qqmlengine/data/testEmptyExtendEmptyComponent.2.qml b/tests/auto/qml/qqmlengine/data/testEmptyExtendEmptyComponent.2.qml index d36e95fec3..ffdb30f072 100644 --- a/tests/auto/qml/qqmlengine/data/testEmptyExtendEmptyComponent.2.qml +++ b/tests/auto/qml/qqmlengine/data/testEmptyExtendEmptyComponent.2.qml @@ -2,6 +2,7 @@ import QtQuick 2.0 Item { property bool success: false + required property QtObject componentCache function reportError(s) { console.warn(s) } diff --git a/tests/auto/qml/qqmlengine/data/testEmptyExtendVMEComponent.1.qml b/tests/auto/qml/qqmlengine/data/testEmptyExtendVMEComponent.1.qml index 53dd5a17e9..ca669a9708 100644 --- a/tests/auto/qml/qqmlengine/data/testEmptyExtendVMEComponent.1.qml +++ b/tests/auto/qml/qqmlengine/data/testEmptyExtendVMEComponent.1.qml @@ -2,6 +2,7 @@ import QtQuick 2.0 Item { property bool success: false + required property QtObject componentCache function reportError(s) { console.warn(s) } diff --git a/tests/auto/qml/qqmlengine/data/testEmptyExtendVMEComponent.2.qml b/tests/auto/qml/qqmlengine/data/testEmptyExtendVMEComponent.2.qml index e5cd7d60de..a93c3b302c 100644 --- a/tests/auto/qml/qqmlengine/data/testEmptyExtendVMEComponent.2.qml +++ b/tests/auto/qml/qqmlengine/data/testEmptyExtendVMEComponent.2.qml @@ -2,6 +2,7 @@ import QtQuick 2.0 Item { property bool success: false + required property QtObject componentCache function reportError(s) { console.warn(s) } diff --git a/tests/auto/qml/qqmlengine/data/testEmptyPropertyEmptyComponent.1.qml b/tests/auto/qml/qqmlengine/data/testEmptyPropertyEmptyComponent.1.qml index d98aef2932..5930e12df6 100644 --- a/tests/auto/qml/qqmlengine/data/testEmptyPropertyEmptyComponent.1.qml +++ b/tests/auto/qml/qqmlengine/data/testEmptyPropertyEmptyComponent.1.qml @@ -2,6 +2,7 @@ import QtQuick 2.0 Item { property bool success: false + required property QtObject componentCache function reportError(s) { console.warn(s) } diff --git a/tests/auto/qml/qqmlengine/data/testEmptyPropertyEmptyComponent.2.qml b/tests/auto/qml/qqmlengine/data/testEmptyPropertyEmptyComponent.2.qml index 7f438aa995..8f929c20b2 100644 --- a/tests/auto/qml/qqmlengine/data/testEmptyPropertyEmptyComponent.2.qml +++ b/tests/auto/qml/qqmlengine/data/testEmptyPropertyEmptyComponent.2.qml @@ -2,6 +2,7 @@ import QtQuick 2.0 Item { property bool success: false + required property QtObject componentCache function reportError(s) { console.warn(s) } diff --git a/tests/auto/qml/qqmlengine/data/testEmptyPropertyVMEComponent.1.qml b/tests/auto/qml/qqmlengine/data/testEmptyPropertyVMEComponent.1.qml index 83d6226e83..20bde6d0af 100644 --- a/tests/auto/qml/qqmlengine/data/testEmptyPropertyVMEComponent.1.qml +++ b/tests/auto/qml/qqmlengine/data/testEmptyPropertyVMEComponent.1.qml @@ -2,6 +2,7 @@ import QtQuick 2.0 Item { property bool success: false + required property QtObject componentCache function reportError(s) { console.warn(s) } diff --git a/tests/auto/qml/qqmlengine/data/testEmptyPropertyVMEComponent.2.qml b/tests/auto/qml/qqmlengine/data/testEmptyPropertyVMEComponent.2.qml index 98dfb7241b..10ae369459 100644 --- a/tests/auto/qml/qqmlengine/data/testEmptyPropertyVMEComponent.2.qml +++ b/tests/auto/qml/qqmlengine/data/testEmptyPropertyVMEComponent.2.qml @@ -2,6 +2,7 @@ import QtQuick 2.0 Item { property bool success: false + required property QtObject componentCache function reportError(s) { console.warn(s) } diff --git a/tests/auto/qml/qqmlengine/data/testIncubatedComponent.qml b/tests/auto/qml/qqmlengine/data/testIncubatedComponent.qml index 50af9c4f16..422637fe31 100644 --- a/tests/auto/qml/qqmlengine/data/testIncubatedComponent.qml +++ b/tests/auto/qml/qqmlengine/data/testIncubatedComponent.qml @@ -2,6 +2,7 @@ import QtQuick 2.0 Item { property bool success: false + required property QtObject componentCache function reportError(s) { console.warn(s) } diff --git a/tests/auto/qml/qqmlengine/data/testLoaderComponent.qml b/tests/auto/qml/qqmlengine/data/testLoaderComponent.qml index a04ca41c26..67d7ddd1c9 100644 --- a/tests/auto/qml/qqmlengine/data/testLoaderComponent.qml +++ b/tests/auto/qml/qqmlengine/data/testLoaderComponent.qml @@ -2,6 +2,7 @@ import QtQuick 2.0 Item { property bool success: false + required property QtObject componentCache function reportError(s) { console.warn(s) } diff --git a/tests/auto/qml/qqmlengine/data/testReloadComponent.qml b/tests/auto/qml/qqmlengine/data/testReloadComponent.qml index 74442108cd..79d4f29db0 100644 --- a/tests/auto/qml/qqmlengine/data/testReloadComponent.qml +++ b/tests/auto/qml/qqmlengine/data/testReloadComponent.qml @@ -2,6 +2,7 @@ import QtQuick 2.0 Item { property bool success: false + required property QtObject componentCache function reportError(s) { console.warn(s) } diff --git a/tests/auto/qml/qqmlengine/data/testScriptComponent.qml b/tests/auto/qml/qqmlengine/data/testScriptComponent.qml index b33eb48461..4952a08a6c 100644 --- a/tests/auto/qml/qqmlengine/data/testScriptComponent.qml +++ b/tests/auto/qml/qqmlengine/data/testScriptComponent.qml @@ -2,6 +2,7 @@ import QtQuick 2.0 Item { property bool success: false + required property QtObject componentCache function reportError(s) { console.warn(s) } diff --git a/tests/auto/qml/qqmlengine/data/testTopLevelComponent.qml b/tests/auto/qml/qqmlengine/data/testTopLevelComponent.qml index 6cf8ec4203..a6a1f4d4d3 100644 --- a/tests/auto/qml/qqmlengine/data/testTopLevelComponent.qml +++ b/tests/auto/qml/qqmlengine/data/testTopLevelComponent.qml @@ -2,6 +2,7 @@ import QtQuick 2.0 Item { property bool success: false + required property QtObject componentCache function reportError(s) { console.warn(s) } diff --git a/tests/auto/qml/qqmlengine/data/testTransientComponent.1.qml b/tests/auto/qml/qqmlengine/data/testTransientComponent.1.qml index d3e6ffd7cf..c661cb6fe4 100644 --- a/tests/auto/qml/qqmlengine/data/testTransientComponent.1.qml +++ b/tests/auto/qml/qqmlengine/data/testTransientComponent.1.qml @@ -2,6 +2,7 @@ import QtQuick 2.0 Item { property bool success: false + required property QtObject componentCache function reportError(s) { console.warn(s) } diff --git a/tests/auto/qml/qqmlengine/data/testTransientComponent.2.qml b/tests/auto/qml/qqmlengine/data/testTransientComponent.2.qml index acb0113e61..8b6c7eda4d 100644 --- a/tests/auto/qml/qqmlengine/data/testTransientComponent.2.qml +++ b/tests/auto/qml/qqmlengine/data/testTransientComponent.2.qml @@ -2,6 +2,7 @@ import QtQuick 2.0 Item { property bool success: false + required property QtObject componentCache function reportError(s) { console.warn(s) } diff --git a/tests/auto/qml/qqmlengine/data/testVMEAggregateEmptyComponent.1.qml b/tests/auto/qml/qqmlengine/data/testVMEAggregateEmptyComponent.1.qml index a5beede469..8c0596eae4 100644 --- a/tests/auto/qml/qqmlengine/data/testVMEAggregateEmptyComponent.1.qml +++ b/tests/auto/qml/qqmlengine/data/testVMEAggregateEmptyComponent.1.qml @@ -2,6 +2,7 @@ import QtQuick 2.0 Item { property bool success: false + required property QtObject componentCache function reportError(s) { console.warn(s) } diff --git a/tests/auto/qml/qqmlengine/data/testVMEAggregateEmptyComponent.2.qml b/tests/auto/qml/qqmlengine/data/testVMEAggregateEmptyComponent.2.qml index 4c8e52f251..39b604d42f 100644 --- a/tests/auto/qml/qqmlengine/data/testVMEAggregateEmptyComponent.2.qml +++ b/tests/auto/qml/qqmlengine/data/testVMEAggregateEmptyComponent.2.qml @@ -2,6 +2,7 @@ import QtQuick 2.0 Item { property bool success: false + required property QtObject componentCache function reportError(s) { console.warn(s) } diff --git a/tests/auto/qml/qqmlengine/data/testVMEAggregateVMEComponent.1.qml b/tests/auto/qml/qqmlengine/data/testVMEAggregateVMEComponent.1.qml index 983d6e824c..807203b6c7 100644 --- a/tests/auto/qml/qqmlengine/data/testVMEAggregateVMEComponent.1.qml +++ b/tests/auto/qml/qqmlengine/data/testVMEAggregateVMEComponent.1.qml @@ -2,6 +2,7 @@ import QtQuick 2.0 Item { property bool success: false + required property QtObject componentCache function reportError(s) { console.warn(s) } diff --git a/tests/auto/qml/qqmlengine/data/testVMEAggregateVMEComponent.2.qml b/tests/auto/qml/qqmlengine/data/testVMEAggregateVMEComponent.2.qml index fc8e5a0cd4..100b287cfd 100644 --- a/tests/auto/qml/qqmlengine/data/testVMEAggregateVMEComponent.2.qml +++ b/tests/auto/qml/qqmlengine/data/testVMEAggregateVMEComponent.2.qml @@ -2,6 +2,7 @@ import QtQuick 2.0 Item { property bool success: false + required property QtObject componentCache function reportError(s) { console.warn(s) } diff --git a/tests/auto/qml/qqmlengine/data/testVMEComponent.1.qml b/tests/auto/qml/qqmlengine/data/testVMEComponent.1.qml index fcfd05c51f..dddf51b926 100644 --- a/tests/auto/qml/qqmlengine/data/testVMEComponent.1.qml +++ b/tests/auto/qml/qqmlengine/data/testVMEComponent.1.qml @@ -2,6 +2,7 @@ import QtQuick 2.0 Item { property bool success: false + required property QtObject componentCache function reportError(s) { console.warn(s) } diff --git a/tests/auto/qml/qqmlengine/data/testVMEComponent.2.qml b/tests/auto/qml/qqmlengine/data/testVMEComponent.2.qml index f434406eec..fa508f16ac 100644 --- a/tests/auto/qml/qqmlengine/data/testVMEComponent.2.qml +++ b/tests/auto/qml/qqmlengine/data/testVMEComponent.2.qml @@ -2,6 +2,7 @@ import QtQuick 2.0 Item { property bool success: false + required property QtObject componentCache function reportError(s) { console.warn(s) } diff --git a/tests/auto/qml/qqmlengine/data/testVMEExtendEmptyComponent.1.qml b/tests/auto/qml/qqmlengine/data/testVMEExtendEmptyComponent.1.qml index 1dcaec90e6..b36d6ebf14 100644 --- a/tests/auto/qml/qqmlengine/data/testVMEExtendEmptyComponent.1.qml +++ b/tests/auto/qml/qqmlengine/data/testVMEExtendEmptyComponent.1.qml @@ -2,6 +2,7 @@ import QtQuick 2.0 Item { property bool success: false + required property QtObject componentCache function reportError(s) { console.warn(s) } diff --git a/tests/auto/qml/qqmlengine/data/testVMEExtendEmptyComponent.2.qml b/tests/auto/qml/qqmlengine/data/testVMEExtendEmptyComponent.2.qml index fd7d7e454c..fce617046b 100644 --- a/tests/auto/qml/qqmlengine/data/testVMEExtendEmptyComponent.2.qml +++ b/tests/auto/qml/qqmlengine/data/testVMEExtendEmptyComponent.2.qml @@ -2,6 +2,7 @@ import QtQuick 2.0 Item { property bool success: false + required property QtObject componentCache function reportError(s) { console.warn(s) } diff --git a/tests/auto/qml/qqmlengine/data/testVMEExtendVMEComponent.1.qml b/tests/auto/qml/qqmlengine/data/testVMEExtendVMEComponent.1.qml index d2dab32fc9..39629d47df 100644 --- a/tests/auto/qml/qqmlengine/data/testVMEExtendVMEComponent.1.qml +++ b/tests/auto/qml/qqmlengine/data/testVMEExtendVMEComponent.1.qml @@ -2,6 +2,7 @@ import QtQuick 2.0 Item { property bool success: false + required property QtObject componentCache function reportError(s) { console.warn(s) } diff --git a/tests/auto/qml/qqmlengine/data/testVMEExtendVMEComponent.2.qml b/tests/auto/qml/qqmlengine/data/testVMEExtendVMEComponent.2.qml index 813e43896c..a4c947cc17 100644 --- a/tests/auto/qml/qqmlengine/data/testVMEExtendVMEComponent.2.qml +++ b/tests/auto/qml/qqmlengine/data/testVMEExtendVMEComponent.2.qml @@ -2,6 +2,7 @@ import QtQuick 2.0 Item { property bool success: false + required property QtObject componentCache function reportError(s) { console.warn(s) } diff --git a/tests/auto/qml/qqmlengine/data/testVMEPropertyEmptyComponent.1.qml b/tests/auto/qml/qqmlengine/data/testVMEPropertyEmptyComponent.1.qml index c6f0b7928b..a87372cd27 100644 --- a/tests/auto/qml/qqmlengine/data/testVMEPropertyEmptyComponent.1.qml +++ b/tests/auto/qml/qqmlengine/data/testVMEPropertyEmptyComponent.1.qml @@ -2,6 +2,7 @@ import QtQuick 2.0 Item { property bool success: false + required property QtObject componentCache function reportError(s) { console.warn(s) } diff --git a/tests/auto/qml/qqmlengine/data/testVMEPropertyEmptyComponent.2.qml b/tests/auto/qml/qqmlengine/data/testVMEPropertyEmptyComponent.2.qml index 255138520c..c4b16d8ec9 100644 --- a/tests/auto/qml/qqmlengine/data/testVMEPropertyEmptyComponent.2.qml +++ b/tests/auto/qml/qqmlengine/data/testVMEPropertyEmptyComponent.2.qml @@ -2,6 +2,7 @@ import QtQuick 2.0 Item { property bool success: false + required property QtObject componentCache function reportError(s) { console.warn(s) } diff --git a/tests/auto/qml/qqmlengine/data/testVMEPropertyVMEComponent.1.qml b/tests/auto/qml/qqmlengine/data/testVMEPropertyVMEComponent.1.qml index 0ad59b32d3..a18a88884c 100644 --- a/tests/auto/qml/qqmlengine/data/testVMEPropertyVMEComponent.1.qml +++ b/tests/auto/qml/qqmlengine/data/testVMEPropertyVMEComponent.1.qml @@ -2,6 +2,7 @@ import QtQuick 2.0 Item { property bool success: false + required property QtObject componentCache function reportError(s) { console.warn(s) } diff --git a/tests/auto/qml/qqmlengine/data/testVMEPropertyVMEComponent.2.qml b/tests/auto/qml/qqmlengine/data/testVMEPropertyVMEComponent.2.qml index 60f72a92fe..eb042e82f8 100644 --- a/tests/auto/qml/qqmlengine/data/testVMEPropertyVMEComponent.2.qml +++ b/tests/auto/qml/qqmlengine/data/testVMEPropertyVMEComponent.2.qml @@ -2,6 +2,7 @@ import QtQuick 2.0 Item { property bool success: false + required property QtObject componentCache function reportError(s) { console.warn(s) } diff --git a/tests/auto/qml/qqmlengine/data/testVMETransientEmptyComponent.1.qml b/tests/auto/qml/qqmlengine/data/testVMETransientEmptyComponent.1.qml index 6c7f959f49..1f97e587e0 100644 --- a/tests/auto/qml/qqmlengine/data/testVMETransientEmptyComponent.1.qml +++ b/tests/auto/qml/qqmlengine/data/testVMETransientEmptyComponent.1.qml @@ -2,6 +2,7 @@ import QtQuick 2.0 Item { property bool success: false + required property QtObject componentCache function reportError(s) { console.warn(s) } diff --git a/tests/auto/qml/qqmlengine/data/testVMETransientEmptyComponent.2.qml b/tests/auto/qml/qqmlengine/data/testVMETransientEmptyComponent.2.qml index 86060c3998..794686494b 100644 --- a/tests/auto/qml/qqmlengine/data/testVMETransientEmptyComponent.2.qml +++ b/tests/auto/qml/qqmlengine/data/testVMETransientEmptyComponent.2.qml @@ -2,6 +2,7 @@ import QtQuick 2.0 Item { property bool success: false + required property QtObject componentCache function reportError(s) { console.warn(s) } diff --git a/tests/auto/qml/qqmlengine/data/testVMETransientVMEComponent.1.qml b/tests/auto/qml/qqmlengine/data/testVMETransientVMEComponent.1.qml index c50fd70dec..f442500c7f 100644 --- a/tests/auto/qml/qqmlengine/data/testVMETransientVMEComponent.1.qml +++ b/tests/auto/qml/qqmlengine/data/testVMETransientVMEComponent.1.qml @@ -2,6 +2,7 @@ import QtQuick 2.0 Item { property bool success: false + required property QtObject componentCache function reportError(s) { console.warn(s) } diff --git a/tests/auto/qml/qqmlengine/data/testVMETransientVMEComponent.2.qml b/tests/auto/qml/qqmlengine/data/testVMETransientVMEComponent.2.qml index 120d249bc0..d57cd8a739 100644 --- a/tests/auto/qml/qqmlengine/data/testVMETransientVMEComponent.2.qml +++ b/tests/auto/qml/qqmlengine/data/testVMETransientVMEComponent.2.qml @@ -2,6 +2,7 @@ import QtQuick 2.0 Item { property bool success: false + required property QtObject componentCache function reportError(s) { console.warn(s) } diff --git a/tests/auto/qml/qqmlengine/tst_qqmlengine.cpp b/tests/auto/qml/qqmlengine/tst_qqmlengine.cpp index 64f167b47e..2a3b945509 100644 --- a/tests/auto/qml/qqmlengine/tst_qqmlengine.cpp +++ b/tests/auto/qml/qqmlengine/tst_qqmlengine.cpp @@ -424,12 +424,13 @@ void tst_qqmlengine::trimComponentCache() QQmlEngine engine; ComponentCacheFunctions componentCache(engine); - engine.rootContext()->setContextProperty("componentCache", &componentCache); engine.setIncubationController(&componentCache); QQmlComponent component(&engine, testFileUrl(file)); QVERIFY2(component.isReady(), qPrintable(component.errorString())); - QScopedPointer<QObject> object(component.create()); + QScopedPointer<QObject> object(component.createWithInitialProperties({ + {"componentCache", QVariant::fromValue(&componentCache)} + })); QVERIFY(object != nullptr); QCOMPARE(object->property("success").toBool(), true); } @@ -511,6 +512,7 @@ void tst_qqmlengine::failedCompilation() QQmlEngine engine; QQmlComponent component(&engine, testFileUrl(file)); + QTest::ignoreMessage(QtMsgType::QtWarningMsg, "QQmlComponent: Component is not ready"); QVERIFY(!component.isReady()); QScopedPointer<QObject> object(component.create()); QVERIFY(object.isNull()); @@ -601,11 +603,10 @@ void tst_qqmlengine::objectOwnership() { QQmlEngine engine; QQmlComponent c(&engine); - engine.rootContext()->setContextProperty("test", this); QQmlEngine::setObjectOwnership(ptr, QQmlEngine::JavaScriptOwnership); - c.setData("import QtQuick 2.0; Item { property int data: test.createAQObjectForOwnershipTest() ? 0 : 1 }", QUrl()); + c.setData("import QtQuick 2.0; Item { required property QtObject test; property int data: test.createAQObjectForOwnershipTest() ? 0 : 1 }", QUrl()); QVERIFY(c.isReady()); - QObject *o = c.create(); + QObject *o = c.createWithInitialProperties( {{"test", QVariant::fromValue(this)}} ); QVERIFY(o != nullptr); } QTRY_VERIFY(spy.count()); @@ -616,13 +617,13 @@ void tst_qqmlengine::objectOwnership() { QQmlEngine engine; QQmlComponent c(&engine); - engine.rootContext()->setContextProperty("test", ptr); QQmlEngine::setObjectOwnership(ptr, QQmlEngine::JavaScriptOwnership); - c.setData("import QtQuick 2.0; QtObject { property var object: { var i = test; test ? 0 : 1 } }", QUrl()); + c.setData("import QtQuick 2.0; QtObject { required property QtObject test; property var object: { var i = test; test ? 0 : 1 } }", QUrl()); QVERIFY(c.isReady()); - QObject *o = c.create(); + QObject *o = c.createWithInitialProperties({{"test", QVariant::fromValue(ptr)}}); QVERIFY(o != nullptr); - engine.rootContext()->setContextProperty("test", nullptr); + QQmlProperty testProp(o, "test"); + testProp.write(QVariant::fromValue<QObject*>(nullptr)); } QTRY_VERIFY(spy.count()); } @@ -772,6 +773,7 @@ public: }; Q_DECLARE_METATYPE(QList<QQmlAbstractUrlInterceptor::DataType>); + void tst_qqmlengine::urlInterceptor_data() { QTest::addColumn<QUrl>("testFile"); @@ -940,14 +942,15 @@ void tst_qqmlengine::cppSignalAndEval() { ObjectCaller objectCaller; QQmlEngine engine; - engine.rootContext()->setContextProperty(QLatin1String("CallerCpp"), &objectCaller); + qmlRegisterSingletonInstance("Test", 1, 0, "CallerCpp", &objectCaller); QQmlComponent c(&engine); c.setData("import QtQuick 2.9\n" + "import Test 1.0\n" "Item {\n" " property var r: 0\n" " Connections {\n" " target: CallerCpp;\n" - " onDoubleReply: {\n" + " function onDoubleReply() {\n" " eval('var z = 1');\n" " r = a;\n" " }\n" diff --git a/tests/auto/qml/qqmlincubator/data/requiredProperty.qml b/tests/auto/qml/qqmlincubator/data/requiredProperty.qml new file mode 100644 index 0000000000..9e355dce72 --- /dev/null +++ b/tests/auto/qml/qqmlincubator/data/requiredProperty.qml @@ -0,0 +1,5 @@ +import QtQuick 2.12 + +Item { + required property int requiredProperty +} diff --git a/tests/auto/qml/qqmlincubator/tst_qqmlincubator.cpp b/tests/auto/qml/qqmlincubator/tst_qqmlincubator.cpp index 8e25079703..756b3b1d7c 100644 --- a/tests/auto/qml/qqmlincubator/tst_qqmlincubator.cpp +++ b/tests/auto/qml/qqmlincubator/tst_qqmlincubator.cpp @@ -70,6 +70,7 @@ private slots: void selfDelete(); void contextDelete(); void garbageCollection(); + void requiredProperties(); private: QQmlIncubationController controller; @@ -1174,6 +1175,44 @@ void tst_qqmlincubator::garbageCollection() QVERIFY(weakIncubatorRef.isNullOrUndefined()); } +void tst_qqmlincubator::requiredProperties() +{ + { + QQmlComponent component(&engine, testFileUrl("requiredProperty.qml")); + QVERIFY(component.isReady()); + // forceCompletion immediately after creating an asynchronous object completes it + QQmlIncubator incubator; + incubator.setInitialProperties({{"requiredProperty", 42}}); + QVERIFY(incubator.isNull()); + component.create(incubator); + QVERIFY(incubator.isLoading()); + + incubator.forceCompletion(); + + QVERIFY(incubator.isReady()); + QVERIFY(incubator.object() != nullptr); + QCOMPARE(incubator.object()->property("requiredProperty").toInt(), 42); + + delete incubator.object(); + } + { + QQmlComponent component(&engine, testFileUrl("requiredProperty.qml")); + QVERIFY(component.isReady()); + // forceCompletion immediately after creating an asynchronous object completes it + QQmlIncubator incubator; + QVERIFY(incubator.isNull()); + component.create(incubator); + QVERIFY(incubator.isLoading()); + + incubator.forceCompletion(); + + QVERIFY(incubator.isError()); + auto error = incubator.errors().first(); + QVERIFY(error.description().contains(QLatin1String("Required property requiredProperty was not initialized"))); + QVERIFY(incubator.object() == nullptr); + } +} + QTEST_MAIN(tst_qqmlincubator) #include "tst_qqmlincubator.moc" diff --git a/tests/auto/qml/qqmlinstantiator/data/createAndRemove.qml b/tests/auto/qml/qqmlinstantiator/data/createAndRemove.qml index 5dd322b5f5..40e996ee4a 100644 --- a/tests/auto/qml/qqmlinstantiator/data/createAndRemove.qml +++ b/tests/auto/qml/qqmlinstantiator/data/createAndRemove.qml @@ -1,18 +1,19 @@ import QtQml 2.1 import QtQuick 2.1 +import Test 1.0 Rectangle { Instantiator { objectName: "instantiator1" - model: model1 + model: Model1 delegate: QtObject { property string datum: model.text } } Component.onCompleted: { - model1.add("Delta"); - model1.add("Gamma"); - model1.add("Beta"); - model1.add("Alpha"); + Model1.add("Delta"); + Model1.add("Gamma"); + Model1.add("Beta"); + Model1.add("Alpha"); } } diff --git a/tests/auto/qml/qqmlinstantiator/tst_qqmlinstantiator.cpp b/tests/auto/qml/qqmlinstantiator/tst_qqmlinstantiator.cpp index 9c5e09c77c..84e08c471a 100644 --- a/tests/auto/qml/qqmlinstantiator/tst_qqmlinstantiator.cpp +++ b/tests/auto/qml/qqmlinstantiator/tst_qqmlinstantiator.cpp @@ -190,9 +190,9 @@ void tst_qqmlinstantiator::intModelChange() void tst_qqmlinstantiator::createAndRemove() { QQmlEngine engine; + QScopedPointer<StringModel> model {new StringModel("model1")}; + qmlRegisterSingletonInstance("Test", 1, 0, "Model1", model.get()); QQmlComponent component(&engine, testFileUrl("createAndRemove.qml")); - StringModel *model = new StringModel("model1"); - engine.rootContext()->setContextProperty("model1", model); QObject *rootObject = component.create(); QVERIFY(rootObject != nullptr); diff --git a/tests/auto/qml/qqmllanguage/data/foreignExtended.qml b/tests/auto/qml/qqmllanguage/data/foreignExtended.qml new file mode 100644 index 0000000000..182d60fd02 --- /dev/null +++ b/tests/auto/qml/qqmllanguage/data/foreignExtended.qml @@ -0,0 +1,20 @@ +import QtQml 2.12 +import Test 1.0 + +QtObject { + property Foreign foreign: Foreign { + objectName: "foreign" + } + property Extended extended: Extended {} + property ForeignExtended foreignExtended: ForeignExtended { + objectName: "foreignExtended" + } + + property int extendedBase: extended.base + + property int extendedExtension: extended.extension + property int foreignExtendedExtension: foreignExtended.extension + + property string foreignObjectName: foreign.objectName + property string foreignExtendedObjectName: foreignExtended.objectName +} diff --git a/tests/auto/qml/qqmllanguage/data/requiredProperties.1.qml b/tests/auto/qml/qqmllanguage/data/requiredProperties.1.qml new file mode 100644 index 0000000000..dac43c6d88 --- /dev/null +++ b/tests/auto/qml/qqmllanguage/data/requiredProperties.1.qml @@ -0,0 +1,8 @@ +import QtQuick 2.13 +Item { + property var required: 32 // required is still allowed as an identifier for properties + function f(required) { // for javascript + required = required + required; + console.log(required); + } +} diff --git a/tests/auto/qml/qqmllanguage/data/requiredProperties.2.qml b/tests/auto/qml/qqmllanguage/data/requiredProperties.2.qml new file mode 100644 index 0000000000..4c12c7b602 --- /dev/null +++ b/tests/auto/qml/qqmllanguage/data/requiredProperties.2.qml @@ -0,0 +1,4 @@ +import QtQuick 2.13 +Item { + required property int test: 42 // cannot specify value for required property +} diff --git a/tests/auto/qml/qqmllanguage/data/requiredProperties.3.qml b/tests/auto/qml/qqmllanguage/data/requiredProperties.3.qml new file mode 100644 index 0000000000..534322215f --- /dev/null +++ b/tests/auto/qml/qqmllanguage/data/requiredProperties.3.qml @@ -0,0 +1,4 @@ +import QtQuick 2.13 +Item { + default required property int test // cannot have required default property +} diff --git a/tests/auto/qml/qqmllanguage/testtypes.cpp b/tests/auto/qml/qqmllanguage/testtypes.cpp index 6956533196..462745eb93 100644 --- a/tests/auto/qml/qqmllanguage/testtypes.cpp +++ b/tests/auto/qml/qqmllanguage/testtypes.cpp @@ -57,7 +57,7 @@ void registerTypes() qmlRegisterType<MyNamespace::MySecondNamespacedType>("Test",1,0,"MySecondNamespacedType"); qmlRegisterUncreatableMetaObject(MyNamespace::staticMetaObject, "Test", 1, 0, "MyNamespace", "Access to enums & flags only"); qmlRegisterType<MyParserStatus>("Test",1,0,"MyParserStatus"); - qmlRegisterType<MyGroupedObject>(); + qmlRegisterAnonymousType<MyGroupedObject>("Test", 1); qmlRegisterType<MyRevisionedClass>("Test",1,0,"MyRevisionedClass"); qmlRegisterType<MyRevisionedClass,1>("Test",1,1,"MyRevisionedClass"); qmlRegisterType<MyRevisionedIllegalOverload>("Test",1,0,"MyRevisionedIllegalOverload"); @@ -118,6 +118,8 @@ void registerTypes() qmlRegisterType<LazyDeferredSubObject>("Test", 1, 0, "LazyDeferredSubObject"); qmlRegisterType<DeferredProperties>("Test", 1, 0, "DeferredProperties"); + + qmlRegisterTypesAndRevisions<Extended, Foreign, ForeignExtended>("Test", 1); } QVariant myCustomVariantTypeConverter(const QString &data) diff --git a/tests/auto/qml/qqmllanguage/testtypes.h b/tests/auto/qml/qqmllanguage/testtypes.h index 1aab24841a..bfbd3e66f5 100644 --- a/tests/auto/qml/qqmllanguage/testtypes.h +++ b/tests/auto/qml/qqmllanguage/testtypes.h @@ -1420,6 +1420,40 @@ public: enum class OtherScopedEnum : int { ScopedVal1, ScopedVal2, ScopedVal3 }; }; +class Extension : public QObject +{ + Q_OBJECT + Q_PROPERTY(int extension READ extension CONSTANT) +public: + Extension(QObject *parent = nullptr) : QObject(parent) {} + int extension() const { return 42; } +}; + +class Extended : public QObject +{ + Q_OBJECT + QML_EXTENDED(Extension) + QML_NAMED_ELEMENT(Extended) + Q_PROPERTY(int base READ base CONSTANT) + +public: + int base() const { return 43; } +}; + +class Foreign +{ + Q_GADGET + QML_FOREIGN(QObject) + QML_NAMED_ELEMENT(Foreign) +}; + +class ForeignExtended +{ + Q_GADGET + QML_FOREIGN(QObject) + QML_NAMED_ELEMENT(ForeignExtended) + QML_EXTENDED(Extension) +}; void registerTypes(); diff --git a/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp b/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp index ecf87c51d6..e2032c3b86 100644 --- a/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp +++ b/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp @@ -132,6 +132,7 @@ private slots: void autoComponentCreation(); void autoComponentCreationInGroupProperty(); void propertyValueSource(); + void requiredProperty(); void attachedProperties(); void dynamicObjects(); void customVariantTypes(); @@ -303,6 +304,8 @@ private slots: void typeWrapperToVariant(); + void extendedForeignTypes(); + private: QQmlEngine engine; QStringList defaultImportPathList; @@ -1633,6 +1636,25 @@ void tst_qqmllanguage::propertyValueSource() } } +void tst_qqmllanguage::requiredProperty() +{ + QQmlEngine engine; + { + QQmlComponent component(&engine, testFileUrl("requiredProperties.1.qml")); + VERIFY_ERRORS(0); + QScopedPointer<QObject> object(component.create()); + QVERIFY(object); + } + { + QQmlComponent component(&engine, testFileUrl("requiredProperties.2.qml")); + QVERIFY(!component.errors().empty()); + } + { + QQmlComponent component(&engine, testFileUrl("requiredProperties.3.qml")); + QVERIFY(!component.errors().empty()); + } +} + void tst_qqmllanguage::attachedProperties() { QQmlComponent component(&engine, testFileUrl("attachedProperties.qml")); @@ -5237,6 +5259,21 @@ void tst_qqmllanguage::typeWrapperToVariant() QVERIFY(target); } +void tst_qqmllanguage::extendedForeignTypes() +{ + QQmlEngine engine; + QQmlComponent component(&engine, testFileUrl("foreignExtended.qml")); + VERIFY_ERRORS(0); + QScopedPointer<QObject> o(component.create()); + QVERIFY(!o.isNull()); + + QCOMPARE(o->property("extendedBase").toInt(), 43); + QCOMPARE(o->property("extendedExtension").toInt(), 42); + QCOMPARE(o->property("foreignExtendedExtension").toInt(), 42); + QCOMPARE(o->property("foreignObjectName").toString(), QLatin1String("foreign")); + QCOMPARE(o->property("foreignExtendedObjectName").toString(), QLatin1String("foreignExtended")); +} + QTEST_MAIN(tst_qqmllanguage) #include "tst_qqmllanguage.moc" diff --git a/tests/auto/qml/qqmllistreference/tst_qqmllistreference.cpp b/tests/auto/qml/qqmllistreference/tst_qqmllistreference.cpp index 199f7bc7e4..8efaedf5b5 100644 --- a/tests/auto/qml/qqmllistreference/tst_qqmllistreference.cpp +++ b/tests/auto/qml/qqmllistreference/tst_qqmllistreference.cpp @@ -87,7 +87,7 @@ public: void tst_qqmllistreference::initTestCase() { QQmlDataTest::initTestCase(); - qmlRegisterType<TestType>(); + qmlRegisterAnonymousType<TestType>("Test", 1); } void tst_qqmllistreference::qmllistreference() diff --git a/tests/auto/qml/qqmlmoduleplugin/moduleWithQmlSingleton/MySingleton.qml b/tests/auto/qml/qqmlmoduleplugin/moduleWithQmlSingleton/MySingleton.qml index 9789be8191..258667be18 100644 --- a/tests/auto/qml/qqmlmoduleplugin/moduleWithQmlSingleton/MySingleton.qml +++ b/tests/auto/qml/qqmlmoduleplugin/moduleWithQmlSingleton/MySingleton.qml @@ -1,5 +1,6 @@ pragma Singleton import QtQuick 2.0 +import Test 1.0 QtObject { property Loader _loader: Loader { @@ -7,10 +8,10 @@ QtObject { } Component.onCompleted: { - if (tracker.objectName === "first") - tracker.objectName = "second" + if (Tracker.objectName === "first") + Tracker.objectName = "second" else - tracker.objectName = "first" + Tracker.objectName = "first" //console.log("created singleton", this) } } diff --git a/tests/auto/qml/qqmlmoduleplugin/protectedModule/plugin.cpp b/tests/auto/qml/qqmlmoduleplugin/protectedModule/plugin.cpp index ae8c231aab..bb5bb00adb 100644 --- a/tests/auto/qml/qqmlmoduleplugin/protectedModule/plugin.cpp +++ b/tests/auto/qml/qqmlmoduleplugin/protectedModule/plugin.cpp @@ -47,9 +47,9 @@ public: void registerTypes(const char *uri) { - // Because the module is protected, this plugin should never be loaded + // The module is protected. The plugin can still be loaded, but it cannot register + // any types. Q_UNUSED(uri); - Q_ASSERT(0); } }; diff --git a/tests/auto/qml/qqmlmoduleplugin/tst_qqmlmoduleplugin.cpp b/tests/auto/qml/qqmlmoduleplugin/tst_qqmlmoduleplugin.cpp index f89cc9f24a..75885bc84a 100644 --- a/tests/auto/qml/qqmlmoduleplugin/tst_qqmlmoduleplugin.cpp +++ b/tests/auto/qml/qqmlmoduleplugin/tst_qqmlmoduleplugin.cpp @@ -609,7 +609,7 @@ void tst_qqmlmoduleplugin::importStrictModule_data() << "import org.qtproject.NonstrictModule 1.0\n" "MyPluginType {}" << "Module 'org.qtproject.NonstrictModule' does not contain a module identifier directive - it cannot be protected from external registrations." - << ":1:1: plugin cannot be loaded for module \"org.qtproject.NonstrictModule\": Cannot install element 'MyPluginType' into protected namespace 'org.qtproject.StrictModule'"; + << ":1:1: plugin cannot be loaded for module \"org.qtproject.NonstrictModule\": Cannot install element 'MyPluginType' into protected module 'org.qtproject.StrictModule' version '1'"; QTest::newRow("non-strict preemption") << "import org.qtproject.PreemptiveModule 1.0\n" @@ -777,7 +777,7 @@ void tst_qqmlmoduleplugin::multiSingleton() { QQmlEngine engine; QObject obj; - engine.rootContext()->setContextProperty("tracker", &obj); + qmlRegisterSingletonInstance("Test", 1, 0, "Tracker", &obj); engine.addImportPath(m_importsDirectory); QQmlComponent component(&engine, testFileUrl("multiSingleton.qml")); QObject *object = component.create(); diff --git a/tests/auto/qml/qqmlnotifier/data/connectnotify.qml b/tests/auto/qml/qqmlnotifier/data/connectnotify.qml index 35226ee5ab..34e70e6afe 100644 --- a/tests/auto/qml/qqmlnotifier/data/connectnotify.qml +++ b/tests/auto/qml/qqmlnotifier/data/connectnotify.qml @@ -3,6 +3,7 @@ import Test 1.0 Item { id: root + required property ExportedClass exportedObject ExportedClass { id: exportedClass objectName: "exportedClass" @@ -22,7 +23,7 @@ Item { } property int foo: exportedClass.qmlObjectProp - property int baz: _exportedObject.cppObjectProp + property int baz: exportedObject.cppObjectProp // v4 bindings that could share a subscription. They don't, though, and the code // relies on that diff --git a/tests/auto/qml/qqmlnotifier/tst_qqmlnotifier.cpp b/tests/auto/qml/qqmlnotifier/tst_qqmlnotifier.cpp index de762d66c5..836b94ad45 100644 --- a/tests/auto/qml/qqmlnotifier/tst_qqmlnotifier.cpp +++ b/tests/auto/qml/qqmlnotifier/tst_qqmlnotifier.cpp @@ -185,8 +185,7 @@ void tst_qqmlnotifier::createObjects() QQmlComponent component(&engine, testFileUrl("connectnotify.qml")); exportedObject = new ExportedClass(); exportedObject->setObjectName("exportedObject"); - engine.rootContext()->setContextProperty("_exportedObject", exportedObject); - root = component.create(); + root = component.createWithInitialProperties({{"exportedObject", QVariant::fromValue(exportedObject)}}); QVERIFY(root != nullptr); exportedClass = qobject_cast<ExportedClass *>( @@ -324,12 +323,12 @@ void tst_qqmlnotifier::lotsOfBindings() TestObject o; QQmlEngine *e = new QQmlEngine; - e->rootContext()->setContextProperty(QStringLiteral("test"), &o); + qmlRegisterSingletonInstance("Test", 1, 0, "Test", &o); QList<QQmlComponent *> components; for (int i = 0; i < 20000; ++i) { QQmlComponent *component = new QQmlComponent(e); - component->setData("import QtQuick 2.0; Item { width: test.a; }", QUrl()); + component->setData("import QtQuick 2.0; import Test 1.0; Item {width: Test.a; }", QUrl()); component->create(e->rootContext()); components.append(component); } diff --git a/tests/auto/qml/qqmlproperty/data/aliasToBinding.qml b/tests/auto/qml/qqmlproperty/data/aliasToBinding.qml new file mode 100644 index 0000000000..54f9e3f944 --- /dev/null +++ b/tests/auto/qml/qqmlproperty/data/aliasToBinding.qml @@ -0,0 +1,23 @@ +import QtQuick 2.7 + +Item { + id: _window + property bool userFontStrikeout: true + + Component.onCompleted: { + _box.font.strikeout = Qt.binding(function() { return _window.userFontStrikeout; }); + } + + Rectangle { + id: _box + width: 100 + height: 100 + property alias font: _text.font + + Text { + id: _text + anchors.fill: parent + text: "Text" + } + } +} diff --git a/tests/auto/qml/qqmlproperty/data/assignEmptyVariantMap.qml b/tests/auto/qml/qqmlproperty/data/assignEmptyVariantMap.qml index a9e51c1255..440f07ac87 100644 --- a/tests/auto/qml/qqmlproperty/data/assignEmptyVariantMap.qml +++ b/tests/auto/qml/qqmlproperty/data/assignEmptyVariantMap.qml @@ -1,5 +1,6 @@ import QtQuick 2.0 Item { + required property QtObject o Component.onCompleted: { o.variantMap = {}; } } diff --git a/tests/auto/qml/qqmlproperty/tst_qqmlproperty.cpp b/tests/auto/qml/qqmlproperty/tst_qqmlproperty.cpp index bc407e97a2..1a5927fa74 100644 --- a/tests/auto/qml/qqmlproperty/tst_qqmlproperty.cpp +++ b/tests/auto/qml/qqmlproperty/tst_qqmlproperty.cpp @@ -153,6 +153,8 @@ private slots: void floatToStringPrecision(); void copy(); + + void bindingToAlias(); private: QQmlEngine engine; }; @@ -1992,11 +1994,9 @@ void tst_qqmlproperty::assignEmptyVariantMap() QCOMPARE(o.variantMap().count(), 1); QCOMPARE(o.variantMap().isEmpty(), false); - QQmlContext context(&engine); - context.setContextProperty("o", &o); QQmlComponent component(&engine, testFileUrl("assignEmptyVariantMap.qml")); - QObject *obj = component.create(&context); + QObject *obj = component.createWithInitialProperties({{"o", QVariant::fromValue(&o)}}); QVERIFY(obj); QCOMPARE(o.variantMap().count(), 0); @@ -2130,6 +2130,15 @@ void tst_qqmlproperty::initTestCase() qmlRegisterType<MyContainer>("Test",1,0,"MyContainer"); } +// QTBUG-60908 +void tst_qqmlproperty::bindingToAlias() +{ + QQmlEngine engine; + QQmlComponent component(&engine, testFileUrl("aliasToBinding.qml")); + QScopedPointer<QObject> o(component.create()); + QVERIFY(!o.isNull()); +} + QTEST_MAIN(tst_qqmlproperty) #include "tst_qqmlproperty.moc" diff --git a/tests/auto/qml/qqmlqt/data/formatting.qml b/tests/auto/qml/qqmlqt/data/formatting.qml index 7a462c8eeb..f2d1e1b5c8 100644 --- a/tests/auto/qml/qqmlqt/data/formatting.qml +++ b/tests/auto/qml/qqmlqt/data/formatting.qml @@ -41,4 +41,9 @@ QtObject { property string err_dateTime1: Qt.formatDateTime() property string err_dateTime2: Qt.formatDateTime(new Date, new Object) + + property var qdate + property var qtime + property var qdatetime + property var qvariant } diff --git a/tests/auto/qml/qqmlqt/data/timeRoundtrip.qml b/tests/auto/qml/qqmlqt/data/timeRoundtrip.qml index 9d73640c87..65732442af 100644 --- a/tests/auto/qml/qqmlqt/data/timeRoundtrip.qml +++ b/tests/auto/qml/qqmlqt/data/timeRoundtrip.qml @@ -1,6 +1,8 @@ import QtQuick 2.0 +import Test 1.0 QtObject { + required property TimeProvider tp Component.onCompleted: { var t = tp.time; tp.time = t; diff --git a/tests/auto/qml/qqmlqt/tst_qqmlqt.cpp b/tests/auto/qml/qqmlqt/tst_qqmlqt.cpp index 2d8115e867..15ef31464b 100644 --- a/tests/auto/qml/qqmlqt/tst_qqmlqt.cpp +++ b/tests/auto/qml/qqmlqt/tst_qqmlqt.cpp @@ -777,10 +777,6 @@ void tst_qqmlqt::dateTimeFormatting() QQmlEngine eng; - eng.rootContext()->setContextProperty("qdate", date); - eng.rootContext()->setContextProperty("qtime", time); - eng.rootContext()->setContextProperty("qdatetime", dateTime); - QQmlComponent component(&eng, testFileUrl("formatting.qml")); QStringList warnings; @@ -794,7 +790,11 @@ void tst_qqmlqt::dateTimeFormatting() foreach (const QString &warning, warnings) QTest::ignoreMessage(QtWarningMsg, qPrintable(warning)); - QObject *object = component.create(); + QObject *object = component.createWithInitialProperties({ + {"qdate", date}, + {"qtime", time}, + {"qdatetime", dateTime} + }); QVERIFY2(component.errorString().isEmpty(), qPrintable(component.errorString())); QVERIFY(object != nullptr); @@ -853,7 +853,6 @@ void tst_qqmlqt::dateTimeFormattingVariants() QFETCH(QStringList, expectedResults); QQmlEngine eng; - eng.rootContext()->setContextProperty("qvariant", variant); QQmlComponent component(&eng, testFileUrl("formatting.qml")); QStringList warnings; @@ -867,7 +866,7 @@ void tst_qqmlqt::dateTimeFormattingVariants() foreach (const QString &warning, warnings) QTest::ignoreMessage(QtWarningMsg, qPrintable(warning)); - QObject *object = component.create(); + QObject *object = component.createWithInitialProperties({{"qvariant", variant}}); QVERIFY2(component.errorString().isEmpty(), qPrintable(component.errorString())); QVERIFY(object != nullptr); @@ -1174,6 +1173,7 @@ void tst_qqmlqt::qtObjectContents() class TimeProvider: public QObject { Q_OBJECT + QML_NAMED_ELEMENT(TimeProvider) Q_PROPERTY(QTime time READ time WRITE setTime NOTIFY timeChanged) public: @@ -1254,13 +1254,14 @@ void tst_qqmlqt::timeRoundtrip() TimeZoneSwitch tzs(QTest::currentDataTag()); QFETCH(QTime, time); + qmlRegisterTypesAndRevisions<TimeProvider>("Test", 1); TimeProvider tp(time); QQmlEngine eng; - eng.rootContext()->setContextProperty(QLatin1String("tp"), &tp); + //qmlRegisterSingletonInstance("Test", 1, 0, "TimeProvider", &tp); QQmlComponent component(&eng, testFileUrl("timeRoundtrip.qml")); - QObject *obj = component.create(); + QObject *obj = component.createWithInitialProperties({{"tp", QVariant::fromValue(&tp)}}); QVERIFY(obj != nullptr); // QML reads m_getTime and saves the result as m_putTime; this should come out the same, without diff --git a/tests/auto/qml/qqmlvaluetypeproviders/data/userType.qml b/tests/auto/qml/qqmlvaluetypeproviders/data/userType.qml index d2f748c4c4..2aa03ed39f 100644 --- a/tests/auto/qml/qqmlvaluetypeproviders/data/userType.qml +++ b/tests/auto/qml/qqmlvaluetypeproviders/data/userType.qml @@ -2,6 +2,7 @@ import QtQuick 2.0 import Test 1.0 Item { + required property TestValueExporter testValueExporter property bool success: false // Test user value type stored as both var and variant diff --git a/tests/auto/qml/qqmlvaluetypeproviders/tst_qqmlvaluetypeproviders.cpp b/tests/auto/qml/qqmlvaluetypeproviders/tst_qqmlvaluetypeproviders.cpp index 22074602b7..b44889798c 100644 --- a/tests/auto/qml/qqmlvaluetypeproviders/tst_qqmlvaluetypeproviders.cpp +++ b/tests/auto/qml/qqmlvaluetypeproviders/tst_qqmlvaluetypeproviders.cpp @@ -256,6 +256,7 @@ class TestValueExporter : public QObject { Q_OBJECT Q_PROPERTY(TestValue testValue READ testValue WRITE setTestValue) + QML_NAMED_ELEMENT(TestValueExporter) public: TestValue testValue() const { return m_testValue; } void setTestValue(const TestValue &v) { m_testValue = v; } @@ -275,15 +276,14 @@ void tst_qqmlvaluetypeproviders::userType() qRegisterMetaType<TestValue>(); QMetaType::registerComparators<TestValue>(); - qmlRegisterType<TestValueExporter>("Test", 1, 0, "TestValueExporter"); + qmlRegisterTypesAndRevisions<TestValueExporter>("Test", 1); TestValueExporter exporter; QQmlEngine e; - e.rootContext()->setContextProperty("testValueExporter", &exporter); QQmlComponent component(&e, testFileUrl("userType.qml")); - QScopedPointer<QObject> obj(component.create()); + QScopedPointer<QObject> obj(component.createWithInitialProperties({{"testValueExporter", QVariant::fromValue(&exporter)}})); QVERIFY(obj != nullptr); QCOMPARE(obj->property("success").toBool(), true); } diff --git a/tests/auto/quick/pointerhandlers/qquickdraghandler/tst_qquickdraghandler.cpp b/tests/auto/quick/pointerhandlers/qquickdraghandler/tst_qquickdraghandler.cpp index 66314f88a2..65c5ac9ef4 100644 --- a/tests/auto/quick/pointerhandlers/qquickdraghandler/tst_qquickdraghandler.cpp +++ b/tests/auto/quick/pointerhandlers/qquickdraghandler/tst_qquickdraghandler.cpp @@ -53,9 +53,12 @@ private slots: void initTestCase(); void defaultPropertyValues(); + void touchDrag_data(); void touchDrag(); void mouseDrag_data(); void mouseDrag(); + void mouseDragThreshold_data(); + void mouseDragThreshold(); void dragFromMargin(); void snapMode_data(); void snapMode(); @@ -131,9 +134,18 @@ void tst_DragHandler::defaultPropertyValues() QCOMPARE(dragHandler->centroid().sceneGrabPosition(), QPointF()); } +void tst_DragHandler::touchDrag_data() +{ + QTest::addColumn<int>("dragThreshold"); + QTest::newRow("threshold zero") << 0; + QTest::newRow("threshold one") << 1; + QTest::newRow("threshold 20") << 20; + QTest::newRow("threshold default") << -1; +} + void tst_DragHandler::touchDrag() { - const int dragThreshold = QGuiApplication::styleHints()->startDragDistance(); + QFETCH(int, dragThreshold); QScopedPointer<QQuickView> windowPtr; createView(windowPtr, "draggables.qml"); QQuickView * window = windowPtr.data(); @@ -142,6 +154,12 @@ void tst_DragHandler::touchDrag() QVERIFY(ball); QQuickDragHandler *dragHandler = ball->findChild<QQuickDragHandler*>(); QVERIFY(dragHandler); + if (dragThreshold < 0) { + dragThreshold = QGuiApplication::styleHints()->startDragDistance(); + QCOMPARE(dragHandler->dragThreshold(), dragThreshold); + } else { + dragHandler->setDragThreshold(dragThreshold); + } QSignalSpy translationChangedSpy(dragHandler, SIGNAL(translationChanged())); QSignalSpy centroidChangedSpy(dragHandler, SIGNAL(centroidChanged())); @@ -161,7 +179,9 @@ void tst_DragHandler::touchDrag() p1 += QPoint(dragThreshold, 0); QTest::touchEvent(window, touchDevice).move(1, p1, window); QQuickTouchUtils::flush(window); - QTRY_VERIFY(dragHandler->centroid().velocity().x() > 0); + qCDebug(lcPointerTests) << "velocity after drag" << dragHandler->centroid().velocity(); + if (dragThreshold > 0) + QTRY_VERIFY(!qFuzzyIsNull(dragHandler->centroid().velocity().x())); QCOMPARE(centroidChangedSpy.count(), 2); QVERIFY(!dragHandler->active()); p1 += QPoint(1, 0); @@ -282,6 +302,81 @@ void tst_DragHandler::mouseDrag() QCOMPARE(centroidChangedSpy.count(), shouldDrag ? 5 : 0); } +void tst_DragHandler::mouseDragThreshold_data() +{ + QTest::addColumn<int>("dragThreshold"); + QTest::newRow("threshold zero") << 0; + QTest::newRow("threshold one") << 1; + QTest::newRow("threshold 20") << 20; + QTest::newRow("threshold default") << -1; +} + +void tst_DragHandler::mouseDragThreshold() +{ + QFETCH(int, dragThreshold); + QScopedPointer<QQuickView> windowPtr; + createView(windowPtr, "draggables.qml"); + QQuickView * window = windowPtr.data(); + + QQuickItem *ball = window->rootObject()->childItems().first(); + QVERIFY(ball); + QQuickDragHandler *dragHandler = ball->findChild<QQuickDragHandler*>(); + QVERIFY(dragHandler); + if (dragThreshold < 0) { + dragThreshold = QGuiApplication::styleHints()->startDragDistance(); + QCOMPARE(dragHandler->dragThreshold(), dragThreshold); + } else { + dragHandler->setDragThreshold(dragThreshold); + } + + QSignalSpy translationChangedSpy(dragHandler, SIGNAL(translationChanged())); + QSignalSpy centroidChangedSpy(dragHandler, SIGNAL(centroidChanged())); + + QPointF ballCenter = ball->clipRect().center(); + QPointF scenePressPos = ball->mapToScene(ballCenter); + QPoint p1 = scenePressPos.toPoint(); + QTest::mousePress(window, Qt::LeftButton, Qt::NoModifier, p1); + QVERIFY(!dragHandler->active()); + QCOMPARE(dragHandler->centroid().position(), ballCenter); + QCOMPARE(dragHandler->centroid().pressPosition(), ballCenter); + QCOMPARE(dragHandler->centroid().scenePosition(), scenePressPos); + QCOMPARE(dragHandler->centroid().scenePressPosition(), scenePressPos); + QCOMPARE(dragHandler->centroid().velocity(), QVector2D()); + QCOMPARE(centroidChangedSpy.count(), 1); + p1 += QPoint(dragThreshold, 0); + QTest::mouseMove(window, p1); + if (dragThreshold > 0) + QTRY_VERIFY(dragHandler->centroid().velocity().x() > 0); + QCOMPARE(centroidChangedSpy.count(), 2); + QVERIFY(!dragHandler->active()); + p1 += QPoint(1, 0); + QTest::mouseMove(window, p1); + QTRY_VERIFY(dragHandler->active()); + QCOMPARE(translationChangedSpy.count(), 0); + QCOMPARE(centroidChangedSpy.count(), 3); + QCOMPARE(dragHandler->translation().x(), 0.0); + QPointF sceneGrabPos = p1; + QCOMPARE(dragHandler->centroid().sceneGrabPosition(), sceneGrabPos); + p1 += QPoint(19, 0); + QTest::mouseMove(window, p1); + QTRY_VERIFY(dragHandler->active()); + QCOMPARE(dragHandler->centroid().position(), ballCenter); + QCOMPARE(dragHandler->centroid().pressPosition(), ballCenter); + QCOMPARE(dragHandler->centroid().scenePosition(), ball->mapToScene(ballCenter)); + QCOMPARE(dragHandler->centroid().scenePressPosition(), scenePressPos); + QCOMPARE(dragHandler->centroid().sceneGrabPosition(), sceneGrabPos); + QCOMPARE(dragHandler->translation().x(), dragThreshold + 20.0); + QCOMPARE(dragHandler->translation().y(), 0.0); + QVERIFY(dragHandler->centroid().velocity().x() > 0); + QCOMPARE(centroidChangedSpy.count(), 4); + QTest::mouseRelease(window, Qt::LeftButton, Qt::NoModifier, p1); + QTRY_VERIFY(!dragHandler->active()); + QCOMPARE(dragHandler->centroid().pressedButtons(), Qt::NoButton); + QCOMPARE(ball->mapToScene(ballCenter).toPoint(), p1); + QCOMPARE(translationChangedSpy.count(), 1); + QCOMPARE(centroidChangedSpy.count(), 5); +} + void tst_DragHandler::dragFromMargin() // QTBUG-74966 { const int dragThreshold = QGuiApplication::styleHints()->startDragDistance(); diff --git a/tests/auto/quick/qquickboundaryrule/data/dragHandler.qml b/tests/auto/quick/qquickboundaryrule/data/dragHandler.qml index c66fd76ff1..769a5b2c7d 100644 --- a/tests/auto/quick/qquickboundaryrule/data/dragHandler.qml +++ b/tests/auto/quick/qquickboundaryrule/data/dragHandler.qml @@ -14,6 +14,7 @@ Rectangle { } BoundaryRule on x { + objectName: "boundaryRule" id: xbr minimum: -50 maximum: 100 diff --git a/tests/auto/quick/qquickboundaryrule/qquickboundaryrule.pro b/tests/auto/quick/qquickboundaryrule/qquickboundaryrule.pro index ef43f4526a..c41f798d33 100644 --- a/tests/auto/quick/qquickboundaryrule/qquickboundaryrule.pro +++ b/tests/auto/quick/qquickboundaryrule/qquickboundaryrule.pro @@ -9,4 +9,4 @@ include (../shared/util.pri) TESTDATA = data/* -QT += core-private gui-private qml-private quick-private testlib +QT += quick-private qml testlib diff --git a/tests/auto/quick/qquickboundaryrule/tst_qquickboundaryrule.cpp b/tests/auto/quick/qquickboundaryrule/tst_qquickboundaryrule.cpp index 44f1c9a2f9..75639dba49 100644 --- a/tests/auto/quick/qquickboundaryrule/tst_qquickboundaryrule.cpp +++ b/tests/auto/quick/qquickboundaryrule/tst_qquickboundaryrule.cpp @@ -30,7 +30,6 @@ #include <QtQml/qqmlengine.h> #include <QtQml/qqmlcomponent.h> #include <QtQuick/qquickview.h> -#include <QtQuick/private/qquickboundaryrule_p.h> #include <QtQuick/private/qquickdraghandler_p.h> #include "../../shared/util.h" #include "../shared/viewtestutil.h" @@ -57,7 +56,7 @@ void tst_qquickboundaryrule::dragHandler() QVERIFY(target); QQuickDragHandler *dragHandler = target->findChild<QQuickDragHandler*>(); QVERIFY(dragHandler); - QQuickBoundaryRule *boundaryRule = target->findChild<QQuickBoundaryRule*>(); + QObject *boundaryRule = target->findChild<QObject *>(QLatin1String("boundaryRule")); QVERIFY(boundaryRule); QSignalSpy overshootChangedSpy(boundaryRule, SIGNAL(currentOvershootChanged())); @@ -68,29 +67,34 @@ void tst_qquickboundaryrule::dragHandler() QTest::mouseMove(&window, p1); QTRY_VERIFY(dragHandler->active()); QCOMPARE(target->position().x(), 100); - QCOMPARE(boundaryRule->currentOvershoot(), 0); - QCOMPARE(boundaryRule->peakOvershoot(), 0); + bool ok = false; + QCOMPARE(boundaryRule->property("currentOvershoot").toReal(&ok), 0); + QVERIFY(ok); + QCOMPARE(boundaryRule->property("peakOvershoot").toReal(&ok), 0); + QVERIFY(ok); QCOMPARE(overshootChangedSpy.count(), 0); // restricted drag: halfway into overshoot p1 += QPoint(20, 0); QTest::mouseMove(&window, p1); QCOMPARE(target->position().x(), 117.5); - QCOMPARE(boundaryRule->currentOvershoot(), 20); - QCOMPARE(boundaryRule->peakOvershoot(), 20); + QCOMPARE(boundaryRule->property("currentOvershoot").toReal(), 20); + QCOMPARE(boundaryRule->property("peakOvershoot").toReal(), 20); QCOMPARE(overshootChangedSpy.count(), 1); // restricted drag: maximum overshoot p1 += QPoint(80, 0); QTest::mouseMove(&window, p1); QCOMPARE(target->position().x(), 140); - QCOMPARE(boundaryRule->currentOvershoot(), 100); - QCOMPARE(boundaryRule->peakOvershoot(), 100); + QCOMPARE(boundaryRule->property("currentOvershoot").toReal(), 100); + QCOMPARE(boundaryRule->property("peakOvershoot").toReal(), 100); QCOMPARE(overshootChangedSpy.count(), 2); // release and let it return to bounds QTest::mouseRelease(&window, Qt::LeftButton, Qt::NoModifier, p1); QTRY_COMPARE(dragHandler->active(), false); QTRY_COMPARE(overshootChangedSpy.count(), 3); - QCOMPARE(boundaryRule->currentOvershoot(), 0); - QCOMPARE(boundaryRule->peakOvershoot(), 0); + QCOMPARE(boundaryRule->property("currentOvershoot").toReal(&ok), 0); + QVERIFY(ok); + QCOMPARE(boundaryRule->property("peakOvershoot").toReal(&ok), 0); + QVERIFY(ok); QCOMPARE(target->position().x(), 100); } diff --git a/tests/auto/quick/qquickflickable/data/resize.qml b/tests/auto/quick/qquickflickable/data/resize.qml index 2f7ae7b8bb..131691d012 100644 --- a/tests/auto/quick/qquickflickable/data/resize.qml +++ b/tests/auto/quick/qquickflickable/data/resize.qml @@ -1,6 +1,7 @@ import QtQuick 2.0 Rectangle { + required property bool setRebound function resizeContent() { flick.resizeContent(600, 600, Qt.point(100, 100)) } diff --git a/tests/auto/quick/qquickflickable/tst_qquickflickable.cpp b/tests/auto/quick/qquickflickable/tst_qquickflickable.cpp index c104eecbcd..5364530ca8 100644 --- a/tests/auto/quick/qquickflickable/tst_qquickflickable.cpp +++ b/tests/auto/quick/qquickflickable/tst_qquickflickable.cpp @@ -226,7 +226,7 @@ void tst_qquickflickable::create() { QQmlEngine engine; QQmlComponent c(&engine, testFileUrl("flickable01.qml")); - QQuickFlickable *obj = qobject_cast<QQuickFlickable*>(c.create()); + QQuickFlickable *obj = qobject_cast<QQuickFlickable*>(c.createWithInitialProperties({{"setRebound", false}})); QVERIFY(obj != nullptr); QCOMPARE(obj->isAtXBeginning(), true); @@ -782,9 +782,8 @@ void tst_qquickflickable::flickableDirection() void tst_qquickflickable::resizeContent() { QQmlEngine engine; - engine.rootContext()->setContextProperty("setRebound", QVariant::fromValue(false)); QQmlComponent c(&engine, testFileUrl("resize.qml")); - QQuickItem *root = qobject_cast<QQuickItem*>(c.create()); + QQuickItem *root = qobject_cast<QQuickItem*>(c.createWithInitialProperties({{"setRebound", false}})); QQuickFlickable *obj = findItem<QQuickFlickable>(root, "flick"); QVERIFY(obj != nullptr); @@ -816,7 +815,7 @@ void tst_qquickflickable::returnToBounds() QScopedPointer<QQuickView> window(new QQuickView); - window->rootContext()->setContextProperty("setRebound", setRebound); + window->setInitialProperties({{"setRebound", setRebound}}); window->setSource(testFileUrl("resize.qml")); window->show(); QVERIFY(QTest::qWaitForWindowActive(window.data())); diff --git a/tests/auto/quick/qquicklistview/data/delegatesWithRequiredProperties.qml b/tests/auto/quick/qquicklistview/data/delegatesWithRequiredProperties.qml new file mode 100644 index 0000000000..f354517678 --- /dev/null +++ b/tests/auto/quick/qquicklistview/data/delegatesWithRequiredProperties.qml @@ -0,0 +1,47 @@ +import QtQuick 2.12 +import Qt.fruit 1.0 + +Rectangle { + id: root + required property bool useCpp + width: 200; height: 200 + + + ListModel { + id: fruitModel + + ListElement { + name: "Apple" + cost: 2 + } + ListElement { + name: "Orange" + cost: 3 + } + ListElement { + name: "Banana" + cost: 1 + } + } + + + Component { + id: fruitDelegate + Row { + id: row + spacing: 10 + required property string name + required property int cost + Text { text: row.name } + Text { text: '$' + row.cost } + Component.onCompleted: () => { console.debug(row.name+row.cost) }; + } + } + + ListView { + anchors.fill: parent + model: root.useCpp ? FruitModelCpp : fruitModel + delegate: fruitDelegate + } + +} diff --git a/tests/auto/quick/qquicklistview/data/listview-sections_delegate_required.qml b/tests/auto/quick/qquicklistview/data/listview-sections_delegate_required.qml new file mode 100644 index 0000000000..18ce406e3f --- /dev/null +++ b/tests/auto/quick/qquicklistview/data/listview-sections_delegate_required.qml @@ -0,0 +1,77 @@ +import QtQuick 2.0 + +Rectangle { + property string sectionProperty: "number" + property int sectionPositioning: ViewSection.InlineLabels + width: 240 + height: 320 + color: "#ffffff" + resources: [ + Component { + id: myDelegate + Item { + id: wrapper + objectName: "wrapper" + property string section: ListView.section + property string nextSection: ListView.nextSection + property string prevSection: ListView.previousSection + height: 20; + width: 240 + Rectangle { + height: 20 + width: parent.width + color: wrapper.ListView.isCurrentItem ? "lightsteelblue" : "white" + Text { + text: index + } + Text { + x: 30 + id: textName + objectName: "textName" + text: name + } + Text { + x: 100 + id: textNumber + objectName: "textNumber" + text: number + } + Text { + objectName: "nextSection" + x: 150 + text: wrapper.ListView.nextSection + } + Text { + x: 200 + text: wrapper.y + } + } + ListView.onRemove: SequentialAnimation { + PropertyAction { target: wrapper; property: "ListView.delayRemove"; value: true } + NumberAnimation { target: wrapper; property: "height"; to: 0; duration: 100; easing.type: Easing.InOutQuad } + PropertyAction { target: wrapper; property: "ListView.delayRemove"; value: false } + } + } + } + ] + ListView { + id: list + objectName: "list" + width: 240 + height: 320 + cacheBuffer: 60 + model: testModel + delegate: myDelegate + section.property: sectionProperty + section.delegate: Rectangle { + id: myDelegate + required property string section + objectName: "sect_" + section + color: "#99bb99" + height: 20 + width: list.width + Text { text: myDelegate.section + ", " + parent.y + ", " + parent.objectName } + } + section.labelPositioning: sectionPositioning + } +} diff --git a/tests/auto/quick/qquicklistview/tst_qquicklistview.cpp b/tests/auto/quick/qquicklistview/tst_qquicklistview.cpp index ca438a9cd5..fb5ae168e8 100644 --- a/tests/auto/quick/qquicklistview/tst_qquicklistview.cpp +++ b/tests/auto/quick/qquicklistview/tst_qquicklistview.cpp @@ -127,6 +127,7 @@ private slots: void qAbstractItemModel_package_sections(); void qAbstractItemModel_sections(); void sectionsPositioning(); + void sectionsDelegate_data(); void sectionsDelegate(); void sectionsDragOutsideBounds_data(); void sectionsDragOutsideBounds(); @@ -280,6 +281,8 @@ private slots: void touchCancel(); void resizeAfterComponentComplete(); + void delegateWithRequiredProperties(); + private: template <class T> void items(const QUrl &source); template <class T> void changed(const QUrl &source); @@ -389,7 +392,7 @@ void tst_QQuickListView::init() m_view = nullptr; } #endif - qmlRegisterType<QAbstractItemModel>(); + qmlRegisterAnonymousType<QAbstractItemModel>("Proxy", 1); qmlRegisterType<ProxyTestInnerModel>("Proxy", 1, 0, "ProxyTestInnerModel"); qmlRegisterType<QSortFilterProxyModel>("Proxy", 1, 0, "QSortFilterProxyModel"); } @@ -2183,8 +2186,17 @@ void tst_QQuickListView::sections(const QUrl &source) QTRY_COMPARE(item->height(), 40.0); } +void tst_QQuickListView::sectionsDelegate_data() +{ + QTest::addColumn<QUrl>("path"); + QTest::addRow("implicit") << testFileUrl("listview-sections_delegate.qml"); + QTest::addRow("required") << testFileUrl("listview-sections_delegate_required.qml"); +} + void tst_QQuickListView::sectionsDelegate() { + QFETCH(QUrl, path); + QScopedPointer<QQuickView> window(createView()); QaimModel model; @@ -2194,7 +2206,7 @@ void tst_QQuickListView::sectionsDelegate() QQmlContext *ctxt = window->rootContext(); ctxt->setContextProperty("testModel", &model); - window->setSource(testFileUrl("listview-sections_delegate.qml")); + window->setSource(path); window->show(); QVERIFY(QTest::qWaitForWindowExposed(window.data())); @@ -9062,6 +9074,90 @@ void tst_QQuickListView::resizeAfterComponentComplete() // QTBUG-76487 QTRY_COMPARE(lastItem->property("y").toInt(), 9 * lastItem->property("height").toInt()); } +class Animal +{ +public: + Animal(const int cost, const QString &name) {m_name = name; m_cost = cost;} + + int cost() const {return m_cost;} + QString name() const {return m_name;} + + QString m_name; + int m_cost; +}; + +class FruitModel : public QAbstractListModel +{ + Q_OBJECT +public: + enum AnimalRoles { + NameRole = Qt::UserRole + 1, + CostRole + }; + + FruitModel(QObject* = nullptr) { + m_animals.push_back(Animal {4, QLatin1String("Melon")}); + m_animals.push_back(Animal {5, QLatin1String("Cherry")}); + } + + int rowCount(const QModelIndex & = QModelIndex()) const override {return m_animals.count();} + + QVariant data(const QModelIndex & index, int role = Qt::DisplayRole) const override { + if (!checkIndex(index)) + return {}; + const Animal &animal = m_animals[index.row()]; + if (role == CostRole) + return animal.cost(); + else if (role == NameRole) + return animal.name(); + return QVariant(); + } + +protected: + QHash<int, QByteArray> roleNames() const override { + QHash<int, QByteArray> roles; + roles[CostRole] = "cost"; + roles[NameRole] = "name"; + return roles; + } +private: + QList<Animal> m_animals; +}; + +void tst_QQuickListView::delegateWithRequiredProperties() +{ + FruitModel myModel; + qmlRegisterSingletonInstance("Qt.fruit", 1, 0, "FruitModelCpp", &myModel); + { + // ListModel + QTest::ignoreMessage(QtMsgType::QtDebugMsg, "Apple2"); + QTest::ignoreMessage(QtMsgType::QtDebugMsg, "Orange3"); + QTest::ignoreMessage(QtMsgType::QtDebugMsg, "Banana1"); + QScopedPointer<QQuickView> window(createView()); + window->setInitialProperties({{QLatin1String("useCpp"), false}}); + window->setSource(testFileUrl("delegatesWithRequiredProperties.qml")); + window->show(); + QVERIFY(QTest::qWaitForWindowExposed(window.data())); + + QObject *listView = window->rootObject(); + QVERIFY(listView); + } + { + // C++ model + QTest::ignoreMessage(QtMsgType::QtDebugMsg, "Melon4"); + QTest::ignoreMessage(QtMsgType::QtDebugMsg, "Cherry5"); + QScopedPointer<QQuickView> window(createView()); + window->setInitialProperties({{QLatin1String("useCpp"), true}}); + window->setSource(testFileUrl("delegatesWithRequiredProperties.qml")); + + window->show(); + QVERIFY(QTest::qWaitForWindowExposed(window.data())); + + QObject *listView = window->rootObject(); + QVERIFY(listView); + } +} + QTEST_MAIN(tst_QQuickListView) #include "tst_qquicklistview.moc" diff --git a/tests/auto/quick/qquickloader/data/RequiredPropertyValuesComponent.qml b/tests/auto/quick/qquickloader/data/RequiredPropertyValuesComponent.qml new file mode 100644 index 0000000000..7bb21e8b93 --- /dev/null +++ b/tests/auto/quick/qquickloader/data/RequiredPropertyValuesComponent.qml @@ -0,0 +1,8 @@ +import QtQuick 2.0 + +Item { + id: behaviorCounter + required property int i + required property string s + +} diff --git a/tests/auto/quick/qquickloader/data/initialPropertyValues.10.qml b/tests/auto/quick/qquickloader/data/initialPropertyValues.10.qml new file mode 100644 index 0000000000..4728346ca1 --- /dev/null +++ b/tests/auto/quick/qquickloader/data/initialPropertyValues.10.qml @@ -0,0 +1,20 @@ +import QtQuick 2.0 + +Item { + id: root + property int i: 0 + property string s: "" + + Loader { + id: loader + objectName: "loader" + onLoaded: { + root.i = loader.item.i; // should be 42 + root.s = loader.item.s; // should be 11 + } + } + + Component.onCompleted: { + loader.setSource("RequiredPropertyValuesComponent.qml", {"i": 42}); + } +} diff --git a/tests/auto/quick/qquickloader/data/initialPropertyValues.9.qml b/tests/auto/quick/qquickloader/data/initialPropertyValues.9.qml new file mode 100644 index 0000000000..5d6e3171a0 --- /dev/null +++ b/tests/auto/quick/qquickloader/data/initialPropertyValues.9.qml @@ -0,0 +1,20 @@ +import QtQuick 2.0 + +Item { + id: root + property int i: 0 + property string s: "" + + Loader { + id: loader + objectName: "loader" + onLoaded: { + root.i = loader.item.i; // should be 42 + root.s = loader.item.s; // should be 11 + } + } + + Component.onCompleted: { + loader.setSource("RequiredPropertyValuesComponent.qml", {"i": 42, "s": "hello world"}); + } +} diff --git a/tests/auto/quick/qquickloader/tst_qquickloader.cpp b/tests/auto/quick/qquickloader/tst_qquickloader.cpp index fbdd87905b..da923d4d41 100644 --- a/tests/auto/quick/qquickloader/tst_qquickloader.cpp +++ b/tests/auto/quick/qquickloader/tst_qquickloader.cpp @@ -681,6 +681,16 @@ void tst_QQuickLoader::initialPropertyValues_data() << QStringList() << (QStringList() << "initialValue") << (QVariantList() << 6); + + QTest::newRow("ensure required properties are set correctly") << testFileUrl("initialPropertyValues.9.qml") + << QStringList() + << (QStringList() << "i" << "s") + << (QVariantList() << 42 << QLatin1String("hello world")); + + QTest::newRow("required properties only partially set =") << testFileUrl("initialPropertyValues.10.qml") + << (QStringList() << QString(testFileUrl("RequiredPropertyValuesComponent.qml").toString() + QLatin1String(":6:5: Required property s was not initialized"))) + << (QStringList() << "i" << "s") + << (QVariantList() << 0 << QLatin1String("")); } void tst_QQuickLoader::initialPropertyValues() diff --git a/tests/auto/quick/qquickmousearea/data/dragreset.qml b/tests/auto/quick/qquickmousearea/data/dragreset.qml index 10039f1fcb..bbe0160080 100644 --- a/tests/auto/quick/qquickmousearea/data/dragreset.qml +++ b/tests/auto/quick/qquickmousearea/data/dragreset.qml @@ -1,6 +1,7 @@ import QtQuick 2.0 Rectangle { id: whiteRect + required property bool haveTarget width: 200 height: 200 color: "white" diff --git a/tests/auto/quick/qquickmousearea/tst_qquickmousearea.cpp b/tests/auto/quick/qquickmousearea/tst_qquickmousearea.cpp index 17553ee6c4..54a29dbc7f 100644 --- a/tests/auto/quick/qquickmousearea/tst_qquickmousearea.cpp +++ b/tests/auto/quick/qquickmousearea/tst_qquickmousearea.cpp @@ -307,7 +307,7 @@ void tst_QQuickMouseArea::resetDrag() { QQuickView window; QByteArray errorMessage; - window.rootContext()->setContextProperty("haveTarget", QVariant(true)); + window.setInitialProperties({{"haveTarget", true}}); QVERIFY2(QQuickTest::initView(window, testFileUrl("dragreset.qml"), true, &errorMessage), errorMessage.constData()); window.show(); QVERIFY(QTest::qWaitForWindowExposed(&window)); @@ -326,7 +326,9 @@ void tst_QQuickMouseArea::resetDrag() QVERIFY(rootItem != nullptr); QSignalSpy targetSpy(drag, SIGNAL(targetChanged())); QVERIFY(drag->target() != nullptr); - window.rootContext()->setContextProperty("haveTarget", QVariant(false)); + auto root = window.rootObject(); + QQmlProperty haveTarget {root, "haveTarget"}; + haveTarget.write(false); QCOMPARE(targetSpy.count(),1); QVERIFY(!drag->target()); } diff --git a/tests/auto/quick/qquickpathview/data/delegateWithRequiredProperties.2.qml b/tests/auto/quick/qquickpathview/data/delegateWithRequiredProperties.2.qml new file mode 100644 index 0000000000..ae8ca784bc --- /dev/null +++ b/tests/auto/quick/qquickpathview/data/delegateWithRequiredProperties.2.qml @@ -0,0 +1,59 @@ +import QtQuick 2.14 + +Item { + id: root + width: 800 + height: 600 + property bool working: false + + ListModel { + id: myModel + ListElement { + name: "Bill Jones" + place: "Berlin" + } + ListElement { + name: "Jane Doe" + place: "Oslo" + } + ListElement { + name: "John Smith" + place: "Oulo" + } + } + + Component { + id: delegateComponent + Rectangle { + id: myDelegate + height: 50 + width: 50 + required property string name + required property int index + onNameChanged: () => {if (myDelegate.name === "You-know-who") root.working = true} + Text { + text: myDelegate.name + font.pointSize: 10 + anchors.fill: myDelegate + } + } + } + + PathView { + anchors.fill: parent + model: myModel + delegate: delegateComponent + path: Path { + startX: 80; startY: 100 + PathQuad { x: 120; y: 25; controlX: 260; controlY: 75 } + PathQuad { x: 140; y: 100; controlX: -20; controlY: 75 } + } + } + Timer { + interval: 1 + running: true + repeat: false + onTriggered: () => { myModel.setProperty(1, "name", "You-know-who"); } + } + +} diff --git a/tests/auto/quick/qquickpathview/data/delegateWithRequiredProperties.3.qml b/tests/auto/quick/qquickpathview/data/delegateWithRequiredProperties.3.qml new file mode 100644 index 0000000000..2996ba18fd --- /dev/null +++ b/tests/auto/quick/qquickpathview/data/delegateWithRequiredProperties.3.qml @@ -0,0 +1,64 @@ +import QtQuick 2.14 + +Item { + id: root + width: 800 + height: 600 + property bool working: false + + ListModel { + id: myModel + ListElement { + name: "Bill Jones" + place: "Berlin" + } + ListElement { + name: "Jane Doe" + place: "Oslo" + } + ListElement { + name: "John Smith" + place: "Oulo" + } + } + + Component { + id: delegateComponent + Rectangle { + id: myDelegate + height: 50 + width: 50 + required property string name + required property int index + onNameChanged: () => {if (myDelegate.name === "You-know-who") root.working = false} + Text { + text: myDelegate.name + font.pointSize: 10 + anchors.fill: myDelegate + } + Component.onCompleted: () => {myDelegate.name = "break binding"} + } + } + + PathView { + anchors.fill: parent + model: myModel + delegate: delegateComponent + path: Path { + startX: 80; startY: 100 + PathQuad { x: 120; y: 25; controlX: 260; controlY: 75 } + PathQuad { x: 140; y: 100; controlX: -20; controlY: 75 } + } + } + Timer { + interval: 1 + running: true + repeat: false + onTriggered: () => { + myModel.setProperty(1, "name", "You-know-who") + myModel.setProperty(2, "name", "You-know-who") + root.working = true + } + } + +} diff --git a/tests/auto/quick/qquickpathview/data/delegateWithRequiredProperties.qml b/tests/auto/quick/qquickpathview/data/delegateWithRequiredProperties.qml new file mode 100644 index 0000000000..5d721fd0c4 --- /dev/null +++ b/tests/auto/quick/qquickpathview/data/delegateWithRequiredProperties.qml @@ -0,0 +1,53 @@ +import QtQuick 2.14 + +Item { + width: 400 + height: 200 + + ListModel { + id: myModel + ListElement { + name: "Bill Jones" + place: "Berlin" + } + ListElement { + name: "Jane Doe" + place: "Oslo" + } + ListElement { + name: "John Smith" + place: "Oulo" + } + } + + Component { + id: delegateComponent + Rectangle { + id: myDelegate + required property int index + required property string name + required property string place + height: 100 + width: 100 + Text { + text: myDelegate.name + " lives in " + myDelegate.place + myDelegate.index + font.pointSize: 16 + anchors.fill: myDelegate + + Component.onCompleted: () => {console.info(myDelegate.name+myDelegate.place+myDelegate.index)} + } + } + } + + PathView { + anchors.fill: parent + model: myModel + delegate: delegateComponent + path: Path { + startX: 120; startY: 100 + PathQuad { x: 120; y: 25; controlX: 260; controlY: 75 } + PathQuad { x: 120; y: 100; controlX: -20; controlY: 75 } + } + } + +} diff --git a/tests/auto/quick/qquickpathview/data/delegatewithUnrelatedRequiredPreventsAccessToModel.qml b/tests/auto/quick/qquickpathview/data/delegatewithUnrelatedRequiredPreventsAccessToModel.qml new file mode 100644 index 0000000000..bf130a2d73 --- /dev/null +++ b/tests/auto/quick/qquickpathview/data/delegatewithUnrelatedRequiredPreventsAccessToModel.qml @@ -0,0 +1,52 @@ +import QtQuick 2.14 + +Item { + width: 400 + height: 200 + + ListModel { + id: myModel + ListElement { + name: "Bill Jones" + place: "Berlin" + } + ListElement { + name: "Jane Doe" + place: "Oslo" + } + ListElement { + name: "John Smith" + place: "Oulo" + } + } + + Component { + id: delegateComponent + Rectangle { + id: myDelegate + required property int set + set: 42 + height: 100 + width: 100 + Text { + text: "Test" + font.pointSize: 16 + anchors.fill: myDelegate + + Component.onCompleted: () => { try {index; console.log(index); console.log(name)} catch(ex) {console.info(ex.name)} } + } + } + } + + PathView { + anchors.fill: parent + model: myModel + delegate: delegateComponent + path: Path { + startX: 120; startY: 100 + PathQuad { x: 120; y: 25; controlX: 260; controlY: 75 } + PathQuad { x: 120; y: 100; controlX: -20; controlY: 75 } + } + } + +} diff --git a/tests/auto/quick/qquickpathview/tst_qquickpathview.cpp b/tests/auto/quick/qquickpathview/tst_qquickpathview.cpp index 4498548d45..a8e847a5c7 100644 --- a/tests/auto/quick/qquickpathview/tst_qquickpathview.cpp +++ b/tests/auto/quick/qquickpathview/tst_qquickpathview.cpp @@ -150,6 +150,8 @@ private slots: void movementDirection(); void removePath(); void objectModelMove(); + void requiredPropertiesInDelegate(); + void requiredPropertiesInDelegatePreventUnrelated(); }; class TestObject : public QObject @@ -2724,6 +2726,41 @@ void tst_QQuickPathView::objectModelMove() } } +void tst_QQuickPathView::requiredPropertiesInDelegate() +{ + { + QTest::ignoreMessage(QtMsgType::QtInfoMsg, "Bill JonesBerlin0"); + QTest::ignoreMessage(QtMsgType::QtInfoMsg, "Jane DoeOslo1"); + QTest::ignoreMessage(QtMsgType::QtInfoMsg, "John SmithOulo2"); + QScopedPointer<QQuickView> window(createView()); + window->setSource(testFileUrl("delegateWithRequiredProperties.qml")); + window->show(); + } + { + QScopedPointer<QQuickView> window(createView()); + window->setSource(testFileUrl("delegateWithRequiredProperties.2.qml")); + window->show(); + QTRY_VERIFY(window->rootObject()->property("working").toBool()); + } + { + QScopedPointer<QQuickView> window(createView()); + QTest::ignoreMessage(QtMsgType::QtWarningMsg, QRegularExpression("Writing to \"name\" broke the binding to the underlying model")); + window->setSource(testFileUrl("delegateWithRequiredProperties.3.qml")); + window->show(); + QTRY_VERIFY(window->rootObject()->property("working").toBool()); + } +} + +void tst_QQuickPathView::requiredPropertiesInDelegatePreventUnrelated() +{ + QTest::ignoreMessage(QtMsgType::QtInfoMsg, "ReferenceError"); + QTest::ignoreMessage(QtMsgType::QtInfoMsg, "ReferenceError"); + QTest::ignoreMessage(QtMsgType::QtInfoMsg, "ReferenceError"); + QScopedPointer<QQuickView> window(createView()); + window->setSource(testFileUrl("delegatewithUnrelatedRequiredPreventsAccessToModel.qml")); + window->show(); +} + QTEST_MAIN(tst_QQuickPathView) #include "tst_qquickpathview.moc" diff --git a/tests/auto/quick/qquickpositioners/data/transitions-padding.qml b/tests/auto/quick/qquickpositioners/data/transitions-padding.qml index e3175c480c..eda9ce628e 100644 --- a/tests/auto/quick/qquickpositioners/data/transitions-padding.qml +++ b/tests/auto/quick/qquickpositioners/data/transitions-padding.qml @@ -5,6 +5,16 @@ Rectangle { width: 500 height: 500 + required property bool usePopulateTransition + required property bool enableAddTransition + required property bool dynamicallyPopulate + required property var testModel + required property var model_targetItems_transitionFrom + required property var model_displacedItems_transitionVia + required property point targetItems_transitionFrom + required property point displacedItems_transitionVia + required property string testedPositioner + property int duration: 50 property real incrementalSize: 5 diff --git a/tests/auto/quick/qquickpositioners/data/transitions.qml b/tests/auto/quick/qquickpositioners/data/transitions.qml index a1f27bb06e..988a01e373 100644 --- a/tests/auto/quick/qquickpositioners/data/transitions.qml +++ b/tests/auto/quick/qquickpositioners/data/transitions.qml @@ -5,6 +5,16 @@ Rectangle { width: 500 height: 500 + required property bool usePopulateTransition + required property bool enableAddTransition + required property bool dynamicallyPopulate + required property var testModel + required property var model_targetItems_transitionFrom + required property var model_displacedItems_transitionVia + required property point targetItems_transitionFrom + required property point displacedItems_transitionVia + required property string testedPositioner + property int duration: 50 property real incrementalSize: 5 diff --git a/tests/auto/quick/qquickpositioners/tst_qquickpositioners.cpp b/tests/auto/quick/qquickpositioners/tst_qquickpositioners.cpp index d3c0f345b9..e6bbd8c215 100644 --- a/tests/auto/quick/qquickpositioners/tst_qquickpositioners.cpp +++ b/tests/auto/quick/qquickpositioners/tst_qquickpositioners.cpp @@ -1025,16 +1025,17 @@ void tst_qquickpositioners::populateTransitions(const QString &positionerObjectN QScopedPointer<QQuickView> window(QQuickViewTestUtil::createView()); - QQmlContext *ctxt = window->rootContext(); - ctxt->setContextProperty("usePopulateTransition", usePopulateTransition); - ctxt->setContextProperty("enableAddTransition", true); - ctxt->setContextProperty("dynamicallyPopulate", dynamicallyPopulate); - ctxt->setContextProperty("testModel", &model); - ctxt->setContextProperty("model_targetItems_transitionFrom", &model_targetItems_transitionFrom); - ctxt->setContextProperty("model_displacedItems_transitionVia", &model_displacedItems_transitionVia); - ctxt->setContextProperty("targetItems_transitionFrom", targetItems_transitionFrom); - ctxt->setContextProperty("displacedItems_transitionVia", displacedItems_transitionVia); - ctxt->setContextProperty("testedPositioner", positionerObjectName); + window->setInitialProperties({ + {"usePopulateTransition", usePopulateTransition}, + {"enableAddTransition", true}, + {"dynamicallyPopulate", dynamicallyPopulate}, + {"testModel", QVariant::fromValue(&model)}, + {"model_targetItems_transitionFrom", QVariant::fromValue(&model_targetItems_transitionFrom)}, + {"model_displacedItems_transitionVia", QVariant::fromValue(&model_displacedItems_transitionVia)}, + {"targetItems_transitionFrom", targetItems_transitionFrom}, + {"displacedItems_transitionVia", displacedItems_transitionVia}, + {"testedPositioner", positionerObjectName} + }); window->setSource(testFileUrl(qmlFile)); QQuickItem *positioner = window->rootObject()->findChild<QQuickItem*>(positionerObjectName); @@ -1111,16 +1112,17 @@ void tst_qquickpositioners::addTransitions(const QString &positionerObjectName) QaimModel model_displacedItems_transitionVia; QScopedPointer<QQuickView> window(QQuickViewTestUtil::createView()); - QQmlContext *ctxt = window->rootContext(); - ctxt->setContextProperty("usePopulateTransition", QVariant(false)); - ctxt->setContextProperty("enableAddTransition", QVariant(true)); - ctxt->setContextProperty("dynamicallyPopulate", QVariant(false)); - ctxt->setContextProperty("testModel", &model); - ctxt->setContextProperty("model_targetItems_transitionFrom", &model_targetItems_transitionFrom); - ctxt->setContextProperty("model_displacedItems_transitionVia", &model_displacedItems_transitionVia); - ctxt->setContextProperty("targetItems_transitionFrom", targetItems_transitionFrom); - ctxt->setContextProperty("displacedItems_transitionVia", displacedItems_transitionVia); - ctxt->setContextProperty("testedPositioner", QString()); + window->setInitialProperties({ + {"usePopulateTransition", QVariant(false)}, + {"enableAddTransition", QVariant(true)}, + {"dynamicallyPopulate", QVariant(false)}, + {"testModel", QVariant::fromValue(&model)}, + {"model_targetItems_transitionFrom", QVariant::fromValue(&model_targetItems_transitionFrom)}, + {"model_displacedItems_transitionVia", QVariant::fromValue(&model_displacedItems_transitionVia)}, + {"targetItems_transitionFrom", targetItems_transitionFrom}, + {"displacedItems_transitionVia", displacedItems_transitionVia}, + {"testedPositioner", QString()} + }); window->setSource(testFileUrl(qmlFile)); window->show(); QVERIFY(QTest::qWaitForWindowExposed(window.data())); @@ -1234,16 +1236,17 @@ void tst_qquickpositioners::moveTransitions(const QString &positionerObjectName) QaimModel model_displacedItems_transitionVia; QScopedPointer<QQuickView> window(QQuickViewTestUtil::createView()); - QQmlContext *ctxt = window->rootContext(); - ctxt->setContextProperty("usePopulateTransition", QVariant(false)); - ctxt->setContextProperty("enableAddTransition", QVariant(false)); - ctxt->setContextProperty("dynamicallyPopulate", QVariant(false)); - ctxt->setContextProperty("testModel", &model); - ctxt->setContextProperty("model_targetItems_transitionFrom", &model_targetItems_transitionFrom); - ctxt->setContextProperty("model_displacedItems_transitionVia", &model_displacedItems_transitionVia); - ctxt->setContextProperty("targetItems_transitionFrom", targetItems_transitionFrom); - ctxt->setContextProperty("displacedItems_transitionVia", displacedItems_transitionVia); - ctxt->setContextProperty("testedPositioner", QString()); + window->setInitialProperties({ + {"usePopulateTransition", QVariant(false)}, + {"enableAddTransition", QVariant(false)}, + {"dynamicallyPopulate", QVariant(false)}, + {"testModel", QVariant::fromValue(&model)}, + {"model_targetItems_transitionFrom", QVariant::fromValue(&model_targetItems_transitionFrom)}, + {"model_displacedItems_transitionVia", QVariant::fromValue(&model_displacedItems_transitionVia)}, + {"targetItems_transitionFrom", targetItems_transitionFrom}, + {"displacedItems_transitionVia", displacedItems_transitionVia}, + {"testedPositioner", QString()} + }); window->setSource(testFileUrl(qmlFile)); window->show(); QVERIFY(QTest::qWaitForWindowExposed(window.data())); diff --git a/tests/auto/quick/qquickrepeater/data/objlist_required.qml b/tests/auto/quick/qquickrepeater/data/objlist_required.qml new file mode 100644 index 0000000000..cc9dd9566c --- /dev/null +++ b/tests/auto/quick/qquickrepeater/data/objlist_required.qml @@ -0,0 +1,23 @@ +import QtQuick 2.0 + +Rectangle { + id: container + objectName: "container" + width: 240 + height: 320 + color: "white" + Repeater { + id: repeater + objectName: "repeater" + model: testData + property int errors: 0 + property int instantiated: 0 + Component { + Item{ + required property int index + required property int idx + Component.onCompleted: {if (index != idx) repeater.errors += 1; repeater.instantiated++} + } + } + } +} diff --git a/tests/auto/quick/qquickrepeater/data/requiredProperty.qml b/tests/auto/quick/qquickrepeater/data/requiredProperty.qml new file mode 100644 index 0000000000..80eb3c28ee --- /dev/null +++ b/tests/auto/quick/qquickrepeater/data/requiredProperty.qml @@ -0,0 +1,16 @@ +import QtQuick 2.14 + +Item { + Column { + Repeater { + model: ["apples", "oranges", "pears"] + Text { + id: txt + required property string modelData + required property int index + text: modelData + index + Component.onCompleted: () => {console.info(txt.text)} + } + } + } +} diff --git a/tests/auto/quick/qquickrepeater/tst_qquickrepeater.cpp b/tests/auto/quick/qquickrepeater/tst_qquickrepeater.cpp index 65e7d29595..ccfef63902 100644 --- a/tests/auto/quick/qquickrepeater/tst_qquickrepeater.cpp +++ b/tests/auto/quick/qquickrepeater/tst_qquickrepeater.cpp @@ -55,6 +55,7 @@ public: private slots: void numberModel(); + void objectList_data(); void objectList(); void stringList(); void dataModel_adding(); @@ -79,6 +80,7 @@ private slots: void QTBUG54859_asynchronousMove(); void package(); void ownership(); + void requiredProperties(); }; class TestObject : public QObject @@ -143,6 +145,14 @@ void tst_QQuickRepeater::numberModel() delete window; } +void tst_QQuickRepeater::objectList_data() +{ + QTest::addColumn<QUrl>("filename"); + + QTest::newRow("normal") << testFileUrl("objlist.qml"); + QTest::newRow("required") << testFileUrl("objlist_required.qml"); +} + class MyObject : public QObject { Q_OBJECT @@ -157,6 +167,7 @@ public: void tst_QQuickRepeater::objectList() { + QFETCH(QUrl, filename); QQuickView *window = createView(); QObjectList data; for (int i=0; i<100; i++) @@ -165,7 +176,7 @@ void tst_QQuickRepeater::objectList() QQmlContext *ctxt = window->rootContext(); ctxt->setContextProperty("testData", QVariant::fromValue(data)); - window->setSource(testFileUrl("objlist.qml")); + window->setSource(filename); qApp->processEvents(); QQuickRepeater *repeater = findItem<QQuickRepeater>(window->rootObject(), "repeater"); @@ -1108,6 +1119,18 @@ void tst_QQuickRepeater::ownership() QVERIFY(!modelGuard); } +void tst_QQuickRepeater::requiredProperties() +{ + QTest::ignoreMessage(QtMsgType::QtInfoMsg, "apples0"); + QTest::ignoreMessage(QtMsgType::QtInfoMsg, "oranges1"); + QTest::ignoreMessage(QtMsgType::QtInfoMsg, "pears2"); + QQmlEngine engine; + + QQmlComponent component(&engine, testFileUrl("requiredProperty.qml")); + QScopedPointer<QObject> o {component.create()}; + QVERIFY(o); +} + QTEST_MAIN(tst_QQuickRepeater) #include "tst_qquickrepeater.moc" diff --git a/tests/auto/quick/qquicktableview/data/delegateWithRequired.qml b/tests/auto/quick/qquicktableview/data/delegateWithRequired.qml new file mode 100644 index 0000000000..bebfd86931 --- /dev/null +++ b/tests/auto/quick/qquicktableview/data/delegateWithRequired.qml @@ -0,0 +1,70 @@ +/**************************************************************************** +** +** Copyright (C) 2018 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtQuick module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** 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 Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** 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-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.12 +import QtQuick.Window 2.3 + +Item { + width: 640 + height: 450 + + property alias tableView: tableView + + TableView { + id: tableView + width: 600 + height: 400 + delegate: tableViewDelegate + } + + Component { + id: tableViewDelegate + Rectangle { + id: rect + required property string position + required property bool hasModelChildren + required property QtObject model + Text {text: rect.position} + implicitWidth: 100 + implicitHeight: 100 + Component.onCompleted: () => {if (rect.position === "R1:C1" && rect.model.hasModelChildren == rect.hasModelChildren) console.info("success")} + } + } + +} diff --git a/tests/auto/quick/qquicktableview/data/delegatewithRequiredUnset.qml b/tests/auto/quick/qquicktableview/data/delegatewithRequiredUnset.qml new file mode 100644 index 0000000000..0c685cd49e --- /dev/null +++ b/tests/auto/quick/qquicktableview/data/delegatewithRequiredUnset.qml @@ -0,0 +1,71 @@ +/**************************************************************************** +** +** Copyright (C) 2018 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtQuick module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** 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 Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** 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-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.12 +import QtQuick.Window 2.3 + +Item { + width: 640 + height: 450 + + property alias tableView: tableView + + TableView { + id: tableView + width: 600 + height: 400 + delegate: tableViewDelegate + } + + Component { + id: tableViewDelegate + Rectangle { + id: rect + required property string position + required property bool unset + required property bool hasModelChildren + required property QtObject model + Text {text: rect.position} + implicitWidth: 100 + implicitHeight: 100 + Component.onCompleted: () => {if (rect.position === "R1:C1" && rect.model.hasModelChildren == rect.hasModelChildren) console.info("success")} + } + } + +} diff --git a/tests/auto/quick/qquicktableview/tst_qquicktableview.cpp b/tests/auto/quick/qquicktableview/tst_qquicktableview.cpp index 889175a228..230dcc9446 100644 --- a/tests/auto/quick/qquicktableview/tst_qquicktableview.cpp +++ b/tests/auto/quick/qquicktableview/tst_qquicktableview.cpp @@ -173,6 +173,7 @@ private slots: void checkSyncView_differentSizedModels(); void checkSyncView_connect_late_data(); void checkSyncView_connect_late(); + void delegateWithRequiredProperties(); }; tst_QQuickTableView::tst_QQuickTableView() @@ -2619,6 +2620,50 @@ void tst_QQuickTableView::checkSyncView_connect_late() } +void tst_QQuickTableView::delegateWithRequiredProperties() +{ + constexpr static int PositionRole = Qt::UserRole+1; + struct MyTable : QAbstractTableModel { + + + using QAbstractTableModel::QAbstractTableModel; + + int rowCount(const QModelIndex& = QModelIndex()) const override { + return 3; + } + + int columnCount(const QModelIndex& = QModelIndex()) const override { + return 3; + } + + QVariant data(const QModelIndex &index, int = Qt::DisplayRole) const override { + return QVariant::fromValue(QString::asprintf("R%d:C%d", index.row(), index.column())); + } + + QHash<int, QByteArray> roleNames() const override { + return QHash<int, QByteArray> { {PositionRole, "position"} }; + } + }; + + auto model = QVariant::fromValue(QSharedPointer<MyTable>(new MyTable)); + { + QTest::ignoreMessage(QtMsgType::QtInfoMsg, "success"); + LOAD_TABLEVIEW("delegateWithRequired.qml") + QVERIFY(tableView); + tableView->setModel(model); + WAIT_UNTIL_POLISHED; + QVERIFY(view->errors().empty()); + } + { + QTest::ignoreMessage(QtMsgType::QtWarningMsg, QRegularExpression(R"|(TableView: failed loading index: \d)|")); + LOAD_TABLEVIEW("delegatewithRequiredUnset.qml") + QVERIFY(tableView); + tableView->setModel(model); + WAIT_UNTIL_POLISHED; + QTRY_VERIFY(view->errors().empty()); + } +} + QTEST_MAIN(tst_QQuickTableView) #include "tst_qquicktableview.moc" diff --git a/tests/manual/pointer/pointerDrag.qml b/tests/manual/pointer/pointerDrag.qml index 79044eb0b4..2063d8fae2 100644 --- a/tests/manual/pointer/pointerDrag.qml +++ b/tests/manual/pointer/pointerDrag.qml @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2018 The Qt Company Ltd. +** Copyright (C) 2019 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the manual tests of the Qt Toolkit. @@ -26,7 +26,7 @@ ** ****************************************************************************/ -import QtQuick 2.12 +import QtQuick 2.15 import "content" Rectangle { @@ -74,7 +74,14 @@ Rectangle { label: "DragHandler" objectName: "dragSquircle1" DragHandler { - + dragThreshold: ckZeroDragThreshold1.checked ? 0 : undefined + } + CheckBox { + id: ckZeroDragThreshold1 + label: " Zero threshold" + anchors.horizontalCenter: parent.horizontalCenter + y: 20 + checked: false } } @@ -99,7 +106,16 @@ Rectangle { id: tap2 gesturePolicy: root.globalGesturePolicy } - DragHandler { } + DragHandler { + dragThreshold: ckZeroDragThreshold2.checked ? 0 : undefined + } + CheckBox { + id: ckZeroDragThreshold2 + label: " Zero threshold" + anchors.horizontalCenter: parent.horizontalCenter + y: 32 + checked: false + } } TextBox { @@ -107,7 +123,16 @@ Rectangle { width: 100; height: 100 label: "DragHandler\nTapHandler" color: queryColor(tap3.pressed) - DragHandler { } + DragHandler { + dragThreshold: ckZeroDragThreshold3.checked ? 0 : undefined + } + CheckBox { + id: ckZeroDragThreshold3 + label: " Zero threshold" + anchors.horizontalCenter: parent.horizontalCenter + y: 32 + checked: false + } TapHandler { id: tap3 gesturePolicy: root.globalGesturePolicy @@ -118,7 +143,16 @@ Rectangle { x: 400; y: 0 width: 100; height: 100 label: "DragHandler" - DragHandler { } + DragHandler { + dragThreshold: ckZeroDragThreshold4.checked ? 0 : undefined + } + CheckBox { + id: ckZeroDragThreshold4 + label: " Zero threshold" + anchors.horizontalCenter: parent.horizontalCenter + y: 20 + checked: false + } TextBox { label: "TapHandler" @@ -145,6 +179,13 @@ Rectangle { label: " Greedy ↓" checked: true } + CheckBox { + id: ckZeroDragThreshold5 + label: " Zero threshold" + x: 10 + anchors.bottom: ckGreedyDrag.top + checked: false + } TapHandler { id: tap5 gesturePolicy: root.globalGesturePolicy @@ -159,6 +200,7 @@ Rectangle { DragHandler { grabPermissions: ckGreedyDrag ? DragHandler.CanTakeOverFromAnything : DragHandler.CanTakeOverFromItems | DragHandler.CanTakeOverFromHandlersOfDifferentType | DragHandler.ApprovesTakeOverByAnything + dragThreshold: ckZeroDragThreshold5.checked ? 0 : undefined } } } @@ -174,7 +216,16 @@ Rectangle { label: "DragHandler" x: (parent.width - width)/2 y: 60 - DragHandler { } + DragHandler { + dragThreshold: ckZeroDragThreshold6.checked ? 0 : undefined + } + } + CheckBox { + id: ckZeroDragThreshold6 + label: " Zero threshold" + anchors.horizontalCenter: parent.horizontalCenter + y: 20 + checked: false } } |