aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTarja Sundqvist <tarja.sundqvist@qt.io>2024-05-08 08:14:41 +0300
committerTarja Sundqvist <tarja.sundqvist@qt.io>2024-05-08 08:14:41 +0300
commit5f4570b5164a828b20514b938957ce06b105ff3e (patch)
tree0114d737813cb121ba31cbe5c2f73db746cc10dc
parent6ab9856ef379fc3fe44d5fac03a83f679f398511 (diff)
parentb299416894bcaf7965fd53c195636d84f0674255 (diff)
Merge remote-tracking branch 'origin/tqtc/lts-5.15.14' into tqtc/lts-5.15-opensourcev5.15.14-lts-lgpl5.15
-rw-r--r--.qmake.conf2
-rw-r--r--src/qml/doc/src/qmllanguageref/syntax/imports.qdoc16
-rw-r--r--src/qml/jit/qv4baselinejit.cpp4
-rw-r--r--src/qmlmodels/qqmldelegatemodel.cpp23
-rw-r--r--src/quick/items/qquickitem.cpp7
-rw-r--r--tests/auto/qml/qml.pro1
-rw-r--r--tests/auto/qml/qqmldelegatemodel/data/deleteRace.qml50
-rw-r--r--tests/auto/qml/qqmldelegatemodel/tst_qqmldelegatemodel.cpp23
-rw-r--r--tests/auto/quick/pointerhandlers/qquickhoverhandler/BLACKLIST1
-rw-r--r--tests/auto/quick/qquickdroparea/BLACKLIST1
-rw-r--r--tests/auto/quick/qquickitem2/data/activeFocusOnTab_infiniteLoop3.qml13
-rw-r--r--tests/auto/quick/qquickitem2/tst_qquickitem.cpp12
-rw-r--r--tests/auto/quick/qquicktext/BLACKLIST2
-rw-r--r--tests/auto/quick/qquicktextedit/BLACKLIST1
-rw-r--r--tests/auto/quickwidgets/qquickwidget/BLACKLIST1
15 files changed, 128 insertions, 29 deletions
diff --git a/.qmake.conf b/.qmake.conf
index 65ef03633e..831517bb0e 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.13
+MODULE_VERSION = 5.15.14
diff --git a/src/qml/doc/src/qmllanguageref/syntax/imports.qdoc b/src/qml/doc/src/qmllanguageref/syntax/imports.qdoc
index fdba452271..866ddc6d60 100644
--- a/src/qml/doc/src/qmllanguageref/syntax/imports.qdoc
+++ b/src/qml/doc/src/qmllanguageref/syntax/imports.qdoc
@@ -36,12 +36,10 @@ resources and component directories are used within a QML document. The types
which may be used within a document depends on which modules, resources and
directories are imported by the document.
-\section2 Import Types
-
There are three different types of imports. Each import type has a slightly
different syntax, and different semantics apply to different import types.
-\section3 Module (Namespace) Imports
+\section2 Module (Namespace) Imports
The most common type of import is a module import. Clients can import
\l{qtqml-modules-identifiedmodules.html}{QML modules} which register QML object
@@ -127,7 +125,7 @@ Rectangle {
In this case, the engine will emit an error and refuse to load the file.
-\section4 C++ Module Imports
+\section3 C++ Module Imports
Usually, C++ types are declared using the QML_ELEMENT and QML_NAMED_ELEMENT()
macros and registered via the build system using QML_IMPORT_NAME and
@@ -137,7 +135,7 @@ module that can be imported to access the types.
This is most common in client applications which define their own QML object
types in C++.
-\section4 Importing into a Qualified Local Namespace
+\section3 Importing into a Qualified Local Namespace
The \c import statement may optionally use the \c as keyword to specify that
the types should be imported into a particular document-local namespace. If a
@@ -187,7 +185,7 @@ way that multiple modules can be imported into the global namespace. For example
\snippet qml/imports/merged-named-imports.qml imports
-\section3 Directory Imports
+\section2 Directory Imports
A directory which contains QML documents may also be imported directly in a
QML document. This provides a simple way for QML types to be segmented into
@@ -213,7 +211,7 @@ section about \l{Importing into a Qualified Local Namespace}.
For more information about directory imports, please see the in-depth
documentation about \l{qtqml-syntax-directoryimports.html}{directory imports}.
-\section3 JavaScript Resource Imports
+\section2 JavaScript Resource Imports
JavaScript resources may be imported directly in a QML document. Every
JavaScript resource must have an identifier by which it is accessed.
@@ -226,7 +224,7 @@ import "<JavaScriptFile>" as <Identifier>
Note that the \c <Identifier> must be unique within a QML document, unlike the
local namespace qualifier which can be applied to module imports.
-\section4 JavaScript Resources from Modules
+\section3 JavaScript Resources from Modules
Javascript files can be provided by modules, by adding identifier
definitions to the \c qmldir file which specifies the module.
@@ -269,7 +267,7 @@ Item {
}
\endqml
-\section4 Further Information
+\section3 Further Information
For more information about JavaScript resources, please see the documentation
about \l{qtqml-javascript-resources.html}
diff --git a/src/qml/jit/qv4baselinejit.cpp b/src/qml/jit/qv4baselinejit.cpp
index 45150cfffd..5ad53faf95 100644
--- a/src/qml/jit/qv4baselinejit.cpp
+++ b/src/qml/jit/qv4baselinejit.cpp
@@ -540,6 +540,8 @@ void BaselineJIT::generate_ThrowException()
as->passEngineAsArg(0);
BASELINEJIT_GENERATE_RUNTIME_CALL(ThrowException, CallResultDestination::Ignore);
as->gotoCatchException();
+
+ // LOAD_ACC(); <- not needed here since it would be unreachable.
}
void BaselineJIT::generate_GetException() { as->getException(); }
@@ -547,9 +549,11 @@ void BaselineJIT::generate_SetException() { as->setException(); }
void BaselineJIT::generate_CreateCallContext()
{
+ STORE_ACC();
as->prepareCallWithArgCount(1);
as->passCppFrameAsArg(0);
BASELINEJIT_GENERATE_RUNTIME_CALL(PushCallContext, CallResultDestination::Ignore);
+ LOAD_ACC();
}
void BaselineJIT::generate_PushCatchContext(int index, int name) { as->pushCatchContext(index, name); }
diff --git a/src/qmlmodels/qqmldelegatemodel.cpp b/src/qmlmodels/qqmldelegatemodel.cpp
index 4fcff70de6..3b57edfc5d 100644
--- a/src/qmlmodels/qqmldelegatemodel.cpp
+++ b/src/qmlmodels/qqmldelegatemodel.cpp
@@ -1871,10 +1871,15 @@ void QQmlDelegateModelPrivate::emitChanges()
for (int i = 1; i < m_groupCount; ++i)
QQmlDelegateModelGroupPrivate::get(m_groups[i])->emitModelUpdated(reset);
- auto cacheCopy = m_cache; // deliberate; emitChanges may alter m_cache
- for (QQmlDelegateModelItem *cacheItem : qAsConst(cacheCopy)) {
- if (cacheItem->attached)
- cacheItem->attached->emitChanges();
+ // emitChanges may alter m_cache and delete items
+ QVarLengthArray<QPointer<QQmlDelegateModelAttached>> attachedObjects;
+ attachedObjects.reserve(m_cache.length());
+ for (const QQmlDelegateModelItem *cacheItem : qAsConst(m_cache))
+ attachedObjects.append(cacheItem->attached);
+
+ for (const QPointer<QQmlDelegateModelAttached> &attached : qAsConst(attachedObjects)) {
+ if (attached && attached->m_cacheItem)
+ attached->emitChanges();
}
}
@@ -2663,20 +2668,24 @@ void QQmlDelegateModelAttached::emitChanges()
m_previousGroups = m_cacheItem->groups;
int indexChanges = 0;
- for (int i = 1; i < m_cacheItem->metaType->groupCount; ++i) {
+ const int groupCount = m_cacheItem->metaType->groupCount;
+ for (int i = 1; i < groupCount; ++i) {
if (m_previousIndex[i] != m_currentIndex[i]) {
m_previousIndex[i] = m_currentIndex[i];
indexChanges |= (1 << i);
}
}
+ // Don't access m_cacheItem anymore once we've started sending signals.
+ // We don't own it and someone might delete it.
+
int notifierId = 0;
const QMetaObject *meta = metaObject();
- for (int i = 1; i < m_cacheItem->metaType->groupCount; ++i, ++notifierId) {
+ for (int i = 1; i < groupCount; ++i, ++notifierId) {
if (groupChanges & (1 << i))
QMetaObject::activate(this, meta, notifierId, nullptr);
}
- for (int i = 1; i < m_cacheItem->metaType->groupCount; ++i, ++notifierId) {
+ for (int i = 1; i < groupCount; ++i, ++notifierId) {
if (indexChanges & (1 << i))
QMetaObject::activate(this, meta, notifierId, nullptr);
}
diff --git a/src/quick/items/qquickitem.cpp b/src/quick/items/qquickitem.cpp
index 33da9762d3..ec55fb2998 100644
--- a/src/quick/items/qquickitem.cpp
+++ b/src/quick/items/qquickitem.cpp
@@ -59,6 +59,7 @@
#include <QtCore/private/qnumeric_p.h>
#include <QtGui/qpa/qplatformtheme.h>
#include <QtCore/qloggingcategory.h>
+#include <QtCore/private/qduplicatetracker_p.h>
#include <private/qqmlglobal_p.h>
#include <private/qqmlengine_p.h>
@@ -2526,6 +2527,7 @@ QQuickItem* QQuickItemPrivate::nextPrevItemInTabFocusChain(QQuickItem *item, boo
QQuickItem *current = item;
qCDebug(DBG_FOCUS) << "QQuickItemPrivate::nextPrevItemInTabFocusChain: startItem:" << startItem;
qCDebug(DBG_FOCUS) << "QQuickItemPrivate::nextPrevItemInTabFocusChain: firstFromItem:" << firstFromItem;
+ QDuplicateTracker<QQuickItem *> cycleDetector;
do {
qCDebug(DBG_FOCUS) << "QQuickItemPrivate::nextPrevItemInTabFocusChain: current:" << current;
qCDebug(DBG_FOCUS) << "QQuickItemPrivate::nextPrevItemInTabFocusChain: from:" << from;
@@ -2592,7 +2594,10 @@ QQuickItem* QQuickItemPrivate::nextPrevItemInTabFocusChain(QQuickItem *item, boo
// traversed all of the chain (by compare the [current] item with [startItem])
// Since the [startItem] might be promoted to its parent if it is invisible,
// we still have to check [current] item with original start item
- if ((current == startItem || current == originalStartItem) && from == firstFromItem) {
+ // We might also run into a cycle before we reach firstFromItem again
+ // but note that we have to ignore current if we are meant to skip it
+ if (((current == startItem || current == originalStartItem) && from == firstFromItem) ||
+ (!skip && cycleDetector.hasSeen(current))) {
// wrapped around, avoid endless loops
if (item == contentItem) {
qCDebug(DBG_FOCUS) << "QQuickItemPrivate::nextPrevItemInTabFocusChain: looped, return contentItem";
diff --git a/tests/auto/qml/qml.pro b/tests/auto/qml/qml.pro
index 621e8bb437..104fb216c2 100644
--- a/tests/auto/qml/qml.pro
+++ b/tests/auto/qml/qml.pro
@@ -43,6 +43,7 @@ PRIVATETESTS += \
animation \
qqmlecmascript \
qqmlcontext \
+ qqmldelegatemodel \
qqmlexpression \
qqmlglobal \
qqmllanguage \
diff --git a/tests/auto/qml/qqmldelegatemodel/data/deleteRace.qml b/tests/auto/qml/qqmldelegatemodel/data/deleteRace.qml
new file mode 100644
index 0000000000..23874970e7
--- /dev/null
+++ b/tests/auto/qml/qqmldelegatemodel/data/deleteRace.qml
@@ -0,0 +1,50 @@
+import QtQuick 2.15
+import QtQml.Models 2.15
+
+Item {
+ DelegateModel {
+ id: delegateModel
+ model: ListModel {
+ id: sourceModel
+
+ ListElement { title: "foo" }
+ ListElement { title: "bar" }
+
+ function clear() {
+ if (count > 0)
+ remove(0, count);
+ }
+ }
+
+ groups: [
+ DelegateModelGroup { name: "selectedItems" }
+ ]
+
+ delegate: Text {
+ height: DelegateModel.inSelectedItems ? implicitHeight * 2 : implicitHeight
+ Component.onCompleted: {
+ if (index === 0)
+ DelegateModel.inSelectedItems = true;
+ }
+ }
+
+ Component.onCompleted: {
+ items.create(0)
+ items.create(1)
+ }
+ }
+
+ ListView {
+ anchors.fill: parent
+ model: delegateModel
+ }
+
+ Timer {
+ running: true
+ interval: 10
+ onTriggered: sourceModel.clear()
+ }
+
+ property int count: delegateModel.items.count
+}
+
diff --git a/tests/auto/qml/qqmldelegatemodel/tst_qqmldelegatemodel.cpp b/tests/auto/qml/qqmldelegatemodel/tst_qqmldelegatemodel.cpp
index 35f1e2c94d..f0afdb16ca 100644
--- a/tests/auto/qml/qqmldelegatemodel/tst_qqmldelegatemodel.cpp
+++ b/tests/auto/qml/qqmldelegatemodel/tst_qqmldelegatemodel.cpp
@@ -47,6 +47,7 @@ private slots:
void filterOnGroup_removeWhenCompleted();
void qtbug_86017();
void contextAccessedByHandler();
+ void deleteRace();
};
class AbstractItemModel : public QAbstractItemModel
@@ -139,17 +140,6 @@ void tst_QQmlDelegateModel::valueWithoutCallingObjectFirst()
QCOMPARE(model->variantValue(index, role), expectedValue);
}
-void tst_QQmlDelegateModel::filterOnGroup_removeWhenCompleted()
-{
- QQuickView view(testFileUrl("removeFromGroup.qml"));
- QCOMPARE(view.status(), QQuickView::Ready);
- view.show();
- QQuickItem *root = view.rootObject();
- QVERIFY(root);
- QQmlDelegateModel *model = root->findChild<QQmlDelegateModel*>();
- QVERIFY(model);
- QTest::qWaitFor([=]{ return model->count() == 2; } );
-
void tst_QQmlDelegateModel::qtbug_86017()
{
QQmlEngine engine;
@@ -186,6 +176,17 @@ void tst_QQmlDelegateModel::contextAccessedByHandler()
QVERIFY(root->property("works").toBool());
}
+void tst_QQmlDelegateModel::deleteRace()
+{
+ QQmlEngine engine;
+ QQmlComponent c(&engine, testFileUrl("deleteRace.qml"));
+ QVERIFY2(c.isReady(), qPrintable(c.errorString()));
+ QScopedPointer<QObject> o(c.create());
+ QVERIFY(!o.isNull());
+ QTRY_COMPARE(o->property("count").toInt(), 2);
+ QTRY_COMPARE(o->property("count").toInt(), 0);
+}
+
QTEST_MAIN(tst_QQmlDelegateModel)
#include "tst_qqmldelegatemodel.moc"
diff --git a/tests/auto/quick/pointerhandlers/qquickhoverhandler/BLACKLIST b/tests/auto/quick/pointerhandlers/qquickhoverhandler/BLACKLIST
index 9bb35c4770..2df6574c2e 100644
--- a/tests/auto/quick/pointerhandlers/qquickhoverhandler/BLACKLIST
+++ b/tests/auto/quick/pointerhandlers/qquickhoverhandler/BLACKLIST
@@ -1,3 +1,4 @@
[movingItemWithHoverHandler]
macos # Can't move cursor (QTBUG-76312)
+sles-15.4 # (QTBUG-111294)
diff --git a/tests/auto/quick/qquickdroparea/BLACKLIST b/tests/auto/quick/qquickdroparea/BLACKLIST
index 0967969b04..e5223c1c87 100644
--- a/tests/auto/quick/qquickdroparea/BLACKLIST
+++ b/tests/auto/quick/qquickdroparea/BLACKLIST
@@ -2,3 +2,4 @@
# QTBUG-99765
[containsDrag_internal]
ubuntu-20.04
+sles-15.4
diff --git a/tests/auto/quick/qquickitem2/data/activeFocusOnTab_infiniteLoop3.qml b/tests/auto/quick/qquickitem2/data/activeFocusOnTab_infiniteLoop3.qml
new file mode 100644
index 0000000000..889e480f3b
--- /dev/null
+++ b/tests/auto/quick/qquickitem2/data/activeFocusOnTab_infiniteLoop3.qml
@@ -0,0 +1,13 @@
+import QtQuick 2.6
+
+Item {
+ visible: true
+ Item {
+ visible: false
+ Item {
+ objectName: "hiddenChild"
+ activeFocusOnTab: true
+ focus: true
+ }
+ }
+}
diff --git a/tests/auto/quick/qquickitem2/tst_qquickitem.cpp b/tests/auto/quick/qquickitem2/tst_qquickitem.cpp
index c8f251dbe1..c8ef36ee68 100644
--- a/tests/auto/quick/qquickitem2/tst_qquickitem.cpp
+++ b/tests/auto/quick/qquickitem2/tst_qquickitem.cpp
@@ -67,6 +67,7 @@ private slots:
void activeFocusOnTab10();
void activeFocusOnTab_infiniteLoop_data();
void activeFocusOnTab_infiniteLoop();
+ void activeFocusOnTab_infiniteLoopControls();
void nextItemInFocusChain();
void nextItemInFocusChain2();
@@ -1057,6 +1058,17 @@ void tst_QQuickItem::activeFocusOnTab_infiniteLoop()
QCOMPARE(item, window->rootObject());
}
+
+void tst_QQuickItem::activeFocusOnTab_infiniteLoopControls()
+{
+ auto source = testFileUrl("activeFocusOnTab_infiniteLoop3.qml");
+ QScopedPointer<QQuickView>window(new QQuickView());
+ window->setSource(source);
+ window->show();
+ QVERIFY(window->errors().isEmpty());
+ QTest::keyClick(window.get(), Qt::Key_Tab); // should not hang
+}
+
void tst_QQuickItem::nextItemInFocusChain()
{
if (!qt_tab_all_widgets())
diff --git a/tests/auto/quick/qquicktext/BLACKLIST b/tests/auto/quick/qquicktext/BLACKLIST
index f50276a4f1..85deb2288e 100644
--- a/tests/auto/quick/qquicktext/BLACKLIST
+++ b/tests/auto/quick/qquicktext/BLACKLIST
@@ -6,3 +6,5 @@ macos
opensuse-42.1
[hAlignVisual]
sles
+[contentSize]
+sles-15.4 # QTBUG-112360
diff --git a/tests/auto/quick/qquicktextedit/BLACKLIST b/tests/auto/quick/qquicktextedit/BLACKLIST
index a5cbd1675e..272e70b5cf 100644
--- a/tests/auto/quick/qquicktextedit/BLACKLIST
+++ b/tests/auto/quick/qquicktextedit/BLACKLIST
@@ -11,4 +11,5 @@ sles
# QTBUG-82052
[linkHover]
macos ci
+sles-15.4
diff --git a/tests/auto/quickwidgets/qquickwidget/BLACKLIST b/tests/auto/quickwidgets/qquickwidget/BLACKLIST
index 095e9ee484..afc565eab4 100644
--- a/tests/auto/quickwidgets/qquickwidget/BLACKLIST
+++ b/tests/auto/quickwidgets/qquickwidget/BLACKLIST
@@ -3,3 +3,4 @@ opensuse-42.3
opensuse-leap
[enterLeave]
macos
+sles-15.4 # QTBUG-64397