diff options
Diffstat (limited to 'src/quick')
| -rw-r--r-- | src/quick/accessible/qaccessiblequickview.cpp | 7 | ||||
| -rw-r--r-- | src/quick/doc/snippets/qml/listview/hideDelegate.qml | 27 | ||||
| -rw-r--r-- | src/quick/doc/snippets/qml/listview/listview.qml | 9 | ||||
| -rw-r--r-- | src/quick/doc/snippets/qml/listview/stateInDelegate.qml | 20 | ||||
| -rw-r--r-- | src/quick/doc/snippets/qml/listview/stateInModel.qml | 26 | ||||
| -rw-r--r-- | src/quick/doc/src/guidelines/qtquick-bestpractices.qdoc | 6 | ||||
| -rw-r--r-- | src/quick/doc/src/guidelines/qtquick-toolsnutilities.qdoc | 17 | ||||
| -rw-r--r-- | src/quick/handlers/qquickpinchhandler.cpp | 12 | ||||
| -rw-r--r-- | src/quick/items/qquickflickable.cpp | 4 | ||||
| -rw-r--r-- | src/quick/items/qquickitem.cpp | 60 | ||||
| -rw-r--r-- | src/quick/items/qquickitemview.cpp | 4 | ||||
| -rw-r--r-- | src/quick/items/qquicklistview.cpp | 46 | ||||
| -rw-r--r-- | src/quick/items/qquickmousearea.cpp | 9 | ||||
| -rw-r--r-- | src/quick/items/qquickscreen.cpp | 2 | ||||
| -rw-r--r-- | src/quick/items/qquickwindow.cpp | 29 | ||||
| -rw-r--r-- | src/quick/items/qquickwindow_p.h | 1 | ||||
| -rw-r--r-- | src/quick/util/qquickpixmapcache.cpp | 23 |
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(); |
