From eb154bd1f223121a8d8ae481ce6a873d56823765 Mon Sep 17 00:00:00 2001 From: Maximilian Goldstein Date: Mon, 19 Apr 2021 14:44:33 +0200 Subject: qqmlirbuilder: Fix treating parser warnings as errros Previously parser warnings (i.e. inline components having lowercase names) were treated as errors. Because these were not handled properly this also resulted in the QQmlComponent with the warning never becoming ready. This resulted applications hanging instead of terminating. Change-Id: Ia5ad3b54edc1b94dd94d0bf771c3494691abec71 Reviewed-by: Fabian Kosmale (cherry picked from commit e49be8d2b1b7acb310873a63f46980d1f0296f95) --- src/qml/compiler/qqmlirbuilder.cpp | 4 +++- tests/auto/qml/qqmllanguage/data/hangOnWarning.qml | 3 +++ tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp | 12 ++++++++++++ 3 files changed, 18 insertions(+), 1 deletion(-) create mode 100644 tests/auto/qml/qqmllanguage/data/hangOnWarning.qml diff --git a/src/qml/compiler/qqmlirbuilder.cpp b/src/qml/compiler/qqmlirbuilder.cpp index 5fcdcd1532..c96a781b65 100644 --- a/src/qml/compiler/qqmlirbuilder.cpp +++ b/src/qml/compiler/qqmlirbuilder.cpp @@ -448,7 +448,9 @@ bool IRBuilder::generateFromQml(const QString &code, const QString &url, Documen errors << m; } - return false; + + if (!errors.isEmpty() || !parseResult) + return false; } program = parser.ast(); Q_ASSERT(program); diff --git a/tests/auto/qml/qqmllanguage/data/hangOnWarning.qml b/tests/auto/qml/qqmllanguage/data/hangOnWarning.qml new file mode 100644 index 0000000000..51943c3839 --- /dev/null +++ b/tests/auto/qml/qqmllanguage/data/hangOnWarning.qml @@ -0,0 +1,3 @@ +import QtQml 2.15 + +QtObject["foobar"] {} diff --git a/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp b/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp index de8b2ef7eb..94ecd6862a 100644 --- a/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp +++ b/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp @@ -334,6 +334,8 @@ private slots: void accessNullPointerPropertyCache(); void bareInlineComponent(); + void hangOnWarning(); + private: QQmlEngine engine; QStringList defaultImportPathList; @@ -5841,6 +5843,16 @@ void tst_qqmllanguage::bareInlineComponent() QVERIFY(tab1Found); } +void tst_qqmllanguage::hangOnWarning() +{ + QTest::ignoreMessage(QtWarningMsg, + qPrintable(QStringLiteral("%1:3 : Ignored annotation") + .arg(testFileUrl("hangOnWarning.qml").toString()))); + QQmlComponent component(&engine, testFileUrl("hangOnWarning.qml")); + QScopedPointer object(component.create()); + QVERIFY(object != nullptr); +} + QTEST_MAIN(tst_qqmllanguage) #include "tst_qqmllanguage.moc" -- cgit v1.2.3 From 02f0c23d001b433e333ede211227c8021b55277e Mon Sep 17 00:00:00 2001 From: Mitch Curtis Date: Mon, 19 Apr 2021 13:31:07 +0200 Subject: Document that QML_SINGLETON only works with QObjects Change-Id: I18c38037cd635fa3300c761b16038b67ac3b0d74 Reviewed-by: Fabian Kosmale (cherry picked from commit 03a2e51063de99f85b3b801c7ccd6663163a61b0) --- src/qml/doc/src/qmlfunctions.qdoc | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/qml/doc/src/qmlfunctions.qdoc b/src/qml/doc/src/qmlfunctions.qdoc index 4e531ceb61..6f5a0c4196 100644 --- a/src/qml/doc/src/qmlfunctions.qdoc +++ b/src/qml/doc/src/qmlfunctions.qdoc @@ -159,11 +159,11 @@ \relates QQmlEngine Declares the enclosing type to be a singleton in QML. This only takes effect - if the type is available in QML, by having a \l QML_ELEMENT or - \l QML_NAMED_ELEMENT() macro. By default, each QQmlEngine will try to create a - singleton instance using the type's default constructor when the type is first - accessed. If there is no default constructor the singleton is initially - inaccessible. This behavior can be overridden by calling + if the type is a \l Q_OBJECT and is available in QML (by having a + \l QML_ELEMENT or \l QML_NAMED_ELEMENT() macro). By default, each QQmlEngine + will try to create a singleton instance using the type's default constructor + when the type is first accessed. If there is no default constructor the + singleton is initially inaccessible. This behavior can be overridden by calling \l qmlRegisterSingletonType() with a specific factory function or \l qmlRegisterSingletonInstance() with a specific instance for the same class and the same type namespace and version. -- cgit v1.2.3 From 44055ebbe1db7e8f229de6c6936cd326b69dff15 Mon Sep 17 00:00:00 2001 From: Maximilian Goldstein Date: Fri, 8 Jan 2021 11:58:55 +0100 Subject: Fix warning and assert when removing items from groups When removing items from groups actively shown by a model filter a warning and assert was triggered in the past. This change fixes this behavior. Fixes: QTBUG-86017 Change-Id: I49b7498a3d03141b654e453a3c35a43fc7ba804a Reviewed-by: Ulf Hermann (cherry picked from commit 8a3ede5ba1daf2d9314d71db972175b2791456c0) Reviewed-by: Fabian Kosmale --- src/qmlmodels/qqmldelegatemodel.cpp | 2 ++ src/quick/items/qquickitemview.cpp | 4 ++- .../qml/qqmldelegatemodel/data/qtbug_86017.qml | 32 ++++++++++++++++++++++ .../qqmldelegatemodel/tst_qqmldelegatemodel.cpp | 15 ++++++++++ 4 files changed, 52 insertions(+), 1 deletion(-) create mode 100644 tests/auto/qml/qqmldelegatemodel/data/qtbug_86017.qml diff --git a/src/qmlmodels/qqmldelegatemodel.cpp b/src/qmlmodels/qqmldelegatemodel.cpp index 6db30c5fe6..dbd73ae667 100644 --- a/src/qmlmodels/qqmldelegatemodel.cpp +++ b/src/qmlmodels/qqmldelegatemodel.cpp @@ -1343,6 +1343,8 @@ QObject *QQmlDelegateModel::object(int index, QQmlIncubator::IncubationMode incu QQmlIncubator::Status QQmlDelegateModel::incubationStatus(int index) { Q_D(QQmlDelegateModel); + if (d->m_compositor.count(d->m_compositorGroup) <= index) + return QQmlIncubator::Null; Compositor::iterator it = d->m_compositor.find(d->m_compositorGroup, index); if (!it->inCache()) return QQmlIncubator::Null; diff --git a/src/quick/items/qquickitemview.cpp b/src/quick/items/qquickitemview.cpp index 15cc6b34cf..3999109e47 100644 --- a/src/quick/items/qquickitemview.cpp +++ b/src/quick/items/qquickitemview.cpp @@ -2346,7 +2346,9 @@ FxViewItem *QQuickItemViewPrivate::createItem(int modelIndex, QQmlIncubator::Inc inRequest = true; - QObject* object = model->object(modelIndex, incubationMode); + // The model will run this same range check internally but produce a warning and return nullptr. + // Since we handle this result graciously in our code, we preempt this warning by checking the range ourselves. + QObject* object = modelIndex < model->count() ? model->object(modelIndex, incubationMode) : nullptr; QQuickItem *item = qmlobject_cast(object); if (!item) { diff --git a/tests/auto/qml/qqmldelegatemodel/data/qtbug_86017.qml b/tests/auto/qml/qqmldelegatemodel/data/qtbug_86017.qml new file mode 100644 index 0000000000..02d737e37f --- /dev/null +++ b/tests/auto/qml/qqmldelegatemodel/data/qtbug_86017.qml @@ -0,0 +1,32 @@ +import QtQuick 2.8 +import QtQml.Models 2.1 + +DelegateModel { + id: visualModel + model: ListModel { + id: myLM + ListElement { + name: "Apple" + } + ListElement { + name: "Orange" + } + } + + filterOnGroup: "selected" + + groups: [ + DelegateModelGroup { + name: "selected" + includeByDefault: true + } + ] + + delegate: Text { + Component.onCompleted: { + DelegateModel.inPersistedItems = true + DelegateModel.inSelected = false + } + text: "item " + index + } +} diff --git a/tests/auto/qml/qqmldelegatemodel/tst_qqmldelegatemodel.cpp b/tests/auto/qml/qqmldelegatemodel/tst_qqmldelegatemodel.cpp index 71550a50f3..9bc359d243 100644 --- a/tests/auto/qml/qqmldelegatemodel/tst_qqmldelegatemodel.cpp +++ b/tests/auto/qml/qqmldelegatemodel/tst_qqmldelegatemodel.cpp @@ -45,6 +45,7 @@ private slots: void valueWithoutCallingObjectFirst_data(); void valueWithoutCallingObjectFirst(); void filterOnGroup_removeWhenCompleted(); + void qtbug_86017(); }; class AbstractItemModel : public QAbstractItemModel @@ -147,6 +148,20 @@ void tst_QQmlDelegateModel::filterOnGroup_removeWhenCompleted() QQmlDelegateModel *model = root->findChild(); QVERIFY(model); QTest::qWaitFor([=]{ return model->count() == 2; } ); + +void tst_QQmlDelegateModel::qtbug_86017() +{ + QQmlEngine engine; + QQmlComponent component(&engine); + component.loadUrl(testFileUrl("qtbug_86017.qml")); + QScopedPointer root(component.create()); + QVERIFY2(root, qPrintable(component.errorString())); + QTRY_VERIFY(component.isReady()); + QQmlDelegateModel *model = qobject_cast(root.data()); + + QVERIFY(model); + QCOMPARE(model->count(), 2); + QCOMPARE(model->filterGroup(), "selected"); } QTEST_MAIN(tst_QQmlDelegateModel) -- cgit v1.2.3 From acc724235c1e6eeebc387e9b9f10926675410aa9 Mon Sep 17 00:00:00 2001 From: Zhang Hao Date: Fri, 23 Apr 2021 15:01:10 +0800 Subject: Remove extra colon JavaScript Grammatical errors, There should be no colon after the function brackets Fixes: QTBUG-93048 Change-Id: I902d490bf810fa60e3b3d2a76de7902345289cfe Reviewed-by: Ulf Hermann (cherry picked from commit df8e6136834326e363db49829d227a303e5425ed) Reviewed-by: Qt Cherry-pick Bot --- src/qml/doc/src/qmllanguageref/syntax/signals.qdoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/qml/doc/src/qmllanguageref/syntax/signals.qdoc b/src/qml/doc/src/qmllanguageref/syntax/signals.qdoc index 075b3a7646..0e06cbec8a 100644 --- a/src/qml/doc/src/qmllanguageref/syntax/signals.qdoc +++ b/src/qml/doc/src/qmllanguageref/syntax/signals.qdoc @@ -133,7 +133,7 @@ Rectangle { Connections { target: button - function onClicked(): { + function onClicked() { rect.color = Qt.rgba(Math.random(), Math.random(), Math.random(), 1); } } -- cgit v1.2.3 From f81427db238c2dd5cdc4e300f3b8204419c04839 Mon Sep 17 00:00:00 2001 From: Fabian Kosmale Date: Tue, 27 Apr 2021 14:56:35 +0200 Subject: QQmlComponentPrivate::setInitialProperty: improve error message We can discern between the case where the property does not exist at all, and the case where we cannot set it. Change-Id: Ia2e8f4cc077a00b90d720db01bff1542a812dea0 Reviewed-by: Mitch Curtis (cherry picked from commit 7275328b967582010abfd59c9a93feef4cb1379f) Reviewed-by: Qt Cherry-pick Bot --- src/qml/qml/qqmlcomponent.cpp | 9 +++++++-- tests/auto/qml/qqmlcomponent/tst_qqmlcomponent.cpp | 2 +- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/src/qml/qml/qqmlcomponent.cpp b/src/qml/qml/qqmlcomponent.cpp index 98083ffa00..82995bbd65 100644 --- a/src/qml/qml/qqmlcomponent.cpp +++ b/src/qml/qml/qqmlcomponent.cpp @@ -375,10 +375,15 @@ bool QQmlComponentPrivate::setInitialProperty(QObject *component, const QString& { QQmlProperty prop = QQmlComponentPrivate::removePropertyFromRequired(component, name, requiredProperties()); QQmlPropertyPrivate *privProp = QQmlPropertyPrivate::get(prop); - if (!prop.isValid() || !privProp->writeValueProperty(value, {})) { + const bool isValid = prop.isValid(); + if (!isValid || !privProp->writeValueProperty(value, {})) { QQmlError error{}; error.setUrl(url); - error.setDescription(QLatin1String("Could not set property %1").arg(name)); + if (isValid) + error.setDescription(QLatin1String("Could not set initial property %1").arg(name)); + else + error.setDescription(QLatin1String("Setting initial properties failed: %2 does not have a property called %1").arg(name, + QQmlMetaType::prettyTypeName(component))); state.errors.push_back(error); return false; } else diff --git a/tests/auto/qml/qqmlcomponent/tst_qqmlcomponent.cpp b/tests/auto/qml/qqmlcomponent/tst_qqmlcomponent.cpp index 43cbd93396..544569de5f 100644 --- a/tests/auto/qml/qqmlcomponent/tst_qqmlcomponent.cpp +++ b/tests/auto/qml/qqmlcomponent/tst_qqmlcomponent.cpp @@ -828,7 +828,7 @@ void tst_qqmlcomponent::testSetInitialProperties() comp.createWithInitialProperties(QVariantMap { {"notThePropertiesYoureLookingFor", 42} }) }; QVERIFY(obj); - QVERIFY(comp.errorString().contains("Could not set property notThePropertiesYoureLookingFor")); + QVERIFY(comp.errorString().contains("Setting initial properties failed: Item does not have a property called notThePropertiesYoureLookingFor")); } } -- cgit v1.2.3 From 5fda4ec00bd2069255d48f644543683b5bf202d2 Mon Sep 17 00:00:00 2001 From: Mitch Curtis Date: Tue, 27 Apr 2021 14:20:35 +0200 Subject: Document QQmlComponent::createWithInitialProperties() error handling Unlike create(), it can produce errors that should be checked. Change-Id: I78f2e58c8666eb45f6e850c43e3e97a448b2758e Reviewed-by: Fabian Kosmale (cherry picked from commit 4f0622f7f553cd841874f0efe65d7f13edeec216) Reviewed-by: Qt Cherry-pick Bot --- src/qml/qml/qqmlcomponent.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/qml/qml/qqmlcomponent.cpp b/src/qml/qml/qqmlcomponent.cpp index 82995bbd65..4618591e4c 100644 --- a/src/qml/qml/qqmlcomponent.cpp +++ b/src/qml/qml/qqmlcomponent.cpp @@ -835,6 +835,14 @@ QObject *QQmlComponent::create(QQmlContext *context) properties with \a initialProperties. \a context specifies the context where the object instance is to be created. + \omit + TODO: also mention errorString() when QTBUG-93239 is fixed + \endomit + + If any of the \c initialProperties cannot be set, \l isError() will return + \c true, and the \l errors() function can be used to + get detailed information about the error(s). + \sa QQmlComponent::create \since 5.14 */ -- cgit v1.2.3 From 02d9ede53916663ea527aec3c3c9ae3a75df7c07 Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Thu, 29 Apr 2021 10:44:00 +0200 Subject: Fix build with GCC 11: include Task-number: QTBUG-90395 Change-Id: I5a767ffd92f5d598d1e85ed7efb970dc98a31a74 Reviewed-by: Andy Shaw --- src/qmldebug/qqmlprofilerevent_p.h | 1 + 1 file changed, 1 insertion(+) diff --git a/src/qmldebug/qqmlprofilerevent_p.h b/src/qmldebug/qqmlprofilerevent_p.h index ef395c8507..54712c7dcc 100644 --- a/src/qmldebug/qqmlprofilerevent_p.h +++ b/src/qmldebug/qqmlprofilerevent_p.h @@ -48,6 +48,7 @@ #include #include +#include #include // -- cgit v1.2.3 From 73a620559749cb636766ae7f94a32e0cc7cdb6e7 Mon Sep 17 00:00:00 2001 From: Ulf Hermann Date: Mon, 3 May 2021 17:20:54 +0200 Subject: V4 debugger: Properly count break points We cannot just take the number of active breakpoints as ID for the next one. It's possible to remove breakpoints after all. Fixes: QTBUG-93404 Change-Id: Icde7a8e47c740e930f2313ffd9034b00033a54aa Reviewed-by: hjk Reviewed-by: Fabian Kosmale (cherry picked from commit 7f12cf3346d65d0bff78fff8000ed519fbb921ba) Reviewed-by: Qt Cherry-pick Bot --- .../qmldbg_debugger/qv4debuggeragent.cpp | 2 +- .../qmltooling/qmldbg_debugger/qv4debuggeragent.h | 1 + .../debugger/qqmldebugjs/data/breakPointIds.qml | 15 ++++ .../qml/debugger/qqmldebugjs/tst_qqmldebugjs.cpp | 89 +++++++++++++++++----- 4 files changed, 88 insertions(+), 19 deletions(-) create mode 100644 tests/auto/qml/debugger/qqmldebugjs/data/breakPointIds.qml diff --git a/src/plugins/qmltooling/qmldbg_debugger/qv4debuggeragent.cpp b/src/plugins/qmltooling/qmldbg_debugger/qv4debuggeragent.cpp index c74fd35ea2..710b2716d3 100644 --- a/src/plugins/qmltooling/qmldbg_debugger/qv4debuggeragent.cpp +++ b/src/plugins/qmltooling/qmldbg_debugger/qv4debuggeragent.cpp @@ -163,7 +163,7 @@ int QV4DebuggerAgent::addBreakPoint(const QString &fileName, int lineNumber, boo for (QV4Debugger *debugger : qAsConst(m_debuggers)) debugger->addBreakPoint(fileName, lineNumber, condition); - int id = m_breakPoints.size(); + const int id = ++m_lastBreakPointId; m_breakPoints.insert(id, BreakPoint(fileName, lineNumber, enabled, condition)); return id; } diff --git a/src/plugins/qmltooling/qmldbg_debugger/qv4debuggeragent.h b/src/plugins/qmltooling/qmldbg_debugger/qv4debuggeragent.h index ccaf76b269..58222deb58 100644 --- a/src/plugins/qmltooling/qmldbg_debugger/qv4debuggeragent.h +++ b/src/plugins/qmltooling/qmldbg_debugger/qv4debuggeragent.h @@ -93,6 +93,7 @@ private: }; QHash m_breakPoints; + int m_lastBreakPointId = 0; bool m_breakOnThrow; QV4DebugServiceImpl *m_debugService; }; diff --git a/tests/auto/qml/debugger/qqmldebugjs/data/breakPointIds.qml b/tests/auto/qml/debugger/qqmldebugjs/data/breakPointIds.qml new file mode 100644 index 0000000000..c3e7687831 --- /dev/null +++ b/tests/auto/qml/debugger/qqmldebugjs/data/breakPointIds.qml @@ -0,0 +1,15 @@ +import QtQml 2.15 +Timer { + Component.onCompleted: { + console.log('0') + console.log('1') + console.log('2') + console.log('3') + console.log('4') + console.log('5') + running = true + } + + interval: 0 + onTriggered: Qt.quit() +} diff --git a/tests/auto/qml/debugger/qqmldebugjs/tst_qqmldebugjs.cpp b/tests/auto/qml/debugger/qqmldebugjs/tst_qqmldebugjs.cpp index 91470e0651..59cab6eb75 100644 --- a/tests/auto/qml/debugger/qqmldebugjs/tst_qqmldebugjs.cpp +++ b/tests/auto/qml/debugger/qqmldebugjs/tst_qqmldebugjs.cpp @@ -65,6 +65,7 @@ const char *STEPACTION_QMLFILE = "stepAction.qml"; const char *BREAKPOINTRELOCATION_QMLFILE = "breakpointRelocation.qml"; const char *ENCODEQMLSCOPE_QMLFILE = "encodeQmlScope.qml"; const char *BREAKONANCHOR_QMLFILE = "breakOnAnchor.qml"; +const char *BREAKPOINTIDS_QMLFILE = "breakPointIds.qml"; #undef QVERIFY #define QVERIFY(statement) \ @@ -156,6 +157,8 @@ private slots: void encodeQmlScope(); void breakOnAnchor(); + void breakPointIds(); + private: ConnectResult init(bool qmlscene, const QString &qmlFile = QString(TEST_QMLFILE), bool blockMode = true, bool restrictServices = false); @@ -165,10 +168,11 @@ private: void targetData(); bool waitForClientSignal(const char *signal, int timeout = 30000); void checkVersionParameters(); + int setBreakPoint(const QString &file, int sourceLine, bool enabled); + void clearBreakPoint(int id); }; - void tst_QQmlDebugJS::initTestCase() { QQmlDebugTest::initTestCase(); @@ -566,7 +570,8 @@ void tst_QQmlDebugJS::changeBreakpoint() int sourceLine2 = 37; int sourceLine1 = 38; - QCOMPARE(init(qmlscene, CHANGEBREAKPOINT_QMLFILE), ConnectSuccess); + const QString file = QLatin1String(CHANGEBREAKPOINT_QMLFILE); + QCOMPARE(init(qmlscene, file), ConnectSuccess); bool isStopped = false; QObject::connect(m_client.data(), &QV4DebugClient::stopped, this, [&]() { isStopped = true; }); @@ -589,27 +594,13 @@ void tst_QQmlDebugJS::changeBreakpoint() return breakpointsHit[0].toInt(); }; - auto setBreakPoint = [&](int sourceLine, bool enabled) { - int id = -1; - auto connection = QObject::connect(m_client.data(), &QV4DebugClient::result, [&]() { - id = extractBody().value("breakpoint").toInt(); - }); - - m_client->setBreakpoint(QLatin1String(CHANGEBREAKPOINT_QMLFILE), sourceLine, -1, enabled); - bool success = QTest::qWaitFor([&]() { return id >= 0; }); - Q_UNUSED(success); - - QObject::disconnect(connection); - return id; - }; - //The breakpoints are in a timer loop so we can set them after connect(). //Furthermore the breakpoints should be hit in the right order because setting of breakpoints //can only occur in the QML event loop. (see QCOMPARE for sourceLine2 below) - const int breakpoint1 = setBreakPoint(sourceLine1, false); + const int breakpoint1 = setBreakPoint(file, sourceLine1, false); QVERIFY(breakpoint1 >= 0); - const int breakpoint2 = setBreakPoint(sourceLine2, true); + const int breakpoint2 = setBreakPoint(file, sourceLine2, true); QVERIFY(breakpoint2 >= 0); auto verifyBreakpoint = [&](int sourceLine, int breakpointId) { @@ -1026,6 +1017,39 @@ void tst_QQmlDebugJS::breakOnAnchor() QCOMPARE(breaks, 2); } +void tst_QQmlDebugJS::breakPointIds() +{ + QString file(BREAKPOINTIDS_QMLFILE); + QCOMPARE(init(true, file), ConnectSuccess); + + int breaks = 0; + int breakPointIds[] = { -1, -1, -1, -1, -1, -1}; + + QObject::connect(m_client.data(), &QV4DebugClient::stopped, this, [&]() { + const QJsonObject body = m_client->response().body.toObject(); + QCOMPARE(body.value("sourceLine").toInt(), breaks + 4); + const QJsonArray breakpointsHit = body.value("breakpoints").toArray(); + QVERIFY(breakpointsHit.size() > 0); + QCOMPARE(breakpointsHit[0].toInt(), breakPointIds[breaks]); + ++breaks; + m_client->continueDebugging(QV4DebugClient::Continue); + }); + + for (int i = 0; i < 6; ++i) + breakPointIds[i] = setBreakPoint(file, i + 4, true); + + clearBreakPoint(breakPointIds[2]); + breakPointIds[2] = setBreakPoint(file, 6, true); + + QTRY_COMPARE(m_process->state(), QProcess::Running); + m_client->connect(); + + QTRY_COMPARE(m_process->state(), QProcess::NotRunning); + QCOMPARE(m_process->exitStatus(), QProcess::NormalExit); + + QCOMPARE(breaks, 6); +} + QList tst_QQmlDebugJS::createClients() { m_client = new QV4DebugClient(m_connection); @@ -1054,6 +1078,35 @@ void tst_QQmlDebugJS::checkVersionParameters() QCOMPARE(body.value("ChangeBreakpoint").toBool(), true); } +int tst_QQmlDebugJS::setBreakPoint(const QString &file, int sourceLine, bool enabled) +{ + int id = -1; + auto connection = QObject::connect(m_client.data(), &QV4DebugClient::result, [&]() { + id = m_client->response().body.toObject().value("breakpoint").toInt(); + }); + + m_client->setBreakpoint(file, sourceLine, -1, enabled); + bool success = QTest::qWaitFor([&]() { return id >= 0; }); + Q_UNUSED(success); + + QObject::disconnect(connection); + return id; +} + +void tst_QQmlDebugJS::clearBreakPoint(int id) +{ + bool ok = false; + auto connection = QObject::connect(m_client.data(), &QV4DebugClient::result, [&]() { + ok = true; + }); + + m_client->clearBreakpoint(id); + bool success = QTest::qWaitFor([&]() { return ok; }); + Q_UNUSED(success); + + QObject::disconnect(connection); +} + QTEST_MAIN(tst_QQmlDebugJS) #include "tst_qqmldebugjs.moc" -- cgit v1.2.3 From 002fe9ee421223de9ddf7f4ed63df1002d9e9c51 Mon Sep 17 00:00:00 2001 From: Romain Pokrzywka Date: Wed, 25 Mar 2020 00:46:15 -0500 Subject: Avoid stale QSGTexture pointer accesses On rare occasions, it seems to be possible for the texture to be used after deletion, which results in crashes in pixmap() after casting. Rather than storing a raw pointer, wrap the texture in QPointer to avoid the stale pointer accesses. Task-number: QTBUG-80415 Change-Id: Ia0ee556f4a3a4eee777ca14065635f4bc5f90da2 Reviewed-by: Andy Nichols (cherry picked from commit 1c010b202506bb7eb0f0e24ab37ad50e319abada) Reviewed-by: Qt Cherry-pick Bot --- .../scenegraph/adaptations/software/qsgsoftwareinternalimagenode_p.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/quick/scenegraph/adaptations/software/qsgsoftwareinternalimagenode_p.h b/src/quick/scenegraph/adaptations/software/qsgsoftwareinternalimagenode_p.h index cd39edc11b..8fe4b5916a 100644 --- a/src/quick/scenegraph/adaptations/software/qsgsoftwareinternalimagenode_p.h +++ b/src/quick/scenegraph/adaptations/software/qsgsoftwareinternalimagenode_p.h @@ -54,6 +54,8 @@ #include #include +#include + QT_BEGIN_NAMESPACE namespace QSGSoftwareHelpers { @@ -132,7 +134,7 @@ private: QRectF m_innerSourceRect; QRectF m_subSourceRect; - QSGTexture *m_texture; + QPointer m_texture; QPixmap m_cachedMirroredPixmap; bool m_mirror; -- cgit v1.2.3 From 3001f62f4db8fcc4f5f6c0e96da0ef39cff92086 Mon Sep 17 00:00:00 2001 From: Shawn Rutledge Date: Mon, 3 May 2021 20:33:56 +0200 Subject: Make PinchArea translate correctly inside a rotated parent Fixes: QTBUG-63673 Change-Id: I91231bb8555b7eb02a9580f9f184b261d8bd44c8 Reviewed-by: Richard Moe Gustavsen (cherry picked from commit 7642205be45135add120373299df02e05f4ffc58) Reviewed-by: Shawn Rutledge --- src/quick/items/qquickpincharea.cpp | 8 ++- .../qquickpincharea/data/draggablePinchArea.qml | 70 ++++++++++++++++++++++ .../quick/qquickpincharea/tst_qquickpincharea.cpp | 66 ++++++++++++++++++++ 3 files changed, 143 insertions(+), 1 deletion(-) create mode 100644 tests/auto/quick/qquickpincharea/data/draggablePinchArea.qml diff --git a/src/quick/items/qquickpincharea.cpp b/src/quick/items/qquickpincharea.cpp index e87ed949d1..994bdc54a9 100644 --- a/src/quick/items/qquickpincharea.cpp +++ b/src/quick/items/qquickpincharea.cpp @@ -556,7 +556,10 @@ void QQuickPinchArea::updatePinch() d->inPinch = true; d->stealMouse = true; if (d->pinch && d->pinch->target()) { - d->pinchStartPos = pinch()->target()->position(); + auto targetParent = pinch()->target()->parentItem(); + d->pinchStartPos = targetParent ? + targetParent->mapToScene(pinch()->target()->position()) : + pinch()->target()->position(); d->pinchStartScale = d->pinch->target()->scale(); d->pinchStartRotation = d->pinch->target()->rotation(); d->pinch->setActive(true); @@ -604,6 +607,9 @@ void QQuickPinchArea::updatePinchTarget() s = qMin(qMax(pinch()->minimumScale(),s), pinch()->maximumScale()); pinch()->target()->setScale(s); QPointF pos = d->sceneLastCenter - d->sceneStartCenter + d->pinchStartPos; + if (auto targetParent = pinch()->target()->parentItem()) + pos = targetParent->mapFromScene(pos); + if (pinch()->axis() & QQuickPinch::XAxis) { qreal x = pos.x(); if (x < pinch()->xmin()) diff --git a/tests/auto/quick/qquickpincharea/data/draggablePinchArea.qml b/tests/auto/quick/qquickpincharea/data/draggablePinchArea.qml new file mode 100644 index 0000000000..3acf67b4b6 --- /dev/null +++ b/tests/auto/quick/qquickpincharea/data/draggablePinchArea.qml @@ -0,0 +1,70 @@ +import QtQuick 2.12 + +Rectangle { + id: root + width: 600 + height: 600 + + Rectangle { + objectName: "paContainer" + width: parent.width -100 + height: parent.height - 100 + border.color: "black" + anchors.centerIn: parent + transformOrigin: Item.Center + + Rectangle { + width: 300 + height: 300 + color: "tomato" + PinchArea { + id: pa + anchors.fill: parent + pinch.target: parent + pinch.minimumScale: 0.5 + pinch.maximumScale: 2 + pinch.minimumRotation: -360 + pinch.maximumRotation: 360 + pinch.dragAxis: Pinch.XAndYAxis + pinch.minimumX: -100 + pinch.maximumX: 300 + pinch.minimumY: -100 + pinch.maximumY: 300 + } + + + Text { text: "this way up" } + } + } + + // only for touch feedback / troubleshooting + Item { + id: glassPane + z: 10000 + anchors.fill: parent + + PointHandler { + id: ph1 + target: Rectangle { + parent: glassPane + color: "green" + visible: ph1.active + x: ph1.point.position.x - width / 2 + y: ph1.point.position.y - height / 2 + width: 20; height: width; radius: width / 2 + } + } + + PointHandler { + id: ph2 + target: Rectangle { + parent: glassPane + color: "blue" + visible: ph2.active + x: ph2.point.position.x - width / 2 + y: ph2.point.position.y - height / 2 + width: 20; height: width; radius: width / 2 + } + } + } +} diff --git a/tests/auto/quick/qquickpincharea/tst_qquickpincharea.cpp b/tests/auto/quick/qquickpincharea/tst_qquickpincharea.cpp index 5b7108d96b..367df96118 100644 --- a/tests/auto/quick/qquickpincharea/tst_qquickpincharea.cpp +++ b/tests/auto/quick/qquickpincharea/tst_qquickpincharea.cpp @@ -52,6 +52,8 @@ private slots: void cancel(); void transformedPinchArea_data(); void transformedPinchArea(); + void dragTransformedPinchArea_data(); + void dragTransformedPinchArea(); private: QQuickView *createView(); @@ -586,6 +588,70 @@ void tst_QQuickPinchArea::transformedPinchArea() } } +void tst_QQuickPinchArea::dragTransformedPinchArea_data() +{ + QTest::addColumn("rotation"); + QTest::addColumn("p1"); + QTest::addColumn("p2"); + QTest::addColumn("delta"); + + QTest::newRow("unrotated") + << 0 << QPoint(100, 100) << QPoint(200, 100) << QPoint(40, 40); + QTest::newRow("20 deg") + << 20 << QPoint(100, 100) << QPoint(200, 100) << QPoint(40, 40); + QTest::newRow("90 deg") + << 90 << QPoint(100, 100) << QPoint(200, 100) << QPoint(0, 40); + QTest::newRow("180 deg") + << 180 << QPoint(100, 100) << QPoint(200, 100) << QPoint(40, 0); + QTest::newRow("225 deg") + << 210 << QPoint(200, 200) << QPoint(300, 200) << QPoint(80, 80); +} + +void tst_QQuickPinchArea::dragTransformedPinchArea() // QTBUG-63673 +{ + QFETCH(int, rotation); + QFETCH(QPoint, p1); + QFETCH(QPoint, p2); + QFETCH(QPoint, delta); + const int threshold = qApp->styleHints()->startDragDistance(); + + QQuickView *view = createView(); + QScopedPointer scope(view); + view->setSource(testFileUrl("draggablePinchArea.qml")); + view->show(); + QVERIFY(QTest::qWaitForWindowExposed(view)); + QVERIFY(view->rootObject()); + QQuickPinchArea *pinchArea = view->rootObject()->findChild(); + QVERIFY(pinchArea); + QQuickItem *pinchAreaTarget = pinchArea->parentItem(); + QVERIFY(pinchAreaTarget); + QQuickItem *pinchAreaContainer = pinchAreaTarget->parentItem(); + QVERIFY(pinchAreaContainer); + pinchAreaContainer->setRotation(rotation); + + QTest::QTouchEventSequence pinchSequence = QTest::touchEvent(view, device); + // start pinch + pinchSequence.press(1, pinchArea->mapToScene(p1).toPoint(), view) + .press(2, pinchArea->mapToScene(p2).toPoint(), view).commit(); + QQuickTouchUtils::flush(view); + pinchSequence.move(1, pinchArea->mapToScene(p1 + QPoint(threshold, threshold)).toPoint(), view) + .move(2, pinchArea->mapToScene(p2 + QPoint(threshold, threshold)).toPoint(), view).commit(); + QQuickTouchUtils::flush(view); + pinchSequence.move(1, pinchArea->mapToScene(p1 + delta).toPoint(), view) + .move(2, pinchArea->mapToScene(p2 + delta).toPoint(), view).commit(); + QQuickTouchUtils::flush(view); + QCOMPARE(pinchArea->pinch()->active(), true); + auto error = delta - QPoint(threshold, threshold) - + pinchAreaTarget->position().toPoint(); // expect 0, 0 + QVERIFY(qAbs(error.x()) <= 1); + QVERIFY(qAbs(error.y()) <= 1); + + // release pinch + pinchSequence.release(1, p1, view).release(2, p2, view).commit(); + QQuickTouchUtils::flush(view); + QCOMPARE(pinchArea->pinch()->active(), false); +} + QQuickView *tst_QQuickPinchArea::createView() { QQuickView *window = new QQuickView(nullptr); -- cgit v1.2.3 From 6ce50ad548aad6caca815b3058ee1a2be923344f Mon Sep 17 00:00:00 2001 From: Ulf Hermann Date: Mon, 3 May 2021 19:23:49 +0200 Subject: V4 Debugger: Collect locals also from block scopes Block scopes can contain "const" and "let" members. Fixes: QTBUG-92224 Change-Id: Ie13d7d573e2759c510e1ea48c6edc68a095f40a0 Reviewed-by: Fabian Kosmale (cherry picked from commit 051dd3178bc4c9214af60c69cecfc2c28f13174d) --- .../qmldbg_debugger/qv4datacollector.cpp | 3 +- .../debugger/qqmldebugjs/data/letConstLocals.qml | 16 ++++++ .../qml/debugger/qqmldebugjs/tst_qqmldebugjs.cpp | 59 ++++++++++++++++++++++ .../qml/debugger/qv4debugger/tst_qv4debugger.cpp | 12 ++++- 4 files changed, 87 insertions(+), 3 deletions(-) create mode 100644 tests/auto/qml/debugger/qqmldebugjs/data/letConstLocals.qml diff --git a/src/plugins/qmltooling/qmldbg_debugger/qv4datacollector.cpp b/src/plugins/qmltooling/qmldbg_debugger/qv4datacollector.cpp index 74077abeb4..4cf72b62c6 100644 --- a/src/plugins/qmltooling/qmldbg_debugger/qv4datacollector.cpp +++ b/src/plugins/qmltooling/qmldbg_debugger/qv4datacollector.cpp @@ -216,7 +216,8 @@ bool QV4DataCollector::collectScope(QJsonObject *dict, int frameNr, int scopeNr) return false; QV4::ScopedObject scopeObject(scope, engine()->newObject()); - if (ctxt->d()->type == QV4::Heap::ExecutionContext::Type_CallContext) { + if (ctxt->d()->type == QV4::Heap::ExecutionContext::Type_CallContext || + ctxt->d()->type == QV4::Heap::ExecutionContext::Type_BlockContext) { QStringList names; Refs collectedRefs; diff --git a/tests/auto/qml/debugger/qqmldebugjs/data/letConstLocals.qml b/tests/auto/qml/debugger/qqmldebugjs/data/letConstLocals.qml new file mode 100644 index 0000000000..1715992490 --- /dev/null +++ b/tests/auto/qml/debugger/qqmldebugjs/data/letConstLocals.qml @@ -0,0 +1,16 @@ +import QtQml 2.15 + +Timer { + Component.onCompleted: { + var a = 97 + var b = 98 + var c = 99 + let d = 100 + const e = 101 + console.log("onClicked") // Set breakpoint + running = true + } + + interval: 0 + onTriggered: Qt.quit() +} diff --git a/tests/auto/qml/debugger/qqmldebugjs/tst_qqmldebugjs.cpp b/tests/auto/qml/debugger/qqmldebugjs/tst_qqmldebugjs.cpp index 59cab6eb75..43c81ee515 100644 --- a/tests/auto/qml/debugger/qqmldebugjs/tst_qqmldebugjs.cpp +++ b/tests/auto/qml/debugger/qqmldebugjs/tst_qqmldebugjs.cpp @@ -66,6 +66,7 @@ const char *BREAKPOINTRELOCATION_QMLFILE = "breakpointRelocation.qml"; const char *ENCODEQMLSCOPE_QMLFILE = "encodeQmlScope.qml"; const char *BREAKONANCHOR_QMLFILE = "breakOnAnchor.qml"; const char *BREAKPOINTIDS_QMLFILE = "breakPointIds.qml"; +const char *LETCONSTLOCALS_QMLFILE = "letConstLocals.qml"; #undef QVERIFY #define QVERIFY(statement) \ @@ -158,6 +159,7 @@ private slots: void breakOnAnchor(); void breakPointIds(); + void letConstLocals(); private: ConnectResult init(bool qmlscene, const QString &qmlFile = QString(TEST_QMLFILE), @@ -1050,6 +1052,63 @@ void tst_QQmlDebugJS::breakPointIds() QCOMPARE(breaks, 6); } +void tst_QQmlDebugJS::letConstLocals() +{ + QString file(LETCONSTLOCALS_QMLFILE); + QCOMPARE(init(true, file), ConnectSuccess); + + QObject::connect(m_client.data(), &QV4DebugClient::stopped, this, [&]() { + m_client->frame(); + }); + + int numScopes = 0; + QString expectedMembers = QStringLiteral("abcde"); + QObject::connect(m_client.data(), &QV4DebugClient::result, this, [&]() { + const auto value = m_client->response(); + if (value.command == QStringLiteral("frame")) { + const auto scopes = value.body.toObject().value(QStringLiteral("scopes")).toArray(); + for (const auto &scope : scopes) { + const auto scopeObject = scope.toObject(); + const int type = scopeObject.value("type").toInt(); + if (type == 1 || type == 4) { + m_client->scope(scopeObject.value("index").toInt()); + ++numScopes; + } + } + QVERIFY(numScopes > 0); + } else if (value.command == QStringLiteral("scope")) { + const auto props = value.body.toObject().value(QStringLiteral("object")).toObject() + .value(QStringLiteral("properties")).toArray(); + for (const auto &prop : props) { + const auto propObj = prop.toObject(); + const QString name = propObj.value(QStringLiteral("name")).toString(); + if (name == QStringLiteral("onCompleted")) + continue; + QVERIFY(name.length() == 1); + auto i = expectedMembers.indexOf(name.at(0)); + QVERIFY(i != -1); + expectedMembers.remove(i, 1); + QCOMPARE(propObj.value(QStringLiteral("type")).toString(), + QStringLiteral("number")); + QCOMPARE(propObj.value(QStringLiteral("value")).toInt(), + int(name.at(0).toLatin1())); + } + if (--numScopes == 0) { + QVERIFY(expectedMembers.isEmpty()); + m_client->continueDebugging(QV4DebugClient::Continue); + } + } + }); + + setBreakPoint(file, 10, true); + + QTRY_COMPARE(m_process->state(), QProcess::Running); + m_client->connect(); + + QTRY_COMPARE(m_process->state(), QProcess::NotRunning); + QCOMPARE(m_process->exitStatus(), QProcess::NormalExit); +} + QList tst_QQmlDebugJS::createClients() { m_client = new QV4DebugClient(m_connection); diff --git a/tests/auto/qml/debugger/qv4debugger/tst_qv4debugger.cpp b/tests/auto/qml/debugger/qv4debugger/tst_qv4debugger.cpp index e3cbeb9891..e4e7728508 100644 --- a/tests/auto/qml/debugger/qv4debugger/tst_qv4debugger.cpp +++ b/tests/auto/qml/debugger/qv4debugger/tst_qv4debugger.cpp @@ -575,21 +575,29 @@ void tst_qv4debugger::readLocals() QString script = "var f = function(a, b) {\n" " var c = a + b\n" + " let e = 'jaja'\n" + " const ff = 'nenene'\n" " var d = a - b\n" // breakpoint, c should be set, d should be undefined " return c === d\n" "}\n" "f(1, 2, 3);\n"; - debugger()->addBreakPoint("readLocals", 3); + debugger()->addBreakPoint("readLocals", 5); evaluateJavaScript(script, "readLocals"); QVERIFY(m_debuggerAgent->m_wasPaused); QVERIFY(m_debuggerAgent->m_capturedScope.size() > 1); const TestAgent::NamedRefs &frame0 = m_debuggerAgent->m_capturedScope.at(0); - QCOMPARE(frame0.size(), 5); // locals and parameters + QCOMPARE(frame0.size(), 7); // locals and parameters QVERIFY(frame0.contains("c")); QCOMPARE(frame0.type("c"), QStringLiteral("number")); QCOMPARE(frame0.value("c").toDouble(), 3.0); QVERIFY(frame0.contains("d")); QCOMPARE(frame0.type("d"), QStringLiteral("undefined")); + QVERIFY(frame0.contains("e")); + QCOMPARE(frame0.type("e"), QStringLiteral("string")); + QCOMPARE(frame0.value("e").toString(), QStringLiteral("jaja")); + QVERIFY(frame0.contains("ff")); + QCOMPARE(frame0.type("ff"), QStringLiteral("string")); + QCOMPARE(frame0.value("ff").toString(), QStringLiteral("nenene")); } void tst_qv4debugger::readObject() -- cgit v1.2.3 From 54873d967a22343a36e7b8c02aa32f4061adf1e3 Mon Sep 17 00:00:00 2001 From: Richard Moe Gustavsen Date: Thu, 6 May 2021 11:20:53 +0200 Subject: qquicktableview: upon forceLayout(), check for visible rows/columns at the origin There is a bug in TableView which will stop the user from scrolling/flicking back to the first column if it has become visible after first being hidden. The reason is that this is somewhat of a special case that happens only if the current left column is already at the origin of the viewport, since that will fool tableview into thinking that there can be no more columns in front of it. This patch add an extra section to the function that checks for visibility changes, to detect this special case. Fixes: QTBUG-93264 Change-Id: Ieaad507b45ea11dc231519e9f49cbf182d6443ba Reviewed-by: Mitch Curtis (cherry picked from commit 546df684e272bbbc5e8b871ae9b224fdb34a4cfa) Reviewed-by: Qt Cherry-pick Bot --- src/quick/items/qquicktableview.cpp | 78 +++++++++++++--------- .../quick/qquicktableview/tst_qquicktableview.cpp | 78 ++++++++++++++++++++++ 2 files changed, 126 insertions(+), 30 deletions(-) diff --git a/src/quick/items/qquicktableview.cpp b/src/quick/items/qquicktableview.cpp index 652050b5ec..7fc6b6572d 100644 --- a/src/quick/items/qquicktableview.cpp +++ b/src/quick/items/qquicktableview.cpp @@ -958,43 +958,61 @@ QQuickTableViewPrivate::RebuildOptions QQuickTableViewPrivate::checkForVisibilit return RebuildOption::None; } - // Go through all columns from first to last, find the columns that used - // to be hidden and not loaded, and check if they should become visible - // (and vice versa). If there is a change, we need to rebuild. RebuildOptions rebuildOptions = RebuildOption::None; - for (int column = leftColumn(); column <= rightColumn(); ++column) { - const bool wasVisibleFromBefore = loadedColumns.contains(column); - const bool isVisibleNow = !qFuzzyIsNull(getColumnWidth(column)); - if (wasVisibleFromBefore == isVisibleNow) - continue; - - // A column changed visibility. This means that it should - // either be loaded or unloaded. So we need a rebuild. - qCDebug(lcTableViewDelegateLifecycle) << "Column" << column << "changed visibility to" << isVisibleNow; + if (loadedTableOuterRect.x() == origin.x() && leftColumn() != 0) { + // Since the left column is at the origin of the viewport, but still not the first + // column in the model, we need to calculate a new left column since there might be + // columns in front of it that used to be hidden, but should now be visible (QTBUG-93264). rebuildOptions.setFlag(RebuildOption::ViewportOnly); - if (column == leftColumn()) { - // The first loaded column should now be hidden. This means that we - // need to calculate which column should now be first instead. - rebuildOptions.setFlag(RebuildOption::CalculateNewTopLeftColumn); + rebuildOptions.setFlag(RebuildOption::CalculateNewTopLeftColumn); + } else { + // Go through all loaded columns from first to last, find the columns that used + // to be hidden and not loaded, and check if they should become visible + // (and vice versa). If there is a change, we need to rebuild. + for (int column = leftColumn(); column <= rightColumn(); ++column) { + const bool wasVisibleFromBefore = loadedColumns.contains(column); + const bool isVisibleNow = !qFuzzyIsNull(getColumnWidth(column)); + if (wasVisibleFromBefore == isVisibleNow) + continue; + + // A column changed visibility. This means that it should + // either be loaded or unloaded. So we need a rebuild. + qCDebug(lcTableViewDelegateLifecycle) << "Column" << column << "changed visibility to" << isVisibleNow; + rebuildOptions.setFlag(RebuildOption::ViewportOnly); + if (column == leftColumn()) { + // The first loaded column should now be hidden. This means that we + // need to calculate which column should now be first instead. + rebuildOptions.setFlag(RebuildOption::CalculateNewTopLeftColumn); + } + break; } - break; } - // Go through all rows from first to last, and do the same as above - for (int row = topRow(); row <= bottomRow(); ++row) { - const bool wasVisibleFromBefore = loadedRows.contains(row); - const bool isVisibleNow = !qFuzzyIsNull(getRowHeight(row)); - if (wasVisibleFromBefore == isVisibleNow) - continue; - - // A row changed visibility. This means that it should - // either be loaded or unloaded. So we need a rebuild. - qCDebug(lcTableViewDelegateLifecycle) << "Row" << row << "changed visibility to" << isVisibleNow; + if (loadedTableOuterRect.y() == origin.y() && topRow() != 0) { + // Since the top row is at the origin of the viewport, but still not the first + // row in the model, we need to calculate a new top row since there might be + // rows in front of it that used to be hidden, but should now be visible (QTBUG-93264). rebuildOptions.setFlag(RebuildOption::ViewportOnly); - if (row == topRow()) - rebuildOptions.setFlag(RebuildOption::CalculateNewTopLeftRow); - break; + rebuildOptions.setFlag(RebuildOption::CalculateNewTopLeftRow); + } else { + // Go through all loaded rows from first to last, find the rows that used + // to be hidden and not loaded, and check if they should become visible + // (and vice versa). If there is a change, we need to rebuild. + for (int row = topRow(); row <= bottomRow(); ++row) { + const bool wasVisibleFromBefore = loadedRows.contains(row); + const bool isVisibleNow = !qFuzzyIsNull(getRowHeight(row)); + if (wasVisibleFromBefore == isVisibleNow) + continue; + + // A row changed visibility. This means that it should + // either be loaded or unloaded. So we need a rebuild. + qCDebug(lcTableViewDelegateLifecycle) << "Row" << row << "changed visibility to" << isVisibleNow; + rebuildOptions.setFlag(RebuildOption::ViewportOnly); + if (row == topRow()) + rebuildOptions.setFlag(RebuildOption::CalculateNewTopLeftRow); + break; + } } return rebuildOptions; diff --git a/tests/auto/quick/qquicktableview/tst_qquicktableview.cpp b/tests/auto/quick/qquicktableview/tst_qquicktableview.cpp index d14c37d8e3..6d37fb44e3 100644 --- a/tests/auto/quick/qquicktableview/tst_qquicktableview.cpp +++ b/tests/auto/quick/qquicktableview/tst_qquicktableview.cpp @@ -169,6 +169,8 @@ private slots: void checkTableviewInsideAsyncLoader(); void hideRowsAndColumns_data(); void hideRowsAndColumns(); + void hideAndShowFirstColumn(); + void hideAndShowFirstRow(); void checkThatRevisionedPropertiesCannotBeUsedInOldImports(); void checkSyncView_rootView_data(); void checkSyncView_rootView(); @@ -2413,6 +2415,82 @@ void tst_QQuickTableView::hideRowsAndColumns() QVERIFY(!columnsToHideList.contains(column)); } +void tst_QQuickTableView::hideAndShowFirstColumn() +{ + // Check that if we hide the first column, it will move + // the second column to the origin of the viewport. Then check + // that if we show the first column again, it will reappear at + // the origin of the viewport, and as such, pushing the second + // column to the right of it. + LOAD_TABLEVIEW("hiderowsandcolumns.qml"); + + const int modelSize = 5; + auto model = TestModelAsVariant(modelSize, modelSize); + tableView->setModel(model); + + // Start by making the first column hidden + const auto columnsToHideList = QList() << 0; + view->rootObject()->setProperty("columnsToHide", QVariant::fromValue(columnsToHideList)); + + WAIT_UNTIL_POLISHED; + + const int expectedColumnCount = modelSize - columnsToHideList.count(); + QCOMPARE(tableViewPrivate->loadedColumns.count(), expectedColumnCount); + QCOMPARE(tableViewPrivate->leftColumn(), 1); + QCOMPARE(tableView->contentX(), 0); + QCOMPARE(tableViewPrivate->loadedTableOuterRect.x(), 0); + + // Make the first column in the model visible again + const auto emptyList = QList(); + view->rootObject()->setProperty("columnsToHide", QVariant::fromValue(emptyList)); + tableView->forceLayout(); + + WAIT_UNTIL_POLISHED; + + QCOMPARE(tableViewPrivate->loadedColumns.count(), modelSize); + QCOMPARE(tableViewPrivate->leftColumn(), 0); + QCOMPARE(tableView->contentX(), 0); + QCOMPARE(tableViewPrivate->loadedTableOuterRect.x(), 0); +} + +void tst_QQuickTableView::hideAndShowFirstRow() +{ + // Check that if we hide the first row, it will move + // the second row to the origin of the viewport. Then check + // that if we show the first row again, it will reappear at + // the origin of the viewport, and as such, pushing the second + // row below it. + LOAD_TABLEVIEW("hiderowsandcolumns.qml"); + + const int modelSize = 5; + auto model = TestModelAsVariant(modelSize, modelSize); + tableView->setModel(model); + + // Start by making the first row hidden + const auto rowsToHideList = QList() << 0; + view->rootObject()->setProperty("rowsToHide", QVariant::fromValue(rowsToHideList)); + + WAIT_UNTIL_POLISHED; + + const int expectedRowsCount = modelSize - rowsToHideList.count(); + QCOMPARE(tableViewPrivate->loadedRows.count(), expectedRowsCount); + QCOMPARE(tableViewPrivate->topRow(), 1); + QCOMPARE(tableView->contentY(), 0); + QCOMPARE(tableViewPrivate->loadedTableOuterRect.y(), 0); + + // Make the first row in the model visible again + const auto emptyList = QList(); + view->rootObject()->setProperty("rowsToHide", QVariant::fromValue(emptyList)); + tableView->forceLayout(); + + WAIT_UNTIL_POLISHED; + + QCOMPARE(tableViewPrivate->loadedRows.count(), modelSize); + QCOMPARE(tableViewPrivate->topRow(), 0); + QCOMPARE(tableView->contentY(), 0); + QCOMPARE(tableViewPrivate->loadedTableOuterRect.y(), 0); +} + void tst_QQuickTableView::checkThatRevisionedPropertiesCannotBeUsedInOldImports() { // Check that if you use a QQmlAdaptorModel together with a Repeater, the -- cgit v1.2.3 From cd45937c2420e063346867b987ac47651511601c Mon Sep 17 00:00:00 2001 From: Shawn Rutledge Date: Thu, 6 May 2021 16:30:24 +0200 Subject: TextEdit: update all glyphnodes on QTD::contentsChanged() signal When a syntax highlighter changes formatting, the actual text doesn't change, and QTextDocument emits contentsChanged() but not contentsChange(int, int, int). We need to regenerate QSG nodes. contentsChanged() is connected to QQuickTextControl::textChanged() and from there to QQuickTextEdit::q_textChanged(). Fixes: QTBUG-74572 Change-Id: Ia62aa6d3adfc9a9d496ee8811db4c2d963dd0c54 Reviewed-by: Allan Sandfeld Jensen (cherry picked from commit d0ffa3c42bb58eef0d2a2c3326984695a60e9667) Reviewed-by: Qt Cherry-pick Bot --- src/quick/items/qquicktextedit.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/quick/items/qquicktextedit.cpp b/src/quick/items/qquicktextedit.cpp index 2db2989e36..2d0402a9c2 100644 --- a/src/quick/items/qquicktextedit.cpp +++ b/src/quick/items/qquicktextedit.cpp @@ -2359,6 +2359,14 @@ void QQuickTextEdit::q_textChanged() d->determineHorizontalAlignment(); d->updateDefaultTextOption(); updateSize(); + + markDirtyNodesForRange(0, d->document->characterCount(), 0); + polish(); + if (isComponentComplete()) { + d->updateType = QQuickTextEditPrivate::UpdatePaintNode; + update(); + } + emit textChanged(); } -- cgit v1.2.3 From 64c22f1691ff78e538800e1715da3488ba9e1baf Mon Sep 17 00:00:00 2001 From: Fabian Kosmale Date: Thu, 6 May 2021 16:52:57 +0200 Subject: MASM: Put pageSize into an inline namespace MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Apple errorneously detects pagesize as belonging to their private API. Avoid this by putting the functions into an inline namespace to change their mangling. Fixes: QTBUG-69577 Change-Id: I061febdc6f961fa8a6e1d43de4154a8e26b04f27 Reviewed-by: Tor Arne Vestbø (cherry picked from commit 719fa10c8219537187f2e3c63eacdf44bd76d410) Reviewed-by: Qt Cherry-pick Bot --- src/3rdparty/masm/wtf/PageBlock.cpp | 2 ++ src/3rdparty/masm/wtf/PageBlock.h | 5 +++++ 2 files changed, 7 insertions(+) diff --git a/src/3rdparty/masm/wtf/PageBlock.cpp b/src/3rdparty/masm/wtf/PageBlock.cpp index e715ed262a..bc0e8d6f2d 100644 --- a/src/3rdparty/masm/wtf/PageBlock.cpp +++ b/src/3rdparty/masm/wtf/PageBlock.cpp @@ -64,6 +64,7 @@ inline size_t systemPageSize() #endif +inline namespace hidden { size_t pageSize() { if (!s_pageSize) @@ -78,5 +79,6 @@ size_t pageMask() s_pageMask = ~(pageSize() - 1); return s_pageMask; } +} } // namespace WTF diff --git a/src/3rdparty/masm/wtf/PageBlock.h b/src/3rdparty/masm/wtf/PageBlock.h index 09e4048239..d85c39cb33 100644 --- a/src/3rdparty/masm/wtf/PageBlock.h +++ b/src/3rdparty/masm/wtf/PageBlock.h @@ -28,8 +28,13 @@ namespace WTF { +// avoid false positive detection by apple +// by putting the function inside an inline namespace +// to obtain different name mangling +inline namespace hidden { WTF_EXPORT_PRIVATE size_t pageSize(); WTF_EXPORT_PRIVATE size_t pageMask(); +} inline bool isPageAligned(void* address) { return !(reinterpret_cast(address) & (pageSize() - 1)); } inline bool isPageAligned(size_t size) { return !(size & (pageSize() - 1)); } inline bool isPowerOfTwo(size_t size) { return !(size & (size - 1)); } -- cgit v1.2.3 From a6705dc99a81b7eab35db61957963d375e723fce Mon Sep 17 00:00:00 2001 From: Laszlo Agocs Date: Wed, 5 May 2021 18:29:46 +0200 Subject: Do full overlap checks within the alpha render list when rebuilding Not applicable to Qt 6.1 and newer because those already have this as part of another patch (9aa3db2e19b2e1622b878cf34b1978f4fdbcac39), which was meant to be a performance optimization. With the example provided it is clear however that there is an actual batching problem in there, with certain scenes, where the problem of incorrectly batching two elements together becomes visible only upon a set of conditions such as: - there is a set of mergeable and non-mergeable nodes (e.g. non-atlased Images + Rectangles or non-atlased Images + Texts) - all in the alpha render list (semi-transparency, e.g. Image with alpha, Text, Rectangle with opacity, etc.) - laid out in a certain way that certain overlaps occur, e.g. in a column with the Images under each other, with Rectangles or Texts on top of the last two. - then trigger certain scene changes, e.g. swap the source of the second and third Image. Certain changes will end up with the incorrect merging described in the render_AlphaOverlapRebuild.qml test case. If the two Rectangles or Texts get merged in one batch, rendered before the third Image, the result is incorrect since the "background" Image is then on top. This can be difficult to reproduce as there are a number of preconditions for the scene and the changes in the scene. But when it happens, it is a critical rendering error. Fixes: QTBUG-92984 Change-Id: I016614d8465f6917ebf6c7d9b2460a31decdda34 Reviewed-by: Eskil Abrahamsen Blomfeldt --- src/quick/scenegraph/coreapi/qsgbatchrenderer.cpp | 6 +- .../scenegraph/data/render_AlphaOverlapRebuild.qml | 115 +++++++++++++++++++++ tests/auto/quick/scenegraph/data/widebtn1.png | Bin 0 -> 1969 bytes tests/auto/quick/scenegraph/data/widebtn2.png | Bin 0 -> 1965 bytes tests/auto/quick/scenegraph/tst_scenegraph.cpp | 4 +- 5 files changed, 122 insertions(+), 3 deletions(-) create mode 100644 tests/auto/quick/scenegraph/data/render_AlphaOverlapRebuild.qml create mode 100644 tests/auto/quick/scenegraph/data/widebtn1.png create mode 100644 tests/auto/quick/scenegraph/data/widebtn2.png diff --git a/src/quick/scenegraph/coreapi/qsgbatchrenderer.cpp b/src/quick/scenegraph/coreapi/qsgbatchrenderer.cpp index 024c0d68ef..e6c2c1b573 100644 --- a/src/quick/scenegraph/coreapi/qsgbatchrenderer.cpp +++ b/src/quick/scenegraph/coreapi/qsgbatchrenderer.cpp @@ -1878,7 +1878,7 @@ bool Renderer::checkOverlap(int first, int last, const Rect &bounds) { for (int i=first; i<=last; ++i) { Element *e = m_alphaRenderList.at(i); - if (!e || e->batch) + if (!e) continue; Q_ASSERT(e->boundsComputed); if (e->bounds.intersects(bounds)) @@ -1949,8 +1949,10 @@ void Renderer::prepareAlphaBatches() continue; if (ej->root != ei->root || ej->isRenderNode) break; - if (ej->batch) + if (ej->batch) { + overlapBounds |= ej->bounds; continue; + } QSGGeometryNode *gnj = ej->node; if (gnj->geometry()->vertexCount() == 0) diff --git a/tests/auto/quick/scenegraph/data/render_AlphaOverlapRebuild.qml b/tests/auto/quick/scenegraph/data/render_AlphaOverlapRebuild.qml new file mode 100644 index 0000000000..f06be8f553 --- /dev/null +++ b/tests/auto/quick/scenegraph/data/render_AlphaOverlapRebuild.qml @@ -0,0 +1,115 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:GPL-EXCEPT$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.15 + +/* + QTBUG-92984. + + Have three Image (with semi-transparency) and two semi-transparent + Rectangle elements, and so all in the alpha render list, with images that + are big enough to not get atlased. (meaning the underlying nodes never get + merged, but the nodes for the Rectangle elements might) + + Lay them out vertically below each other, with the two Rectangles on top of + the second and third Images, respectively. Then change (swap) the source + property of the Images. This triggers a rebuild in the batch renderer. + + Verify that the results are still correct, i.e. that the two Rectangle + elements do not get merged. An incorrect result would be having the third + Image rendered on top of the corresponding Rectangle due the two Rectangles + (incorrectly) being in one merged batch. The Image should always be below, + regardless of which nodes get changed, invalidated, and how batches get + rebuilt. + + The base-final sample set 1 just verifies that the Image changes from the + blueish to greenish. The important part is the second set of samples: this + checks that the red(ish) rectangle is still on top of the third Image. With + incorrect merging behavior the second final result would be the same as the + first final one (i.e. the "background" Image rendered, incorrectly, on top + of the Rectangle). + + #samples: 4 + PixelPos R G B Error-tolerance + #base: 30 115 0.24313 0.30588 0.99607 0.05 + #base: 30 124 0.847059 0.062745 0.2 0.05 + #final: 30 115 0.36078 0.99607 0.42745 0.05 + #final: 30 124 0.870588 0.2 0.0862745 0.05 +*/ + +RenderTestBase { + id: root + + property string selectedItem: "item2" + + Item { + width: 150; height: 50 + Image { + width: parent.width + objectName: "item1" + source: "widebtn1.png" + } + } + + Item { + y: 50; width: 150; height: 50 + Image { + width: parent.width + objectName: "item2" + source: selectedItem == objectName ? "widebtn2.png" : "widebtn1.png" + } + Rectangle { + anchors.fill: parent + anchors.margins: 20 + color: "red" + opacity: 0.8 + } + } + + Item { + y: 100; width: 150; height: 50 + Image { + id: img3 + width: parent.width + objectName: "item3" + source: selectedItem == objectName ? "widebtn2.png" : "widebtn1.png" + } + Rectangle { + width: parent.width + 50 + anchors.centerIn: parent + height: img3.height - 40 + color: "red" + opacity: 0.8 + } + } + + onEnterFinalStage: { + selectedItem = "item3"; + finalStageComplete = true; + } +} diff --git a/tests/auto/quick/scenegraph/data/widebtn1.png b/tests/auto/quick/scenegraph/data/widebtn1.png new file mode 100644 index 0000000000..1150b67a7a Binary files /dev/null and b/tests/auto/quick/scenegraph/data/widebtn1.png differ diff --git a/tests/auto/quick/scenegraph/data/widebtn2.png b/tests/auto/quick/scenegraph/data/widebtn2.png new file mode 100644 index 0000000000..40afe08363 Binary files /dev/null and b/tests/auto/quick/scenegraph/data/widebtn2.png differ diff --git a/tests/auto/quick/scenegraph/tst_scenegraph.cpp b/tests/auto/quick/scenegraph/tst_scenegraph.cpp index 12f7efb7d5..cf85e262c0 100644 --- a/tests/auto/quick/scenegraph/tst_scenegraph.cpp +++ b/tests/auto/quick/scenegraph/tst_scenegraph.cpp @@ -402,7 +402,9 @@ void tst_SceneGraph::render_data() << "render_StackingOrder.qml" << "render_ImageFiltering.qml" << "render_bug37422.qml" - << "render_OpacityThroughBatchRoot.qml"; + << "render_OpacityThroughBatchRoot.qml" + << "render_AlphaOverlapRebuild.qml"; + if (!m_brokenMipmapSupport) files << "render_Mipmap.qml"; -- cgit v1.2.3 From e0bb49624cc7bc8d940dc3f5322f7868abcece15 Mon Sep 17 00:00:00 2001 From: Ulf Hermann Date: Mon, 10 May 2021 09:44:51 +0200 Subject: Doc: Clarify preconditions for using QML_ELEMENT et al You need to include qqml.h and you need to make your own class declarations available to the registration code. Change-Id: I98e6b0b8a0acc309482416c3137d8ed782bbdc82 Reviewed-by: Paul Wicking (cherry picked from commit 40c759cbfa9dfb944a924b6c01fbfd1a15a7a25e) Reviewed-by: Qt Cherry-pick Bot --- src/qml/doc/src/cppintegration/definetypes.qdoc | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/src/qml/doc/src/cppintegration/definetypes.qdoc b/src/qml/doc/src/cppintegration/definetypes.qdoc index ece2fd5fd7..ffe0ec9737 100644 --- a/src/qml/doc/src/cppintegration/definetypes.qdoc +++ b/src/qml/doc/src/cppintegration/definetypes.qdoc @@ -69,6 +69,21 @@ exposed to QML but the type itself should not be instantiable. For a quick guide to choosing the correct approach to expose C++ types to QML, see \l {Choosing the Correct Integration Method Between C++ and QML}. +\section2 Preconditions + +All the macros mentioned below are available from the \c qqml.h +header. You need to add the following code to the files using them in order to +make the macros available: + +\code +#include +\endcode + +Furthermore, your class declarations have to live in headers reachable via your +project's include path. The declarations are used to generate registration code +at compile time, and the registration code needs to include the headers that +contain the declarations. + \section2 Registering an Instantiable Object Type \b{Any QObject-derived C++ class can be registered as the definition of a -- cgit v1.2.3 From 258c854dcba34843fad8023cc3668d5ab7c68c57 Mon Sep 17 00:00:00 2001 From: Andy Shaw Date: Tue, 13 Apr 2021 09:05:59 +0200 Subject: Doc: Fix the Shapes table to reflect reality PathPolyline and PathMultiline do not have GL_NV_path_rendering support so this is updated to reflect that. Change-Id: Iaa119e51bb22d6c8b4907818ffda96cca299893d Reviewed-by: Laszlo Agocs --- src/quick/util/qquickpath.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/quick/util/qquickpath.cpp b/src/quick/util/qquickpath.cpp index 88d0f69baa..71331c0a4a 100644 --- a/src/quick/util/qquickpath.cpp +++ b/src/quick/util/qquickpath.cpp @@ -107,12 +107,13 @@ QT_BEGIN_NAMESPACE \li PathPolyline \li Yes \li Yes + \li No \li Yes - \li Yes - \li PathMultiLine - \li Yes + \row + \li PathMultiLine \li Yes \li Yes + \li No \li Yes \row \li PathQuad -- cgit v1.2.3 From a972a4141f62ee27157b1ee3cbd432724d829c69 Mon Sep 17 00:00:00 2001 From: Alexey Edelev Date: Tue, 4 May 2021 17:42:30 +0200 Subject: Map window coordinates to the same coordinate system as the QPointerEvent point If the window has parent windows its geometry should be mapped to the global coordinates before check if it contains the point coordinates. Fixes: QTBUG-91716 Change-Id: I300547361dbe895b67caeee0d47f416426444552 Reviewed-by: Shawn Rutledge Reviewed-by: Qt CI Bot (cherry picked from commit c740a9d30571079fa22fd26cb8e72df6ca28c7b2) Reviewed-by: Alexey Edelev --- src/quick/handlers/qquickpointerhandler.cpp | 5 +- .../qquicktaphandler/data/simpleTapHandler.qml | 39 +++++++++++++++ .../qquicktaphandler/tst_qquicktaphandler.cpp | 55 ++++++++++++++++++++-- 3 files changed, 95 insertions(+), 4 deletions(-) create mode 100644 tests/auto/quick/pointerhandlers/qquicktaphandler/data/simpleTapHandler.qml diff --git a/src/quick/handlers/qquickpointerhandler.cpp b/src/quick/handlers/qquickpointerhandler.cpp index 2c88be7ab9..e46bd897a6 100644 --- a/src/quick/handlers/qquickpointerhandler.cpp +++ b/src/quick/handlers/qquickpointerhandler.cpp @@ -503,8 +503,11 @@ bool QQuickPointerHandler::parentContains(const QQuickEventPoint *point) const return false; if (QQuickItem *par = parentItem()) { if (par->window()) { + QRect windowGeometry = par->window()->geometry(); + if (!par->window()->isTopLevel()) + windowGeometry = QRect(QWindowPrivate::get(par->window())->globalPosition(), par->window()->size()); QPoint screenPosition = par->window()->mapToGlobal(point->scenePosition().toPoint()); - if (!par->window()->geometry().contains(screenPosition)) + if (!windowGeometry.contains(screenPosition)) return false; } QPointF p = par->mapFromScene(point->scenePosition()); diff --git a/tests/auto/quick/pointerhandlers/qquicktaphandler/data/simpleTapHandler.qml b/tests/auto/quick/pointerhandlers/qquicktaphandler/data/simpleTapHandler.qml new file mode 100644 index 0000000000..1c18133f92 --- /dev/null +++ b/tests/auto/quick/pointerhandlers/qquicktaphandler/data/simpleTapHandler.qml @@ -0,0 +1,39 @@ +/**************************************************************************** +** +** Copyright (C) 2021 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:GPL-EXCEPT$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.12 + +Item { + id: root + width: 100 + height: 100 + property int tapCount: 0 + TapHandler { + onTapped: { ++root.tapCount } + } +} diff --git a/tests/auto/quick/pointerhandlers/qquicktaphandler/tst_qquicktaphandler.cpp b/tests/auto/quick/pointerhandlers/qquicktaphandler/tst_qquicktaphandler.cpp index 419afed3ac..52cef6248f 100644 --- a/tests/auto/quick/pointerhandlers/qquicktaphandler/tst_qquicktaphandler.cpp +++ b/tests/auto/quick/pointerhandlers/qquicktaphandler/tst_qquicktaphandler.cpp @@ -71,15 +71,25 @@ private slots: void buttonsMultiTouch(); void componentUserBehavioralOverride(); void rightLongPressIgnoreWheel(); + void nonTopLevelParentWindow(); private: - void createView(QScopedPointer &window, const char *fileName); + void createView(QScopedPointer &window, const char *fileName, + QWindow *parent = nullptr); QTouchDevice *touchDevice; + void mouseEvent(QEvent::Type type, Qt::MouseButton button, const QPoint &point, + QWindow *targetWindow, QWindow *mapToWindow); }; -void tst_TapHandler::createView(QScopedPointer &window, const char *fileName) +void tst_TapHandler::createView(QScopedPointer &window, const char *fileName, + QWindow *parent) { - window.reset(new QQuickView); + window.reset(new QQuickView(parent)); + if (parent) { + parent->show(); + QVERIFY(QTest::qWaitForWindowActive(parent)); + } + window->setSource(testFileUrl(fileName)); QTRY_COMPARE(window->status(), QQuickView::Ready); QQuickViewTestUtil::centerOnScreen(window.data()); @@ -90,6 +100,20 @@ void tst_TapHandler::createView(QScopedPointer &window, const char * QVERIFY(window->rootObject() != nullptr); } +void tst_TapHandler::mouseEvent(QEvent::Type type, Qt::MouseButton button, const QPoint &point, + QWindow *targetWindow, QWindow *mapToWindow) +{ + QVERIFY(targetWindow); + QVERIFY(mapToWindow); + auto buttons = button; + if (type == QEvent::MouseButtonRelease) { + buttons = Qt::NoButton; + } + QMouseEvent me(type, point, mapToWindow->mapToGlobal(point), button, buttons, + Qt::KeyboardModifiers()); + QVERIFY(qApp->notify(targetWindow, &me)); +} + void tst_TapHandler::initTestCase() { // This test assumes that we don't get synthesized mouse events from QGuiApplication @@ -745,6 +769,31 @@ void tst_TapHandler::rightLongPressIgnoreWheel() QCOMPARE(tappedSpy.count(), 0); } +void tst_TapHandler::nonTopLevelParentWindow() // QTBUG-91716 +{ + QScopedPointer parentWindowPtr(new QQuickWindow); + auto parentWindow = parentWindowPtr.get(); + parentWindow->setGeometry(400, 400, 250, 250); + + QScopedPointer windowPtr; + createView(windowPtr, "simpleTapHandler.qml", parentWindow); + auto window = windowPtr.get(); + window->setGeometry(10, 10, 100, 100); + + QQuickItem *root = window->rootObject(); + + auto p1 = QPoint(20, 20); + mouseEvent(QEvent::MouseButtonPress, Qt::LeftButton, p1, window, parentWindow); + mouseEvent(QEvent::MouseButtonRelease, Qt::LeftButton, p1, window, parentWindow); + + QCOMPARE(root->property("tapCount").toInt(), 1); + + QTest::touchEvent(window, touchDevice).press(0, p1, parentWindow).commit(); + QTest::touchEvent(window, touchDevice).release(0, p1, parentWindow).commit(); + + QCOMPARE(root->property("tapCount").toInt(), 2); +} + QTEST_MAIN(tst_TapHandler) #include "tst_qquicktaphandler.moc" -- cgit v1.2.3 From e1234e2225e2553b72d39ac6baf57efe5c0bd504 Mon Sep 17 00:00:00 2001 From: Andreas Buhr Date: Thu, 14 Jan 2021 16:03:32 +0100 Subject: Consistent naming for (to|from)Is(Defined|Sourced) in animations To store whether "from" and "to" values are defined and/or sourced, QQuickPathAnimationUpdater used fromDefined format, QQuickAbstractAnimationPrivate used fromIsDefined format, QQuickAnimationPropertyUpdater used fromIsDefined format, QQuickAnimatorPrivate used isFromDefined format, QQuickBulkValueAnimator used fromDefined format, QQuickAnimationPropertyUpdater used fromDefined format. This patch changes all these to use the variable names "fromIsDefined", "fromIsSourced", and "toIsDefined". This makes the code more readable. Change-Id: Ia6c228208eb651247b0ba70f83afadb5b1027049 Reviewed-by: Ulf Hermann (cherry picked from commit 702b00bc8bfdc51592a01c9b7ed5939d85a7e192) Reviewed-by: Shawn Rutledge --- src/quick/items/qquickitemanimation.cpp | 27 +++++++++++++-------------- src/quick/items/qquickitemanimation_p_p.h | 8 ++++---- src/quick/util/qquickanimation.cpp | 16 ++++++++-------- src/quick/util/qquickanimation_p_p.h | 10 +++++----- src/quick/util/qquickanimator.cpp | 8 ++++---- src/quick/util/qquickanimator_p_p.h | 8 ++++---- 6 files changed, 38 insertions(+), 39 deletions(-) diff --git a/src/quick/items/qquickitemanimation.cpp b/src/quick/items/qquickitemanimation.cpp index d8649697e4..d00e39343e 100644 --- a/src/quick/items/qquickitemanimation.cpp +++ b/src/quick/items/qquickitemanimation.cpp @@ -529,8 +529,8 @@ QAbstractAnimationJob* QQuickAnchorAnimation::transition(QQuickStateActions &act data->interpolatorType = QMetaType::QReal; data->interpolator = d->interpolator; data->reverse = direction == Backward ? true : false; - data->fromSourced = false; - data->fromDefined = false; + data->fromIsSourced = false; + data->fromIsDefined = false; for (int ii = 0; ii < actions.count(); ++ii) { QQuickStateAction &action = actions[ii]; @@ -543,7 +543,7 @@ QAbstractAnimationJob* QQuickAnchorAnimation::transition(QQuickStateActions &act QQuickBulkValueAnimator *animator = new QQuickBulkValueAnimator; if (data->actions.count()) { animator->setAnimValue(data); - animator->setFromSourcedValue(&data->fromSourced); + animator->setFromIsSourcedValue(&data->fromIsSourced); } else { delete data; } @@ -864,9 +864,9 @@ QAbstractAnimationJob* QQuickPathAnimation::transition(QQuickStateActions &actio data->exitInterval = d->duration ? qreal(d->exitDuration) / d->duration : qreal(0); data->endRotation = d->endRotation; data->reverse = direction == Backward ? true : false; - data->fromSourced = false; - data->fromDefined = (d->path && d->path->hasStartX() && d->path->hasStartY()) ? true : false; - data->toDefined = d->path ? true : false; + data->fromIsSourced = false; + data->fromIsDefined = (d->path && d->path->hasStartX() && d->path->hasStartY()) ? true : false; + data->toIsDefined = d->path ? true : false; int origModifiedSize = modified.count(); for (int i = 0; i < actions.count(); ++i) { @@ -885,8 +885,7 @@ QAbstractAnimationJob* QQuickPathAnimation::transition(QQuickStateActions &actio } } - if (target && d->path && - (modified.count() > origModifiedSize || data->toDefined)) { + if (target && d->path && (modified.count() > origModifiedSize || data->toIsDefined)) { data->target = target; data->path = d->path; data->path->invalidateSequentialHistory(); @@ -897,13 +896,13 @@ QAbstractAnimationJob* QQuickPathAnimation::transition(QQuickStateActions &actio // treat interruptions specially, otherwise we end up with strange paths if ((data->reverse || prevData.reverse) && prevData.currentV > 0 && prevData.currentV < 1) { - if (!data->fromDefined && !data->toDefined && !prevData.painterPath.isEmpty()) { + if (!data->fromIsDefined && !data->toIsDefined && !prevData.painterPath.isEmpty()) { QPointF pathPos = QQuickPath::sequentialPointAt(prevData.painterPath, prevData.pathLength, prevData.attributePoints, prevData.prevBez, prevData.currentV); if (!prevData.anchorPoint.isNull()) pathPos -= prevData.anchorPoint; if (pathPos == data->target->position()) { //only treat as interruption if we interrupted ourself data->painterPath = prevData.painterPath; - data->toDefined = data->fromDefined = data->fromSourced = true; + data->toIsDefined = data->fromIsDefined = data->fromIsSourced = true; data->prevBez.isValid = false; data->interruptStart = prevData.currentV; data->startRotation = prevData.startRotation; @@ -913,13 +912,13 @@ QAbstractAnimationJob* QQuickPathAnimation::transition(QQuickStateActions &actio } } } - pa->setFromSourcedValue(&data->fromSourced); + pa->setFromIsSourcedValue(&data->fromIsSourced); pa->setAnimValue(data); pa->setDuration(d->duration); pa->setEasingCurve(d->easingCurve); return initInstance(pa); } else { - pa->setFromSourcedValue(nullptr); + pa->setFromIsSourcedValue(nullptr); pa->setAnimValue(nullptr); delete pa; delete data; @@ -939,7 +938,7 @@ void QQuickPathAnimationUpdater::setValue(qreal v) } currentV = v; bool atStart = ((reverse && v == 1.0) || (!reverse && v == 0.0)); - if (!fromSourced && (!fromDefined || !toDefined)) { + if (!fromIsSourced && (!fromIsDefined || !toIsDefined)) { qreal startX = reverse ? toX + anchorPoint.x() : target->x() + anchorPoint.x(); qreal startY = reverse ? toY + anchorPoint.y() : target->y() + anchorPoint.y(); qreal endX = reverse ? target->x() + anchorPoint.x() : toX + anchorPoint.x(); @@ -947,7 +946,7 @@ void QQuickPathAnimationUpdater::setValue(qreal v) prevBez.isValid = false; painterPath = path->createPath(QPointF(startX, startY), QPointF(endX, endY), QStringList(), pathLength, attributePoints); - fromSourced = true; + fromIsSourced = true; } qreal angle; diff --git a/src/quick/items/qquickitemanimation_p_p.h b/src/quick/items/qquickitemanimation_p_p.h index c6cfe9dc69..38840257df 100644 --- a/src/quick/items/qquickitemanimation_p_p.h +++ b/src/quick/items/qquickitemanimation_p_p.h @@ -92,7 +92,7 @@ class QQuickPathAnimationUpdater : public QQuickBulkValueUpdater { public: QQuickPathAnimationUpdater() : path(nullptr), pathLength(0), target(nullptr), reverse(false), - fromSourced(false), fromDefined(false), toDefined(false), + fromIsSourced(false), fromIsDefined(false), toIsDefined(false), toX(0), toY(0), currentV(0), orientation(QQuickPathAnimation::Fixed), entryInterval(0), exitInterval(0) {} ~QQuickPathAnimationUpdater() {} @@ -108,9 +108,9 @@ public: QQuickItem *target; bool reverse; - bool fromSourced; - bool fromDefined; - bool toDefined; + bool fromIsSourced; + bool fromIsDefined; + bool toIsDefined; qreal toX; qreal toY; qreal currentV; diff --git a/src/quick/util/qquickanimation.cpp b/src/quick/util/qquickanimation.cpp index 2ff75e8c7c..278ec4bd91 100644 --- a/src/quick/util/qquickanimation.cpp +++ b/src/quick/util/qquickanimation.cpp @@ -1996,7 +1996,7 @@ void QQuickPropertyAnimationPrivate::convertVariant(QVariant &variant, int type) } QQuickBulkValueAnimator::QQuickBulkValueAnimator() - : QAbstractAnimationJob(), animValue(nullptr), fromSourced(nullptr), m_duration(250) + : QAbstractAnimationJob(), animValue(nullptr), fromIsSourced(nullptr), m_duration(250) { } @@ -2026,8 +2026,8 @@ void QQuickBulkValueAnimator::updateCurrentTime(int currentTime) void QQuickBulkValueAnimator::topLevelAnimationLoopChanged() { //check for new from every top-level loop (when the top level animation is started and all subsequent loops) - if (fromSourced) - *fromSourced = false; + if (fromIsSourced) + *fromIsSourced = false; QAbstractAnimationJob::topLevelAnimationLoopChanged(); } @@ -2596,7 +2596,7 @@ void QQuickAnimationPropertyUpdater::setValue(qreal v) if (v == 1.) { QQmlPropertyPrivate::write(action.property, action.toValue, QQmlPropertyData::BypassInterceptor | QQmlPropertyData::DontRemoveBinding); } else { - if (!fromSourced && !fromDefined) { + if (!fromIsSourced && !fromIsDefined) { action.fromValue = action.property.read(); if (interpolatorType) { QQuickPropertyAnimationPrivate::convertVariant(action.fromValue, interpolatorType); @@ -2616,7 +2616,7 @@ void QQuickAnimationPropertyUpdater::setValue(qreal v) return; } wasDeleted = nullptr; - fromSourced = true; + fromIsSourced = true; } void QQuickAnimationPropertyUpdater::debugUpdater(QDebug d, int indentLevel) const @@ -2760,11 +2760,11 @@ QAbstractAnimationJob* QQuickPropertyAnimation::transition(QQuickStateActions &a data->interpolatorType = d->interpolatorType; data->interpolator = d->interpolator; data->reverse = direction == Backward ? true : false; - data->fromSourced = false; - data->fromDefined = d->fromIsDefined; + data->fromIsSourced = false; + data->fromIsDefined = d->fromIsDefined; data->actions = dataActions; animator->setAnimValue(data); - animator->setFromSourcedValue(&data->fromSourced); + animator->setFromIsSourcedValue(&data->fromIsSourced); d->actions = &data->actions; //remove this? } diff --git a/src/quick/util/qquickanimation_p_p.h b/src/quick/util/qquickanimation_p_p.h index 190bb53243..911e7635bb 100644 --- a/src/quick/util/qquickanimation_p_p.h +++ b/src/quick/util/qquickanimation_p_p.h @@ -135,7 +135,7 @@ public: void setAnimValue(QQuickBulkValueUpdater *value); QQuickBulkValueUpdater *getAnimValue() const { return animValue; } - void setFromSourcedValue(bool *value) { fromSourced = value; } + void setFromIsSourcedValue(bool *value) { fromIsSourced = value; } int duration() const override { return m_duration; } void setDuration(int msecs) { m_duration = msecs; } @@ -150,7 +150,7 @@ protected: private: QQuickBulkValueUpdater *animValue; - bool *fromSourced; + bool *fromIsSourced; int m_duration; QEasingCurve easing; }; @@ -311,7 +311,7 @@ public: class Q_AUTOTEST_EXPORT QQuickAnimationPropertyUpdater : public QQuickBulkValueUpdater { public: - QQuickAnimationPropertyUpdater() : interpolatorType(0), interpolator(nullptr), prevInterpolatorType(0), reverse(false), fromSourced(false), fromDefined(false), wasDeleted(nullptr) {} + QQuickAnimationPropertyUpdater() : interpolatorType(0), interpolator(nullptr), prevInterpolatorType(0), reverse(false), fromIsSourced(false), fromIsDefined(false), wasDeleted(nullptr) {} ~QQuickAnimationPropertyUpdater() override; void setValue(qreal v) override; @@ -323,8 +323,8 @@ public: QVariantAnimation::Interpolator interpolator; int prevInterpolatorType; //for generic bool reverse; - bool fromSourced; - bool fromDefined; + bool fromIsSourced; + bool fromIsDefined; bool *wasDeleted; }; diff --git a/src/quick/util/qquickanimator.cpp b/src/quick/util/qquickanimator.cpp index ba96e4001c..a736372049 100644 --- a/src/quick/util/qquickanimator.cpp +++ b/src/quick/util/qquickanimator.cpp @@ -176,7 +176,7 @@ void QQuickAnimator::setTo(qreal to) Q_D(QQuickAnimator); if (to == d->to) return; - d->isToDefined = true; + d->toIsDefined = true; d->to = to; Q_EMIT toChanged(d->to); } @@ -204,7 +204,7 @@ void QQuickAnimator::setFrom(qreal from) Q_D(QQuickAnimator); if (from == d->from) return; - d->isFromDefined = true; + d->fromIsDefined = true; d->from = from; Q_EMIT fromChanged(d->from); } @@ -231,14 +231,14 @@ void QQuickAnimatorPrivate::apply(QQuickAnimatorJob *job, job->setTarget(qobject_cast(action.property.object())); - if (isFromDefined) + if (fromIsDefined) job->setFrom(from); else if (action.fromValue.isValid()) job->setFrom(action.fromValue.toReal()); else job->setFrom(action.property.read().toReal()); - if (isToDefined) + if (toIsDefined) job->setTo(to); else if (action.toValue.isValid()) job->setTo(action.toValue.toReal()); diff --git a/src/quick/util/qquickanimator_p_p.h b/src/quick/util/qquickanimator_p_p.h index 250cb781b0..0966797ee8 100644 --- a/src/quick/util/qquickanimator_p_p.h +++ b/src/quick/util/qquickanimator_p_p.h @@ -68,8 +68,8 @@ public: , duration(250) , from(0) , to(0) - , isFromDefined(false) - , isToDefined(false) + , fromIsDefined(false) + , toIsDefined(false) { } @@ -79,8 +79,8 @@ public: qreal from; qreal to; - uint isFromDefined : 1; - uint isToDefined : 1; + uint fromIsDefined : 1; + uint toIsDefined : 1; void apply(QQuickAnimatorJob *job, const QString &propertyName, QQuickStateActions &actions, QQmlProperties &modified, QObject *defaultTarget); }; -- cgit v1.2.3 From bebb3afa1ced4656a021a55199ee60debe15e1ae Mon Sep 17 00:00:00 2001 From: Tarja Sundqvist Date: Thu, 20 May 2021 14:47:00 +0300 Subject: Bump version Change-Id: I687869905f29fa2af3d6200fd795bcb90d2aedc5 --- .qmake.conf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.qmake.conf b/.qmake.conf index b09daef9c6..a72382f252 100644 --- a/.qmake.conf +++ b/.qmake.conf @@ -4,4 +4,4 @@ CONFIG += warning_clean DEFINES += QT_NO_LINKED_LIST DEFINES += QT_NO_JAVA_STYLE_ITERATORS -MODULE_VERSION = 5.15.4 +MODULE_VERSION = 5.15.5 -- cgit v1.2.3 From 36f75c0a1b0145b50f24db397a641c1760cb351a Mon Sep 17 00:00:00 2001 From: Shawn Rutledge Date: Wed, 26 May 2021 10:31:58 +0200 Subject: docs: Clarify EventPoint properties - pointId is the point ID, obviously. - Users should not set the accepted flag in QML. It's not possible to make this mechanism useful in Qt 6. In Qt 5, there's no pressed(EventPoint) signal; setting it in onTapped() doesn't have the desired effect; and setting it procedurally in any context is an ugly MouseArea hack that we'd better avoid repeating. It was already marked readonly, but the docs mistakenly suggested that it should be settable. The Q_PROPERTY is writable, but probably shouldn't be. Amends a4439d6baf6996fd018575f5ed752b4d4429f92a Fixes: QTBUG-94016 Pick-to: 5.12 Change-Id: I9ee23e8fd4d4417638c520425882b83c26588526 Reviewed-by: Paul Wicking --- src/quick/items/qquickevents.cpp | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/src/quick/items/qquickevents.cpp b/src/quick/items/qquickevents.cpp index 0f5f32a213..3ac8e19e9c 100644 --- a/src/quick/items/qquickevents.cpp +++ b/src/quick/items/qquickevents.cpp @@ -813,7 +813,7 @@ QQuickPointerDevice *QQuickPointerDevice::tabletDevice(const QTabletEvent *event \readonly \qmlproperty int QtQuick::EventPoint::pointId - This property holds the ID of the event, if any. + This property holds the ID of the point, if any. Touchpoints have automatically-incrementing IDs: each time the user presses a finger against the touchscreen, it will be a larger number. @@ -826,12 +826,8 @@ QQuickPointerDevice *QQuickPointerDevice::tabletDevice(const QTabletEvent *event \readonly \qmlproperty bool QtQuick::EventPoint::accepted - Setting \a accepted to true prevents the event from being propagated to - Items below the PointerHandler's Item. - - Generally, if the handler acts on the mouse event, then it should be - accepted so that items lower in the stacking order do not also respond to - the same event. + Indicates whether this point has been accepted during delivery thus far. + This flag cannot be usefully set from QML. */ /*! -- cgit v1.2.3 From 044a84fa3fe5a8d75932079576575afc145b867a Mon Sep 17 00:00:00 2001 From: Albert Astals Cid Date: Fri, 21 May 2021 13:30:41 +0200 Subject: Give a warning when StyledText encounters a non supported entity Change-Id: Iea8bdf25542cd404ee71141467ac1f1398a7d0df Reviewed-by: Fabian Kosmale (cherry picked from commit 8cd43e370040e23fcbd03ad64969e683055bd7d0) Reviewed-by: Qt Cherry-pick Bot --- src/quick/util/qquickstyledtext.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/quick/util/qquickstyledtext.cpp b/src/quick/util/qquickstyledtext.cpp index 93409dc566..f209a14f35 100644 --- a/src/quick/util/qquickstyledtext.cpp +++ b/src/quick/util/qquickstyledtext.cpp @@ -46,6 +46,8 @@ #include "qquickstyledtext_p.h" #include +Q_LOGGING_CATEGORY(lcStyledText, "qt.quick.styledtext") + /* QQuickStyledText supports few tags: @@ -566,6 +568,8 @@ void QQuickStyledTextPrivate::parseEntity(const QChar *&ch, const QString &textI textOut += QChar(34); else if (entity == QLatin1String("nbsp")) textOut += QChar(QChar::Nbsp); + else + qCWarning(lcStyledText) << "StyledText doesn't support entity" << entity; return; } else if (*ch == QLatin1Char(' ')) { QStringRef entity(&textIn, entityStart - 1, entityLength + 1); -- cgit v1.2.3 From 3278d41e9c4da019ff0d1d328ec3ca96b124c15f Mon Sep 17 00:00:00 2001 From: Mitch Curtis Date: Wed, 19 May 2021 13:53:32 +0200 Subject: Remove tst_pixel Future patches will add uses of pixel() and other accessors to selftests/tst_grabImage.qml, and that's where those kinds of tests should be. Task-number: QTBUG-27671 Change-Id: I3ad42ded144cb7fa8b196a3ac58abcd9ee9b2abf Reviewed-by: Fabian Kosmale Reviewed-by: Alexander Akulich (cherry picked from commit 1d1910e70778114e5eae586792664cf6c0997ed0) --- tests/auto/qmltest/pixel/tst_pixel.qml | 65 ---------------------------------- tests/auto/qmltest/qmltest.pro | 1 - 2 files changed, 66 deletions(-) delete mode 100644 tests/auto/qmltest/pixel/tst_pixel.qml diff --git a/tests/auto/qmltest/pixel/tst_pixel.qml b/tests/auto/qmltest/pixel/tst_pixel.qml deleted file mode 100644 index e628fed1d8..0000000000 --- a/tests/auto/qmltest/pixel/tst_pixel.qml +++ /dev/null @@ -1,65 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the test suite of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:GPL-EXCEPT$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3 as published by the Free Software -** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -import QtQuick 2.0 -import QtTest 1.1 - -Rectangle { - id:rect - width: 40 - height: 40 - color:"red" - TestCase { - name: "Pixels" - when: windowShown - - function test_pixel() { - skip("test_pixel() is unstable, QTBUG-27671") - var img = grabImage(rect); - compare(img.pixel(20, 20), Qt.rgba(255, 0, 0, 255)); - compare(img.red(1,1), 255); - compare(img.green(1,1), 0); - compare(img.blue(1,1), 0); - compare(img.alpha(1,1), 255); - - fuzzyCompare(img.red(1,1), 254, 2); - fuzzyCompare(img.pixel(1,1), Qt.rgba(254, 0, 0, 254), 2); - fuzzyCompare(img.pixel(1,1), "#FF0201", 2); - - rect.color = "blue"; - waitForRendering(rect); - img = grabImage(rect); - compare(img.pixel(20, 20), Qt.rgba(0, 0, 255, 255)); - compare(img.red(1,1), 0); - compare(img.green(1,1), 0); - compare(img.blue(1,1), 255); - compare(img.alpha(1,1), 255); - } - - } -} \ No newline at end of file diff --git a/tests/auto/qmltest/qmltest.pro b/tests/auto/qmltest/qmltest.pro index 8ad1541cbc..0b793269e9 100644 --- a/tests/auto/qmltest/qmltest.pro +++ b/tests/auto/qmltest/qmltest.pro @@ -15,7 +15,6 @@ SUBDIRS += \ listview \ objectmodel \ pathview \ - pixel \ positioners \ qqmlbinding \ qtbug46798 \ -- cgit v1.2.3 From 53086eaf2ffb5fc1c360cf13f3d87e8d5f2a7b6f Mon Sep 17 00:00:00 2001 From: Shawn Rutledge Date: Tue, 25 May 2021 23:03:09 +0200 Subject: doc: Improve QQuickItem::ItemChangeData docs Amends 15b232bf694fedf553abac09af077a58ce571f9d Change-Id: Icbc46e795af560b51bc6654e853944e1c591a169 Reviewed-by: Paul Wicking (cherry picked from commit a69b5a39770768844292981b5787e3e8cdc8a863) Reviewed-by: Qt Cherry-pick Bot --- src/quick/items/qquickitem.cpp | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/src/quick/items/qquickitem.cpp b/src/quick/items/qquickitem.cpp index bbacf23d16..0f03e776c9 100644 --- a/src/quick/items/qquickitem.cpp +++ b/src/quick/items/qquickitem.cpp @@ -2095,7 +2095,7 @@ void QQuickItemPrivate::updateSubFocusItem(QQuickItem *scope, bool focus) /*! \class QQuickItem::ItemChangeData \inmodule QtQuick - \brief Adds supplimentary information to the QQuickItem::itemChange() + \brief Adds supplementary information to the QQuickItem::itemChange() function. The meaning of each member of this class is defined by the change type. @@ -2125,25 +2125,31 @@ void QQuickItemPrivate::updateSubFocusItem(QQuickItem *scope, bool focus) /*! \variable QQuickItem::ItemChangeData::realValue - Contains supplimentary information to the QQuickItem::itemChange() function. + The numeric value that has changed: \l {QQuickItem::opacity()}{opacity}, + \l {QQuickItem::rotation()}{rotation} or + \l {QScreen::devicePixelRatio}{device pixel ratio}. \sa QQuickItem::ItemChange */ /*! \variable QQuickItem::ItemChangeData::boolValue - Contains supplimentary information to the QQuickItem::itemChange() function. + The boolean value that has changed: \l {QQuickItem::visible()}{visible}, + \l {QQuickItem::enabled()}{enabled}, \l {QQuickItem::activeFocus()}{activeFocus} + or \l {QQuickItem::antialiasing()}{antialiasing}. \sa QQuickItem::ItemChange */ /*! \variable QQuickItem::ItemChangeData::item - Contains supplimentary information to the QQuickItem::itemChange() function. + The item that has been added or removed as a \l{QQuickItem::childItems()}{child}, + or the new \l{QQuickItem::parentItem()}{parent}. \sa QQuickItem::ItemChange */ /*! \variable QQuickItem::ItemChangeData::window - Contains supplimentary information to the QQuickItem::itemChange() function. + The \l{QQuickWindow}{window} in which the item has been shown, or \c nullptr + if the item has been removed from a window. \sa QQuickItem::ItemChange */ -- cgit v1.2.3