aboutsummaryrefslogtreecommitdiffstats
path: root/src/quick
diff options
context:
space:
mode:
Diffstat (limited to 'src/quick')
-rw-r--r--src/quick/accessible/qaccessiblequickview.cpp7
-rw-r--r--src/quick/doc/snippets/qml/listview/hideDelegate.qml27
-rw-r--r--src/quick/doc/snippets/qml/listview/listview.qml9
-rw-r--r--src/quick/doc/snippets/qml/listview/stateInDelegate.qml20
-rw-r--r--src/quick/doc/snippets/qml/listview/stateInModel.qml26
-rw-r--r--src/quick/doc/src/guidelines/qtquick-bestpractices.qdoc6
-rw-r--r--src/quick/doc/src/guidelines/qtquick-toolsnutilities.qdoc17
-rw-r--r--src/quick/handlers/qquickpinchhandler.cpp12
-rw-r--r--src/quick/items/qquickflickable.cpp4
-rw-r--r--src/quick/items/qquickitem.cpp60
-rw-r--r--src/quick/items/qquickitemview.cpp4
-rw-r--r--src/quick/items/qquicklistview.cpp46
-rw-r--r--src/quick/items/qquickmousearea.cpp9
-rw-r--r--src/quick/items/qquickscreen.cpp2
-rw-r--r--src/quick/items/qquickwindow.cpp29
-rw-r--r--src/quick/items/qquickwindow_p.h1
-rw-r--r--src/quick/util/qquickpixmapcache.cpp23
17 files changed, 230 insertions, 72 deletions
diff --git a/src/quick/accessible/qaccessiblequickview.cpp b/src/quick/accessible/qaccessiblequickview.cpp
index 08f5889070..7b9bd18582 100644
--- a/src/quick/accessible/qaccessiblequickview.cpp
+++ b/src/quick/accessible/qaccessiblequickview.cpp
@@ -87,10 +87,11 @@ QString QAccessibleQuickWindow::text(QAccessible::Text text) const
if (text == QAccessible::DebugDescription) {
return QString::fromLatin1(object()->metaObject()->className()) ;
}
-#else
- Q_UNUSED(text);
#endif
- return window()->title();
+ if (text == QAccessible::Name)
+ return window()->title();
+ else
+ return {};
}
QAccessibleInterface *QAccessibleQuickWindow::childAt(int x, int y) const
diff --git a/src/quick/doc/snippets/qml/listview/hideDelegate.qml b/src/quick/doc/snippets/qml/listview/hideDelegate.qml
new file mode 100644
index 0000000000..7c019a2c92
--- /dev/null
+++ b/src/quick/doc/snippets/qml/listview/hideDelegate.qml
@@ -0,0 +1,27 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+import QtQuick
+import QtQuick.Controls.Basic
+
+//! [ListView]
+ListView {
+ anchors.fill: parent
+ model: ListModel {
+ ListElement { hidden: false }
+ ListElement { hidden: false }
+ ListElement { hidden: false }
+ // ...
+ }
+ delegate: ItemDelegate {
+ text: qsTr("Item %1").arg(index)
+ visible: !model.hidden
+ height: visible ? implicitHeight : 0
+
+ required property int index
+ required property var model
+
+ onClicked: model.hidden = true
+ }
+}
+//! [ListView]
diff --git a/src/quick/doc/snippets/qml/listview/listview.qml b/src/quick/doc/snippets/qml/listview/listview.qml
index c8df8e727b..611f590542 100644
--- a/src/quick/doc/snippets/qml/listview/listview.qml
+++ b/src/quick/doc/snippets/qml/listview/listview.qml
@@ -13,6 +13,8 @@ ListView {
model: ContactModel {}
delegate: Text {
+ required property string name
+ required property string number
text: name + ": " + number
}
}
@@ -25,10 +27,13 @@ Rectangle {
Component {
id: contactDelegate
Item {
+ id: myItem
+ required property string name
+ required property string number
width: 180; height: 40
Column {
- Text { text: '<b>Name:</b> ' + name }
- Text { text: '<b>Number:</b> ' + number }
+ Text { text: '<b>Name:</b> ' + myItem.name }
+ Text { text: '<b>Number:</b> ' + myItem.number }
}
}
}
diff --git a/src/quick/doc/snippets/qml/listview/stateInDelegate.qml b/src/quick/doc/snippets/qml/listview/stateInDelegate.qml
new file mode 100644
index 0000000000..29d8d3e7c2
--- /dev/null
+++ b/src/quick/doc/snippets/qml/listview/stateInDelegate.qml
@@ -0,0 +1,20 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+import QtQuick
+import QtQuick.Controls.Basic
+
+//! [ListView]
+ListView {
+ anchors.fill: parent
+ model: 3
+ delegate: CheckDelegate {
+ text: qsTr("Channel %1").arg(index + 1)
+
+ required property int index
+ property bool channelActivated
+
+ onClicked: channelActivated = checked
+ }
+}
+//! [ListView]
diff --git a/src/quick/doc/snippets/qml/listview/stateInModel.qml b/src/quick/doc/snippets/qml/listview/stateInModel.qml
new file mode 100644
index 0000000000..56b2792140
--- /dev/null
+++ b/src/quick/doc/snippets/qml/listview/stateInModel.qml
@@ -0,0 +1,26 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+import QtQuick
+import QtQuick.Controls.Basic
+
+//! [ListView]
+ListView {
+ anchors.fill: parent
+ model: ListModel {
+ ListElement {
+ channelActivated: true
+ }
+ // ...
+ }
+ delegate: CheckDelegate {
+ text: qsTr("Channel %1").arg(index + 1)
+ checked: model.channelActivated
+
+ required property int index
+ required property var model
+
+ onClicked: model.channelActivated = checked
+ }
+}
+//! [ListView]
diff --git a/src/quick/doc/src/guidelines/qtquick-bestpractices.qdoc b/src/quick/doc/src/guidelines/qtquick-bestpractices.qdoc
index 1934be6f26..2b1c282e64 100644
--- a/src/quick/doc/src/guidelines/qtquick-bestpractices.qdoc
+++ b/src/quick/doc/src/guidelines/qtquick-bestpractices.qdoc
@@ -181,6 +181,12 @@ to a \e {.qml} file.
\li \l{Qt Design Studio: UI Files}
\endlist
+\section1 Using Qt Quick Views
+
+\section2 Store State in Models
+
+See \l {Avoid Storing State in Delegates}.
+
\section1 Using Qt Quick Layouts
Qt offers Qt Quick Layouts to arrange Qt Quick items visually in a layout.
diff --git a/src/quick/doc/src/guidelines/qtquick-toolsnutilities.qdoc b/src/quick/doc/src/guidelines/qtquick-toolsnutilities.qdoc
index 87397e43b4..f614c98ccc 100644
--- a/src/quick/doc/src/guidelines/qtquick-toolsnutilities.qdoc
+++ b/src/quick/doc/src/guidelines/qtquick-toolsnutilities.qdoc
@@ -91,24 +91,9 @@ flag for doing so by passing \c{--help} on the command line.
\section1 qmlformat
-\e qmlformat is a tool that automatically formats QML files in accordance
+\l [QtQml] {qmlformat} is a tool that automatically formats QML files in accordance
with the \l{QML Coding Conventions}.
-If you pass the \c{-n} or \c{--normalize} flag, \e qmlformat groups all
-properties, functions, and signals together, instead of retaining the order you
-specified.
-
-By default, qmlformat writes the formatted version of the file to stdout.
-If you wish to have your file updated in-place specify the \c{-i} flag.
-
-You may also change tab widths and line ending types among other settings,
-either via command line options or by using a settings file called
-\c{.qmlformat.ini}. A default settings file can be obtained by passing the
-\c{--write-defaults} flag.
-
-As with all tools, the \c{-h} or \c{--help} flag will print some information on
-all the available options.
-
\section1 Qt Quick Compiler
The Qt Quick Compiler consist of two components:
diff --git a/src/quick/handlers/qquickpinchhandler.cpp b/src/quick/handlers/qquickpinchhandler.cpp
index 6078cfd45e..971be5eb17 100644
--- a/src/quick/handlers/qquickpinchhandler.cpp
+++ b/src/quick/handlers/qquickpinchhandler.cpp
@@ -697,9 +697,17 @@ void QQuickPinchHandler::handlePointerEventImpl(QPointerEvent *event)
m_xAxis.updateValue(activeTranslation.x(), m_xAxis.persistentValue() + delta.x(), delta.x());
m_yAxis.updateValue(activeTranslation.y(), m_yAxis.persistentValue() + delta.y(), delta.y());
emit translationChanged(delta);
+ // xAxis or yAxis may be disabled; nevertheless, we use setPosition() to compensate for
+ // other aspects of the transform. So it should not be skipped. Above, we've already
+ // subtracted activeTranslation if necessary.
t->setPosition(pos);
- t->setRotation(m_rotationAxis.persistentValue());
- t->setScale(m_scaleAxis.persistentValue());
+ // Set rotation and scale properties only if the respective axes are enabled.
+ // We've already checked above, so we don't expect activeScale or activeRotation to change
+ // if the axis is disabled; but then don't call the setter at all, to avoid breaking bindings.
+ if (m_rotationAxis.enabled())
+ t->setRotation(m_rotationAxis.persistentValue());
+ if (m_scaleAxis.enabled())
+ t->setScale(m_scaleAxis.persistentValue());
} else {
auto activeTranslation = centroid().scenePosition() - centroid().scenePressPosition();
auto accumulated = QPointF(m_xAxis.m_startValue, m_yAxis.m_startValue) + activeTranslation;
diff --git a/src/quick/items/qquickflickable.cpp b/src/quick/items/qquickflickable.cpp
index 77a4bef646..29b2bafa0e 100644
--- a/src/quick/items/qquickflickable.cpp
+++ b/src/quick/items/qquickflickable.cpp
@@ -1726,7 +1726,9 @@ void QQuickFlickable::wheelEvent(QWheelEvent *event)
|| (yflick() && qAbs(d->accumulatedWheelPixelDelta.y()) > qAbs(d->accumulatedWheelPixelDelta.x() * 2))) {
d->drag(currentTimestamp, event->type(), event->position(), d->accumulatedWheelPixelDelta,
true, !d->scrollingPhase, true, velocity);
- event->accept();
+ d->updateBeginningEnd();
+ if ((xflick() && !isAtXBeginning() && !isAtXEnd()) || (yflick() && !isAtYBeginning() && !isAtYEnd()))
+ event->accept();
} else {
qCDebug(lcWheel) << "not dragging: accumulated deltas" << d->accumulatedWheelPixelDelta <<
"moving?" << isMoving() << "can flick horizontally?" << xflick() << "vertically?" << yflick();
diff --git a/src/quick/items/qquickitem.cpp b/src/quick/items/qquickitem.cpp
index 1e4af6838d..82587a178a 100644
--- a/src/quick/items/qquickitem.cpp
+++ b/src/quick/items/qquickitem.cpp
@@ -2375,6 +2375,20 @@ bool QQuickItemPrivate::canAcceptTabFocus(QQuickItem *item)
if (item == item->window()->contentItem())
return true;
+ const auto tabFocus = QGuiApplication::styleHints()->tabFocusBehavior();
+ if (tabFocus == Qt::NoTabFocus)
+ return false;
+ if (tabFocus == Qt::TabFocusAllControls)
+ return true;
+
+ QVariant editable = item->property("editable");
+ if (editable.isValid())
+ return editable.toBool();
+
+ QVariant readonly = item->property("readOnly");
+ if (readonly.isValid())
+ return !readonly.toBool() && item->property("text").isValid();
+
#if QT_CONFIG(accessibility)
QAccessible::Role role = QQuickItemPrivate::get(item)->effectiveAccessibleRole();
if (role == QAccessible::EditableText || role == QAccessible::Table || role == QAccessible::List) {
@@ -2385,14 +2399,6 @@ bool QQuickItemPrivate::canAcceptTabFocus(QQuickItem *item)
}
#endif
- QVariant editable = item->property("editable");
- if (editable.isValid())
- return editable.toBool();
-
- QVariant readonly = item->property("readOnly");
- if (readonly.isValid() && !readonly.toBool() && item->property("text").isValid())
- return true;
-
return false;
}
@@ -2473,8 +2479,6 @@ QQuickItem* QQuickItemPrivate::nextPrevItemInTabFocusChain(QQuickItem *item, boo
if (!contentItem)
return item;
- bool all = QGuiApplication::styleHints()->tabFocusBehavior() == Qt::TabFocusAllControls;
-
QQuickItem *from = nullptr;
bool isTabFence = item->d_func()->isTabFence;
if (forward) {
@@ -2594,7 +2598,7 @@ QQuickItem* QQuickItemPrivate::nextPrevItemInTabFocusChain(QQuickItem *item, boo
}
}
} while (skip || !current->activeFocusOnTab() || !current->isEnabled() || !current->isVisible()
- || !(all || QQuickItemPrivate::canAcceptTabFocus(current)));
+ || !(QQuickItemPrivate::canAcceptTabFocus(current)));
return current;
}
@@ -2666,9 +2670,10 @@ void QQuickItem::setParentItem(QQuickItem *parentItem)
while (!scopeItem->isFocusScope() && scopeItem->parentItem())
scopeItem = scopeItem->parentItem();
if (d->window) {
- d->deliveryAgentPrivate()->
- clearFocusInScope(scopeItem, scopeFocusedItem, Qt::OtherFocusReason,
+ if (QQuickDeliveryAgentPrivate *da = d->deliveryAgentPrivate()) {
+ da->clearFocusInScope(scopeItem, scopeFocusedItem, Qt::OtherFocusReason,
QQuickDeliveryAgentPrivate::DontChangeFocusProperty);
+ }
if (scopeFocusedItem != this)
QQuickItemPrivate::get(scopeFocusedItem)->updateSubFocusItem(this, true);
} else {
@@ -2742,9 +2747,10 @@ void QQuickItem::setParentItem(QQuickItem *parentItem)
emit scopeFocusedItem->focusChanged(false);
} else {
if (d->window) {
- d->deliveryAgentPrivate()->
- setFocusInScope(scopeItem, scopeFocusedItem, Qt::OtherFocusReason,
+ if (QQuickDeliveryAgentPrivate *da = d->deliveryAgentPrivate()) {
+ da->setFocusInScope(scopeItem, scopeFocusedItem, Qt::OtherFocusReason,
QQuickDeliveryAgentPrivate::DontChangeFocusProperty);
+ }
} else {
QQuickItemPrivate::get(scopeFocusedItem)->updateSubFocusItem(scopeItem, true);
}
@@ -6499,9 +6505,10 @@ bool QQuickItemPrivate::setEffectiveVisibleRecur(bool newEffectiveVisible)
dirty(Visible);
if (parentItem)
QQuickItemPrivate::get(parentItem)->dirty(ChildrenStackingChanged);
- if (window)
- if (auto agent = deliveryAgentPrivate(); agent)
+ if (window) {
+ if (auto agent = deliveryAgentPrivate())
agent->removeGrabber(q, true, true, true);
+ }
bool childVisibilityChanged = false;
for (int ii = 0; ii < childItems.size(); ++ii)
@@ -6839,12 +6846,26 @@ void QQuickItem::setSmooth(bool smooth)
key events used by Keys or KeyNavigation have precedence over
focus chain behavior; ignore the events in other key handlers
to allow it to propagate.
+
+ \note {QStyleHints::tabFocusBehavior}{tabFocusBehavior} can further limit focus
+ to only specific types of controls, such as only text or list controls. This is
+ the case on macOS, where focus to particular controls may be restricted based on
+ system settings.
+
+ \sa QStyleHints::tabFocusBehavior, focusPolicy
*/
/*!
\property QQuickItem::activeFocusOnTab
This property holds whether the item wants to be in the tab focus
chain. By default, this is set to \c false.
+
+ \note {QStyleHints::tabFocusBehavior}{tabFocusBehavior} can further limit focus
+ to only specific types of controls, such as only text or list controls. This is
+ the case on macOS, where focus to particular controls may be restricted based on
+ system settings.
+
+ \sa QStyleHints::tabFocusBehavior, focusPolicy
*/
bool QQuickItem::activeFocusOnTab() const
{
@@ -8381,7 +8402,8 @@ void QQuickItem::ungrabTouchPoints()
Q_D(QQuickItem);
if (!d->window)
return;
- d->deliveryAgentPrivate()->removeGrabber(this, false, true);
+ if (QQuickDeliveryAgentPrivate *da = d->deliveryAgentPrivate())
+ da->removeGrabber(this, false, true);
}
/*!
@@ -9877,7 +9899,7 @@ QRectF QQuickItem::mapFromItem(const QQuickItem *item, qreal x, qreal y, qreal w
//! \internal
QPointF QQuickItem::mapToItem(const QQuickItem *item, qreal x, qreal y)
-{ return mapToItem(item, QPoint(x, y)); }
+{ return mapToItem(item, QPointF(x, y)); }
//! \internal
QRectF QQuickItem::mapToItem(const QQuickItem *item, const QRectF &rect) const
diff --git a/src/quick/items/qquickitemview.cpp b/src/quick/items/qquickitemview.cpp
index 210759585b..2da1f172f1 100644
--- a/src/quick/items/qquickitemview.cpp
+++ b/src/quick/items/qquickitemview.cpp
@@ -2497,7 +2497,9 @@ bool QQuickItemViewPrivate::releaseItem(FxViewItem *item, QQmlInstanceModel::Reu
// One case where this can happen is moving an item out of one ObjectModel and into another.
QQuickItemPrivate::get(item->item)->setCulled(true);
}
- if (!isClearing)
+ // If deleteLater was called, the item isn't long for this world and so we shouldn't store references to it.
+ // This can happen when a Repeater is used to populate items in SwipeView's ListView contentItem.
+ if (!isClearing && !QObjectPrivate::get(item->item)->deleteLaterCalled)
unrequestedItems.insert(item->item, model->indexOf(item->item, q));
} else if (flags & QQmlInstanceModel::Destroyed) {
item->item->setParentItem(nullptr);
diff --git a/src/quick/items/qquicklistview.cpp b/src/quick/items/qquicklistview.cpp
index 92b66ca5ed..063c48260a 100644
--- a/src/quick/items/qquicklistview.cpp
+++ b/src/quick/items/qquicklistview.cpp
@@ -2077,7 +2077,7 @@ QQuickItemViewAttached *QQuickListViewPrivate::getAttachedObject(const QObject *
The list view itself is a focus scope (see \l{Keyboard Focus in Qt Quick} for more details).
Delegates are instantiated as needed and may be destroyed at any time.
- As such, state should \e never be stored in a delegate.
+ As such, \l {Avoid Storing State in Delegates}{state should \e never be stored in a delegate}.
Delegates are usually parented to ListView's \l {Flickable::contentItem}{contentItem}, but
typically depending on whether it's visible in the view or not, the \e parent
can change, and sometimes be \c null. Because of that, binding to
@@ -2215,8 +2215,9 @@ QQuickItemViewAttached *QQuickListViewPrivate::getAttachedObject(const QObject *
item is reused. This includes \c index and \c row, but also
any model roles.
- \note Avoid storing any state inside a delegate. If you do, reset it
- manually on receiving the \l ListView::reused signal.
+ \note \l {Avoid Storing State in Delegates}{Avoid storing any state inside
+ a delegate}. If you do, reset it manually on receiving the
+ \l ListView::reused signal.
If an item has timers or animations, consider pausing them on receiving
the \l ListView::pooled signal. That way you avoid using the CPU resources
@@ -2248,6 +2249,45 @@ QQuickItemViewAttached *QQuickListViewPrivate::getAttachedObject(const QObject *
items, at the expense of additional memory usage. \l{ListView::section}{Sections}
have the same effect because they attach and elongate the section label to the
first item within the section.
+
+ \section1 Avoid Storing State in Delegates
+
+ ListView's delegates are instantiated as needed and may be destroyed when
+ out of view. For an illustration of this, run the following example:
+
+ \snippet qml/listview/stateInDelegate.qml ListView
+
+ When an item is clicked, \c channelActivated is set to \c true. However,
+ because delegates can be \l {Reusing Items}{reused} and destroyed, all
+ state is lost when the view is moved far enough. When the delegate becomes
+ visible again, it will have its default, unmodified state (or, in the case
+ of an item that was reused, old state from a previous item).
+
+ To avoid this, state should be stored in the model:
+
+ \snippet qml/listview/stateInModel.qml ListView
+
+ \section1 Hiding Delegates
+
+ Setting a delegate's \l {Item::}{visible} property to \c false will hide
+ that item, but the space it occupied in the view will remain. It is
+ possible to set the item's \l {Item::}{height} to \c 0 (for a \l
+ {ListView::orientation}{vertical} ListView):
+
+ \snippet qml/listview/hideDelegate.qml ListView
+
+ Note that the hidden state is stored in the model, following the advice of
+ the \l {Avoid Storing State in Delegates} section.
+
+ However, if \l spacing is non-zero, there will be uneven gaps between
+ delegates.
+
+ A better option is to filter your model so that items that should not be
+ visible are not loaded by the view at all. This can be achieved with
+ \l QSortFilterProxyModel.
+
+ Another option is to \l {Item::enabled}{disable} the delegate instead of
+ hiding it.
*/
QQuickListView::QQuickListView(QQuickItem *parent)
: QQuickItemView(*(new QQuickListViewPrivate), parent)
diff --git a/src/quick/items/qquickmousearea.cpp b/src/quick/items/qquickmousearea.cpp
index 44cbec55b8..b24a733501 100644
--- a/src/quick/items/qquickmousearea.cpp
+++ b/src/quick/items/qquickmousearea.cpp
@@ -825,6 +825,7 @@ void QQuickMouseArea::hoverEnterEvent(QHoverEvent *event)
me.setPosition(d->lastPos);
emit mouseYChanged(&me);
me.setPosition(d->lastPos);
+ emit positionChanged(&me);
}
// A MouseArea should not block hover events
@@ -1224,6 +1225,10 @@ bool QQuickMouseArea::setPressed(Qt::MouseButton button, bool p, Qt::MouseEventS
{
Q_D(QQuickMouseArea);
+ // Don't allow entering pressed state while invisible
+ if (p && !d->effectiveVisible)
+ return false;
+
#if QT_CONFIG(quick_draganddrop)
bool dragged = d->drag && d->drag->active();
#else
@@ -1320,6 +1325,10 @@ bool QQuickMouseArea::setPressed(Qt::MouseButton button, bool p, Qt::MouseEventS
\endcode
The default value is \c Qt.ArrowCursor.
+
+ \note If the \c cursorShape property is set to \c undefined, the \c MouseArea will
+ not change the existing shape when entering it.
+
\sa Qt::CursorShape
*/
diff --git a/src/quick/items/qquickscreen.cpp b/src/quick/items/qquickscreen.cpp
index c8405ca9ad..cdcab39773 100644
--- a/src/quick/items/qquickscreen.cpp
+++ b/src/quick/items/qquickscreen.cpp
@@ -197,8 +197,8 @@ QT_BEGIN_NAMESPACE
QQuickScreenInfo::QQuickScreenInfo(QObject *parent, QScreen *wrappedScreen)
: QObject(parent)
- , m_screen(wrappedScreen)
{
+ setWrappedScreen(wrappedScreen);
}
QString QQuickScreenInfo::name() const
diff --git a/src/quick/items/qquickwindow.cpp b/src/quick/items/qquickwindow.cpp
index 9de90f8d82..d5d5454f22 100644
--- a/src/quick/items/qquickwindow.cpp
+++ b/src/quick/items/qquickwindow.cpp
@@ -826,13 +826,17 @@ void QQuickWindow::handleApplicationStateChanged(Qt::ApplicationState state)
QQmlListProperty<QObject> QQuickWindowPrivate::data()
{
- return QQmlListProperty<QObject>(q_func(), nullptr,
- QQuickWindowPrivate::data_append,
- QQuickWindowPrivate::data_count,
- QQuickWindowPrivate::data_at,
- QQuickWindowPrivate::data_clear,
- QQuickWindowPrivate::data_replace,
- QQuickWindowPrivate::data_removeLast);
+ QQmlListProperty<QObject> ret;
+
+ ret.object = q_func();
+ ret.append = QQuickWindowPrivate::data_append;
+ ret.count = QQuickWindowPrivate::data_count;
+ ret.at = QQuickWindowPrivate::data_at;
+ ret.clear = QQuickWindowPrivate::data_clear;
+ // replace is not supported by QQuickItem. Don't synthesize it.
+ ret.removeLast = QQuickWindowPrivate::data_removeLast;
+
+ return ret;
}
void QQuickWindowPrivate::dirtyItem(QQuickItem *)
@@ -1840,13 +1844,6 @@ void QQuickWindowPrivate::data_clear(QQmlListProperty<QObject> *property)
itemProperty.clear(&itemProperty);
}
-void QQuickWindowPrivate::data_replace(QQmlListProperty<QObject> *property, qsizetype i, QObject *o)
-{
- QQuickWindow *win = static_cast<QQuickWindow*>(property->object);
- QQmlListProperty<QObject> itemProperty = QQuickItemPrivate::get(win->contentItem())->data();
- itemProperty.replace(&itemProperty, i, o);
-}
-
void QQuickWindowPrivate::data_removeLast(QQmlListProperty<QObject> *property)
{
QQuickWindow *win = static_cast<QQuickWindow*>(property->object);
@@ -4166,8 +4163,8 @@ void QQuickWindow::setGraphicsConfiguration(const QQuickGraphicsConfiguration &c
}
/*!
- \return the QQuickGraphicsDevice passed to setGraphicsDevice(), or a
- default constructed one otherwise
+ \return the QQuickGraphicsConfiguration passed to
+ setGraphicsConfiguration(), or a default constructed one otherwise.
\since 6.0
diff --git a/src/quick/items/qquickwindow_p.h b/src/quick/items/qquickwindow_p.h
index 558c7d8fc2..6393e4a0cb 100644
--- a/src/quick/items/qquickwindow_p.h
+++ b/src/quick/items/qquickwindow_p.h
@@ -231,7 +231,6 @@ public:
static qsizetype data_count(QQmlListProperty<QObject> *);
static QObject *data_at(QQmlListProperty<QObject> *, qsizetype);
static void data_clear(QQmlListProperty<QObject> *);
- static void data_replace(QQmlListProperty<QObject> *, qsizetype, QObject *);
static void data_removeLast(QQmlListProperty<QObject> *);
static void rhiCreationFailureMessage(const QString &backendName,
diff --git a/src/quick/util/qquickpixmapcache.cpp b/src/quick/util/qquickpixmapcache.cpp
index 0cf24bfba2..ef27f22f87 100644
--- a/src/quick/util/qquickpixmapcache.cpp
+++ b/src/quick/util/qquickpixmapcache.cpp
@@ -228,7 +228,7 @@ class QQuickPixmapData
public:
QQuickPixmapData(QQuickPixmap *pixmap, const QUrl &u, const QRect &r, const QSize &rs,
const QQuickImageProviderOptions &po, const QString &e)
- : refCount(1), frameCount(1), frame(0), inCache(false), pixmapStatus(QQuickPixmap::Error),
+ : refCount(1), frameCount(1), frame(0), inCache(false), fromSpecialDevice(false), pixmapStatus(QQuickPixmap::Error),
url(u), errorString(e), requestRegion(r), requestSize(rs),
providerOptions(po), appliedTransform(QQuickImageProviderOptions::UsePluginDefaultTransform),
textureFactory(nullptr), reply(nullptr), prevUnreferenced(nullptr),
@@ -242,7 +242,7 @@ public:
QQuickPixmapData(QQuickPixmap *pixmap, const QUrl &u, const QRect &r, const QSize &s, const QQuickImageProviderOptions &po,
QQuickImageProviderOptions::AutoTransform aTransform, int frame=0, int frameCount=1)
- : refCount(1), frameCount(frameCount), frame(frame), inCache(false), pixmapStatus(QQuickPixmap::Loading),
+ : refCount(1), frameCount(frameCount), frame(frame), inCache(false), fromSpecialDevice(false), pixmapStatus(QQuickPixmap::Loading),
url(u), requestRegion(r), requestSize(s),
providerOptions(po), appliedTransform(aTransform),
textureFactory(nullptr), reply(nullptr), prevUnreferenced(nullptr), prevUnreferencedPtr(nullptr),
@@ -257,7 +257,7 @@ public:
QQuickPixmapData(QQuickPixmap *pixmap, const QUrl &u, QQuickTextureFactory *texture,
const QSize &s, const QRect &r, const QSize &rs, const QQuickImageProviderOptions &po,
QQuickImageProviderOptions::AutoTransform aTransform, int frame=0, int frameCount=1)
- : refCount(1), frameCount(frameCount), frame(frame), inCache(false), pixmapStatus(QQuickPixmap::Ready),
+ : refCount(1), frameCount(frameCount), frame(frame), inCache(false), fromSpecialDevice(false), pixmapStatus(QQuickPixmap::Ready),
url(u), implicitSize(s), requestRegion(r), requestSize(rs),
providerOptions(po), appliedTransform(aTransform),
textureFactory(texture), reply(nullptr), prevUnreferenced(nullptr),
@@ -270,7 +270,7 @@ public:
}
QQuickPixmapData(QQuickPixmap *pixmap, QQuickTextureFactory *texture)
- : refCount(1), frameCount(1), frame(0), inCache(false), pixmapStatus(QQuickPixmap::Ready),
+ : refCount(1), frameCount(1), frame(0), inCache(false), fromSpecialDevice(false), pixmapStatus(QQuickPixmap::Ready),
appliedTransform(QQuickImageProviderOptions::UsePluginDefaultTransform),
textureFactory(texture), reply(nullptr), prevUnreferenced(nullptr),
prevUnreferencedPtr(nullptr), nextUnreferenced(nullptr)
@@ -304,6 +304,7 @@ public:
int frame;
bool inCache:1;
+ bool fromSpecialDevice:1;
QQuickPixmap::Status pixmapStatus;
QUrl url;
@@ -315,7 +316,9 @@ public:
QQuickImageProviderOptions::AutoTransform appliedTransform;
QColorSpace targetColorSpace;
- QIODevice *specialDevice = nullptr;
+ QPointer<QIODevice> specialDevice;
+
+ // actual image data, after loading
QQuickTextureFactory *textureFactory;
QIntrusiveList<QQuickPixmap, &QQuickPixmap::dataListNode> declarativePixmaps;
@@ -926,9 +929,14 @@ void QQuickPixmapReader::processJob(QQuickPixmapReply *runningJob, const QUrl &u
QString errorStr;
QSize readSize;
- if (runningJob->data && runningJob->data->specialDevice) {
+ if (runningJob->data && runningJob->data->fromSpecialDevice) {
+ auto specialDevice = runningJob->data->specialDevice;
+ if (specialDevice.isNull() || QObjectPrivate::get(specialDevice.data())->deleteLaterCalled) {
+ qCDebug(lcImg) << "readImage job aborted" << url;
+ return;
+ }
int frameCount;
- if (!readImage(url, runningJob->data->specialDevice, &image, &errorStr, &readSize, &frameCount,
+ if (!readImage(url, specialDevice.data(), &image, &errorStr, &readSize, &frameCount,
runningJob->requestRegion, runningJob->requestSize,
runningJob->providerOptions, nullptr, runningJob->data->frame)) {
errorCode = QQuickPixmapReply::Loading;
@@ -1831,6 +1839,7 @@ void QQuickPixmap::loadImageFromDevice(QQmlEngine *engine, QIODevice *device, co
d = new QQuickPixmapData(this, url, requestRegion, requestSize, providerOptions,
QQuickImageProviderOptions::UsePluginDefaultTransform, frame, frameCount);
d->specialDevice = device;
+ d->fromSpecialDevice = true;
d->addToCache();
QQuickPixmapReader::readerMutex.lock();