aboutsummaryrefslogtreecommitdiffstats
path: root/src/quick
diff options
context:
space:
mode:
Diffstat (limited to 'src/quick')
-rw-r--r--src/quick/CMakeLists.txt4
-rw-r--r--src/quick/accessible/qaccessiblequickitem.cpp7
-rw-r--r--src/quick/doc/src/concepts/layouts/qtquicklayouts-index.qdoc12
-rw-r--r--src/quick/doc/src/concepts/layouts/qtquicklayouts-qmltypes.qdoc (renamed from src/quick/doc/src/concepts/layouts/qtquicklayouts.qdoc)0
-rw-r--r--src/quick/doc/src/concepts/visualcanvas/scenegraph.qdoc1
-rw-r--r--src/quick/doc/src/qmltypereference.qdoc14
-rw-r--r--src/quick/doc/src/qt6-changes.qdoc4
-rw-r--r--src/quick/doc/src/qtquick.qdoc27
-rw-r--r--src/quick/items/context2d/qquickcanvascontext_p.h6
-rw-r--r--src/quick/items/context2d/qquickcanvasitem_p.h1
-rw-r--r--src/quick/items/context2d/qquickcontext2d_p.h5
-rw-r--r--src/quick/items/qquickaccessibleattached.cpp5
-rw-r--r--src/quick/items/qquickdrag_p.h6
-rw-r--r--src/quick/items/qquickimplicitsizeitem_p.h2
-rw-r--r--src/quick/items/qquickitem.h1
-rw-r--r--src/quick/items/qquickloader.cpp12
-rw-r--r--src/quick/items/qquickloader_p.h1
-rw-r--r--src/quick/items/qquickloader_p_p.h4
-rw-r--r--src/quick/items/qquickrendercontrol.cpp1
-rw-r--r--src/quick/items/qquickrendercontrol.h2
-rw-r--r--src/quick/items/qquickstateoperations.cpp69
-rw-r--r--src/quick/items/qquicktableview.cpp326
-rw-r--r--src/quick/items/qquicktableview_p.h6
-rw-r--r--src/quick/items/qquicktableview_p_p.h48
-rw-r--r--src/quick/items/qquicktext.cpp49
-rw-r--r--src/quick/items/qquicktreeview.cpp315
-rw-r--r--src/quick/items/qquicktreeview_p.h16
-rw-r--r--src/quick/items/qquicktreeview_p_p.h1
-rw-r--r--src/quick/items/qquickview_p.h5
-rw-r--r--src/quick/items/qquickwindow.cpp95
-rw-r--r--src/quick/items/qquickwindow_p.h3
-rw-r--r--src/quick/scenegraph/coreapi/qsgbatchrenderer.cpp54
-rw-r--r--src/quick/scenegraph/coreapi/qsgbatchrenderer_p.h1
-rw-r--r--src/quick/scenegraph/coreapi/qsgmaterialshader.cpp17
-rw-r--r--src/quick/scenegraph/coreapi/qsgmaterialshader.h6
-rw-r--r--src/quick/scenegraph/coreapi/qsgnode.h1
-rw-r--r--src/quick/scenegraph/qsgadaptationlayer_p.h1
-rw-r--r--src/quick/scenegraph/qsgdefaultrendercontext.cpp3
-rw-r--r--src/quick/scenegraph/qsgdefaultrendercontext_p.h2
-rw-r--r--src/quick/scenegraph/qsgrenderloop.cpp4
-rw-r--r--src/quick/scenegraph/qsgrhisupport.cpp89
-rw-r--r--src/quick/scenegraph/qsgrhisupport_p.h6
-rw-r--r--src/quick/scenegraph/util/qsgrhiatlastexture.cpp9
-rw-r--r--src/quick/scenegraph/util/qsgtexturematerial.cpp2
-rw-r--r--src/quick/util/qquickapplication.cpp31
-rw-r--r--src/quick/util/qquickapplication_p.h3
-rw-r--r--src/quick/util/qquickfontloader.cpp12
-rw-r--r--src/quick/util/qquickforeignutils_p.h9
-rw-r--r--src/quick/util/qquickinputmethod.cpp159
-rw-r--r--src/quick/util/qquickinputmethod_p.h122
-rw-r--r--src/quick/util/qquickpath_p.h1
-rw-r--r--src/quick/util/qquickpixmapcache.cpp114
-rw-r--r--src/quick/util/qquickpixmapcache_p.h3
-rw-r--r--src/quick/util/qquickstate_p_p.h12
-rw-r--r--src/quick/util/qquickstategroup.cpp10
-rw-r--r--src/quick/util/qquickvalidator.cpp6
56 files changed, 1176 insertions, 549 deletions
diff --git a/src/quick/CMakeLists.txt b/src/quick/CMakeLists.txt
index 0f8733eb0f..a757ec9afa 100644
--- a/src/quick/CMakeLists.txt
+++ b/src/quick/CMakeLists.txt
@@ -509,6 +509,10 @@ qt_internal_extend_target(Quick CONDITION QT_FEATURE_wheelevent
handlers/qquickwheelhandler_p_p.h
)
+qt_internal_extend_target(Quick CONDITION QT_FEATURE_im
+ SOURCES
+ util/qquickinputmethod.cpp util/qquickinputmethod_p.h
+)
qt_internal_create_tracepoints(Quick qtquick.tracepoints)
qt_internal_add_docs(Quick
diff --git a/src/quick/accessible/qaccessiblequickitem.cpp b/src/quick/accessible/qaccessiblequickitem.cpp
index 933a5b5cbe..9a4ce960f1 100644
--- a/src/quick/accessible/qaccessiblequickitem.cpp
+++ b/src/quick/accessible/qaccessiblequickitem.cpp
@@ -448,6 +448,11 @@ QList<QQuickItem *> QAccessibleQuickItem::childItems() const
return accessibleUnignoredChildren(item());
}
+static bool isTextRole(QAccessible::Role role)
+{
+ return role == QAccessible::EditableText || role == QAccessible::StaticText;
+}
+
QAccessible::State QAccessibleQuickItem::state() const
{
QQuickAccessibleAttached *attached = QQuickAccessibleAttached::attachedProperties(item());
@@ -465,7 +470,7 @@ QAccessible::State QAccessibleQuickItem::state() const
state.offscreen = true;
if ((role() == QAccessible::CheckBox || role() == QAccessible::RadioButton) && object()->property("checked").toBool())
state.checked = true;
- if (item()->activeFocusOnTab() || role() == QAccessible::EditableText)
+ if (item()->activeFocusOnTab() || isTextRole(role()))
state.focusable = true;
if (item()->hasActiveFocus())
state.focused = true;
diff --git a/src/quick/doc/src/concepts/layouts/qtquicklayouts-index.qdoc b/src/quick/doc/src/concepts/layouts/qtquicklayouts-index.qdoc
index 15b8394ebf..cbbaa36c7b 100644
--- a/src/quick/doc/src/concepts/layouts/qtquicklayouts-index.qdoc
+++ b/src/quick/doc/src/concepts/layouts/qtquicklayouts-index.qdoc
@@ -30,17 +30,17 @@
\title Qt Quick Layouts
\brief A module with a set of QML elements that arrange QML items in a user interface.
- Qt Quick Layouts are a set of QML types used to arrange items in a user interface. In contrast
- to \l{Item Positioners}{positioners}, Qt Quick Layouts can also resize their items. This makes
- them well suited for resizable user interfaces. Since layouts are items they can consequently
- be nested.
+ Qt Quick Layouts are a set of QML types used to arrange items in a user
+ interface. In contrast to \l{Item Positioners}{positioners}, Qt Quick
+ Layouts can also resize their child items. This makes them well suited for
+ resizable user interfaces.
Visit the \l{Qt Quick Layouts Overview} page to get started.
\section1 Using the Module
- The QML types can be imported into your application by adding the following
- import statement in your \c {.qml} file.
+ The \l {Qt Quick Layouts QML Types}{QML types} can be imported into your
+ application by adding the following import statement in your \c {.qml} file.
\qml
import QtQuick.Layouts
diff --git a/src/quick/doc/src/concepts/layouts/qtquicklayouts.qdoc b/src/quick/doc/src/concepts/layouts/qtquicklayouts-qmltypes.qdoc
index 0df832cca9..0df832cca9 100644
--- a/src/quick/doc/src/concepts/layouts/qtquicklayouts.qdoc
+++ b/src/quick/doc/src/concepts/layouts/qtquicklayouts-qmltypes.qdoc
diff --git a/src/quick/doc/src/concepts/visualcanvas/scenegraph.qdoc b/src/quick/doc/src/concepts/visualcanvas/scenegraph.qdoc
index eab3b041bb..f0c7b7cbf2 100644
--- a/src/quick/doc/src/concepts/visualcanvas/scenegraph.qdoc
+++ b/src/quick/doc/src/concepts/visualcanvas/scenegraph.qdoc
@@ -185,6 +185,7 @@ force the usage of a given loop. To verify which render loop is in use, enable
the \c qt.scenegraph.general \l {QLoggingCategory}{logging category}.
\section2 Threaded Render Loop ('threaded')
+\target threaded_render_loop
On many configurations, the scene graph rendering will happen on a
dedicated render thread. This is done to increase parallelism of
diff --git a/src/quick/doc/src/qmltypereference.qdoc b/src/quick/doc/src/qmltypereference.qdoc
index 596a061c0d..5c35283a9b 100644
--- a/src/quick/doc/src/qmltypereference.qdoc
+++ b/src/quick/doc/src/qmltypereference.qdoc
@@ -80,7 +80,7 @@ available when you import \c QtQuick.
*/
/*!
- \qmlbasictype color
+ \qmlvaluetype color
\ingroup qtquickvaluetypes
\brief an ARGB color value.
\target colorvaluetypedocs
@@ -140,7 +140,7 @@ available when you import \c QtQuick.
*/
/*!
- \qmlbasictype font
+ \qmlvaluetype font
\ingroup qtquickvaluetypes
\brief a font value with the properties of QFont.
\target fontvaluetypedocs
@@ -256,7 +256,7 @@ available when you import \c QtQuick.
*/
/*!
- \qmlbasictype vector2d
+ \qmlvaluetype vector2d
\ingroup qtquickvaluetypes
\brief A vector2d type has x and y attributes.
@@ -384,7 +384,7 @@ console.log(c + " " + d); // false true
*/
/*!
- \qmlbasictype vector3d
+ \qmlvaluetype vector3d
\ingroup qtquickvaluetypes
\brief a value with x, y, and z attributes.
@@ -555,7 +555,7 @@ console.log(c + " " + d); // false true
*/
/*!
- \qmlbasictype vector4d
+ \qmlvaluetype vector4d
\ingroup qtquickvaluetypes
\brief A vector4d type has x, y, z and w attributes.
@@ -696,7 +696,7 @@ console.log(c + " " + d); // false true
*/
/*!
- \qmlbasictype quaternion
+ \qmlvaluetype quaternion
\ingroup qtquickvaluetypes
\brief A quaternion type has scalar, x, y, and z attributes.
@@ -856,7 +856,7 @@ console.log(c + " " + d); // false true
*/
/*!
- \qmlbasictype matrix4x4
+ \qmlvaluetype matrix4x4
\ingroup qtquickvaluetypes
\brief A matrix4x4 type is a 4-row and 4-column matrix
diff --git a/src/quick/doc/src/qt6-changes.qdoc b/src/quick/doc/src/qt6-changes.qdoc
index 58a7ebb3e1..defacd95a1 100644
--- a/src/quick/doc/src/qt6-changes.qdoc
+++ b/src/quick/doc/src/qt6-changes.qdoc
@@ -138,7 +138,7 @@
OpenGL. It will not be functional when using another graphics API, such as
Vulkan or Metal. Applications relying on QQuickWidget should force the usage
of OpenGL by calling
- \c{QQuickWindow::setGraphicsApi(QSGRendererInterface::OpenGLRhi)} in their
+ \c{QQuickWindow::setGraphicsApi(QSGRendererInterface::OpenGL)} in their
main() function.
\section2 Changes to QQuick* APIs
@@ -206,7 +206,7 @@
not be functional when using another graphics API, such as Vulkan or Metal.
Applications relying on QQuickFramebufferObject should force the usage of
OpenGL by calling
- \c{QQuickWindow::setGraphicsApi(QSGRendererInterface::OpenGLRhi)} in their
+ \c{QQuickWindow::setGraphicsApi(QSGRendererInterface::OpenGL)} in their
main() function.
\li QQuickRenderControl has a slightly changed API: grab() is now
diff --git a/src/quick/doc/src/qtquick.qdoc b/src/quick/doc/src/qtquick.qdoc
index a8665a3641..2e070fa8df 100644
--- a/src/quick/doc/src/qtquick.qdoc
+++ b/src/quick/doc/src/qtquick.qdoc
@@ -38,26 +38,25 @@ provides a visual canvas and includes types for creating and animating
visual components, receiving user input, creating data models and views
and delayed object instantiation.
-The Qt Quick module provides both a \l{Qt Quick QML Types}{QML API} which supplies
-QML types for creating user interfaces with the QML language, and a
+The Qt Quick module provides both a \l{Qt Quick QML Types}{QML API}, which
+supplies QML types for creating user interfaces with the QML language, and a
\l{Qt Quick C++ Classes}{C++ API} for extending QML applications with C++ code.
\note A set of Qt Quick-based UI controls is also available to create user
interfaces. See \l{Qt Quick Controls} for more information.
-For those new to QML and Qt Quick, please see
-\l{QML Applications}
-for an introduction to writing QML applications.
+If you're new to QML and Qt Quick, please see \l{QML Applications} for an
+introduction to writing QML applications.
\section1 Using the Module
\section2 QML API
-The QML types in Qt Quick are available through the \c QtQuick import. To use the
-types, add the following import statement to your .qml file:
+The QML types in Qt Quick are available through the \c QtQuick import. To use
+the types, add the following import statement to your .qml file:
\qml
-import QtQml
+import QtQuick
\endqml
\section2 C++ API
@@ -87,13 +86,13 @@ QT += quick
\section1 Important Concepts in Qt Quick
-Qt Quick provides everything needed to create a rich application with a fluid
-and dynamic user interface. It enables user interfaces to be built around the
+Qt Quick provides everything you need to create a rich application with a fluid
+and dynamic user interface. It enables you to build user interfaces around the
behavior of user interface components and how they connect with one another,
and it provides a visual canvas with its own coordinate system and rendering
-engine. Animation and transition effects are a first class concept in Qt Quick,
-and visual effects can be supplemented through specialized components for
-particle and shader effects.
+engine. Animation and transition effects are first class concepts in Qt Quick,
+and you can add visual effects through specialized components for particle and
+shader effects.
\list
\li \l{Important Concepts In Qt Quick - The Visual Canvas}{The Visual Canvas}
@@ -105,7 +104,7 @@ particle and shader effects.
\li \l{Important Concepts In Qt Quick - Convenience Types}{Convenience Types}
\endlist
-When using the \c QtQuick module, you will need to know how to write QML
+When using the Qt Quick module, you will need to know how to write QML
applications using the QML language. In particular, QML Basics and QML
Essentials from the \l{QML Applications} page.
diff --git a/src/quick/items/context2d/qquickcanvascontext_p.h b/src/quick/items/context2d/qquickcanvascontext_p.h
index ffb01563ed..dcfa863553 100644
--- a/src/quick/items/context2d/qquickcanvascontext_p.h
+++ b/src/quick/items/context2d/qquickcanvascontext_p.h
@@ -56,10 +56,14 @@
QT_REQUIRE_CONFIG(quick_canvas);
#include <QtQuick/qquickitem.h>
-#include <QtQml/private/qv4value_p.h>
+#include <QtQml/private/qv4staticvalue_p.h>
QT_BEGIN_NAMESPACE
+namespace QV4 {
+ struct ExecutionEngine;
+}
+
class QQuickCanvasItem;
class QSGLayer;
diff --git a/src/quick/items/context2d/qquickcanvasitem_p.h b/src/quick/items/context2d/qquickcanvasitem_p.h
index 1972a9a507..11e1ec3fb2 100644
--- a/src/quick/items/context2d/qquickcanvasitem_p.h
+++ b/src/quick/items/context2d/qquickcanvasitem_p.h
@@ -67,6 +67,7 @@ class QQuickCanvasContext;
class QQuickCanvasItemPrivate;
class QQuickPixmap;
+class QQmlV4Function;
class QQuickCanvasPixmap : public QQmlRefCount
{
diff --git a/src/quick/items/context2d/qquickcontext2d_p.h b/src/quick/items/context2d/qquickcontext2d_p.h
index ea1354725f..d769c4396b 100644
--- a/src/quick/items/context2d/qquickcontext2d_p.h
+++ b/src/quick/items/context2d/qquickcontext2d_p.h
@@ -67,7 +67,6 @@ QT_REQUIRE_CONFIG(quick_canvas);
#include <QtCore/qqueue.h>
#include <QtCore/QWaitCondition>
-#include <private/qv4value_p.h>
#include <private/qv4persistent_p.h>
//#define QQUICKCONTEXT2D_DEBUG //enable this for just DEBUG purpose!
@@ -78,6 +77,10 @@ QT_REQUIRE_CONFIG(quick_canvas);
QT_BEGIN_NAMESPACE
+namespace QV4 {
+ struct ExecutionEngine;
+}
+
class QQuickContext2DCommandBuffer;
class QQuickContext2DTexture;
class QQuickPixmap;
diff --git a/src/quick/items/qquickaccessibleattached.cpp b/src/quick/items/qquickaccessibleattached.cpp
index 0b593c0089..730bbe4404 100644
--- a/src/quick/items/qquickaccessibleattached.cpp
+++ b/src/quick/items/qquickaccessibleattached.cpp
@@ -406,9 +406,10 @@ void QQuickAccessibleAttached::setRole(QAccessible::Role role)
m_state.focusable = true;
break;
case QAccessible::StaticText:
- if (!m_stateExplicitlySet.readOnly) {
+ if (!m_stateExplicitlySet.readOnly)
m_state.readOnly = true;
- }
+ if (!m_stateExplicitlySet.focusable)
+ m_state.focusable = true;
break;
default:
break;
diff --git a/src/quick/items/qquickdrag_p.h b/src/quick/items/qquickdrag_p.h
index e17a28d07e..a84af80ee9 100644
--- a/src/quick/items/qquickdrag_p.h
+++ b/src/quick/items/qquickdrag_p.h
@@ -73,11 +73,11 @@ class QQuickDragGrabber
class Item : public QQmlGuard<QQuickItem>
{
public:
- Item(QQuickItem *item) : QQmlGuard<QQuickItem>(item) {}
+ Item(QQuickItem *item) : QQmlGuard<QQuickItem>(Item::objectDestroyedImpl, item) {}
QIntrusiveListNode node;
- protected:
- void objectDestroyed(QQuickItem *) override { delete this; }
+ private:
+ static void objectDestroyedImpl(QQmlGuardImpl *guard) { delete static_cast<Item *>(guard); }
};
typedef QIntrusiveList<Item, &Item::node> ItemList;
diff --git a/src/quick/items/qquickimplicitsizeitem_p.h b/src/quick/items/qquickimplicitsizeitem_p.h
index 41f682fe57..3cf91cdc8f 100644
--- a/src/quick/items/qquickimplicitsizeitem_p.h
+++ b/src/quick/items/qquickimplicitsizeitem_p.h
@@ -51,8 +51,8 @@
// We mean it.
//
-#include "qquickpainteditem.h"
#include <private/qtquickglobal_p.h>
+#include <QtQuick/qquickitem.h>
QT_BEGIN_NAMESPACE
diff --git a/src/quick/items/qquickitem.h b/src/quick/items/qquickitem.h
index 197d891b2a..2fdb0f00c8 100644
--- a/src/quick/items/qquickitem.h
+++ b/src/quick/items/qquickitem.h
@@ -477,6 +477,7 @@ private:
friend class QSGRenderer;
friend class QAccessibleQuickItem;
friend class QQuickAccessibleAttached;
+ friend class QQuickAnchorChanges;
Q_DISABLE_COPY(QQuickItem)
Q_DECLARE_PRIVATE(QQuickItem)
};
diff --git a/src/quick/items/qquickloader.cpp b/src/quick/items/qquickloader.cpp
index bde39d99bd..ea1aa7b0c9 100644
--- a/src/quick/items/qquickloader.cpp
+++ b/src/quick/items/qquickloader.cpp
@@ -1041,9 +1041,15 @@ void QQuickLoaderPrivate::createComponent()
const QQmlComponent::CompilationMode mode = asynchronous
? QQmlComponent::Asynchronous
: QQmlComponent::PreferSynchronous;
- QQmlContext *context = qmlContext(q);
- component.setObject(new QQmlComponent(
- context->engine(), context->resolvedUrl(source), mode, q), q);
+ if (QQmlContext *context = qmlContext(q)) {
+ if (QQmlEngine *engine = context->engine()) {
+ component.setObject(new QQmlComponent(
+ engine, context->resolvedUrl(source), mode, q), q);
+ return;
+ }
+ }
+
+ qmlWarning(q) << "createComponent: Cannot find a QML engine.";
}
#include <moc_qquickloader_p.cpp>
diff --git a/src/quick/items/qquickloader_p.h b/src/quick/items/qquickloader_p.h
index 1d60f2845f..c6216ccc7c 100644
--- a/src/quick/items/qquickloader_p.h
+++ b/src/quick/items/qquickloader_p.h
@@ -56,6 +56,7 @@
QT_BEGIN_NAMESPACE
class QQuickLoaderPrivate;
+class QQmlV4Function;
class Q_QUICK_PRIVATE_EXPORT QQuickLoader : public QQuickImplicitSizeItem
{
Q_OBJECT
diff --git a/src/quick/items/qquickloader_p_p.h b/src/quick/items/qquickloader_p_p.h
index b178803c7d..dac9e2cb59 100644
--- a/src/quick/items/qquickloader_p_p.h
+++ b/src/quick/items/qquickloader_p_p.h
@@ -56,12 +56,14 @@
#include "qquickitemchangelistener_p.h"
#include <qqmlincubator.h>
-#include <private/qv4value_p.h>
+#include <private/qv4staticvalue_p.h>
+#include <private/qv4persistent_p.h>
QT_BEGIN_NAMESPACE
class QQuickLoaderPrivate;
+class QQmlV4Function;
class QQuickLoaderIncubator : public QQmlIncubator
{
public:
diff --git a/src/quick/items/qquickrendercontrol.cpp b/src/quick/items/qquickrendercontrol.cpp
index 1f690f1e85..5d29408b06 100644
--- a/src/quick/items/qquickrendercontrol.cpp
+++ b/src/quick/items/qquickrendercontrol.cpp
@@ -331,6 +331,7 @@ bool QQuickRenderControl::initialize()
params.initialSurfacePixelSize = d->window->size() * d->window->effectiveDevicePixelRatio();
params.maybeSurface = d->window;
renderContext->initialize(&params);
+ d->initialized = true;
} else {
qWarning("QRhi is only compatible with default adaptation");
return false;
diff --git a/src/quick/items/qquickrendercontrol.h b/src/quick/items/qquickrendercontrol.h
index 38e46b10d4..8f16940ea3 100644
--- a/src/quick/items/qquickrendercontrol.h
+++ b/src/quick/items/qquickrendercontrol.h
@@ -81,7 +81,7 @@ public:
QQuickWindow *window() const;
protected:
- QQuickRenderControl(QQuickRenderControlPrivate &dd, QObject *parent = nullptr);
+ explicit QQuickRenderControl(QQuickRenderControlPrivate &dd, QObject *parent = nullptr);
Q_SIGNALS:
void renderRequested();
diff --git a/src/quick/items/qquickstateoperations.cpp b/src/quick/items/qquickstateoperations.cpp
index 54517e1ed6..719c682769 100644
--- a/src/quick/items/qquickstateoperations.cpp
+++ b/src/quick/items/qquickstateoperations.cpp
@@ -482,12 +482,12 @@ void QQuickParentChangePrivate::reverseRewindHelper(const std::unique_ptr<QQuick
{
if (!target || !snapshot)
return;
- auto targetPriv = QQuickItemPrivate::get(target);
+
// leave existing bindings alive; new bindings are applied in applyBindings
- targetPriv->x.setValueBypassingBindings(snapshot->x);
- targetPriv->y.setValueBypassingBindings(snapshot->y);
- targetPriv->width.setValueBypassingBindings(snapshot->width);
- targetPriv->height.setValueBypassingBindings(snapshot->height);
+ // setPosition and setSize update the geometry without invalidating bindings
+ target->setPosition(QPointF(snapshot->x, snapshot->y));
+ target->setSize(QSizeF(snapshot->width, snapshot->height));
+
target->setScale(snapshot->scale);
target->setRotation(snapshot->rotation);
target->setParentItem(snapshot->parent);
@@ -1094,6 +1094,7 @@ void QQuickAnchorChanges::reverse()
QQuickAnchors::Anchors stateHAnchors = d->anchorSet->d_func()->usedAnchors & QQuickAnchors::Horizontal_Mask;
QQuickAnchors::Anchors origHAnchors = targetPrivate->anchors()->usedAnchors() & QQuickAnchors::Horizontal_Mask;
+ const QRectF oldGeometry(d->target->position(), d->target->size());
bool stateSetWidth = (stateHAnchors &&
stateHAnchors != QQuickAnchors::LeftAnchor &&
stateHAnchors != QQuickAnchors::RightAnchor &&
@@ -1102,8 +1103,11 @@ void QQuickAnchorChanges::reverse()
origHAnchors != QQuickAnchors::LeftAnchor &&
origHAnchors != QQuickAnchors::RightAnchor &&
origHAnchors != QQuickAnchors::HCenterAnchor);
- if (d->origWidth.isValid() && stateSetWidth && !origSetWidth)
- d->target->setWidth(d->origWidth.value);
+ if (d->origWidth.isValid() && stateSetWidth && !origSetWidth && !qt_is_nan(d->origWidth)) {
+ targetPrivate->widthValidFlag = true;
+ if (targetPrivate->width != d->origWidth)
+ targetPrivate->width.setValueBypassingBindings(d->origWidth);
+ }
bool stateSetHeight = (stateVAnchors &&
stateVAnchors != QQuickAnchors::TopAnchor &&
@@ -1115,14 +1119,23 @@ void QQuickAnchorChanges::reverse()
origVAnchors != QQuickAnchors::BottomAnchor &&
origVAnchors != QQuickAnchors::VCenterAnchor &&
origVAnchors != QQuickAnchors::BaselineAnchor);
- if (d->origHeight.isValid() && stateSetHeight && !origSetHeight)
- d->target->setHeight(d->origHeight.value);
+ if (d->origHeight.isValid() && stateSetHeight && !origSetHeight && !!qt_is_nan(d->origHeight)) {
+ targetPrivate->heightValidFlag = true;
+ if (targetPrivate->height != d->origHeight)
+ targetPrivate->height.setValueBypassingBindings(d->origHeight);
+ }
- if (stateHAnchors && !origHAnchors)
- d->target->setX(d->origX);
+ if (stateHAnchors && !origHAnchors && !qt_is_nan(d->origX) && d->origX != targetPrivate->x)
+ targetPrivate->x.setValueBypassingBindings(d->origX);
- if (stateVAnchors && !origVAnchors)
- d->target->setY(d->origY);
+ if (stateVAnchors && !origVAnchors && !qt_is_nan(d->origY) && d->origY != targetPrivate->y)
+ targetPrivate->y.setValueBypassingBindings(d->origY);
+
+ const QRectF newGeometry(d->target->position(), d->target->size());
+ if (newGeometry != oldGeometry) {
+ targetPrivate->dirty(QQuickItemPrivate::Position);
+ d->target->geometryChange(newGeometry, oldGeometry);
+ }
}
QQuickStateActionEvent::EventType QQuickAnchorChanges::type() const
@@ -1316,15 +1329,31 @@ void QQuickAnchorChanges::rewind()
return;
QQuickItemPrivate *targetPrivate = QQuickItemPrivate::get(d->target);
+ const QRectF oldGeometry(d->target->position(), d->target->size());
+
+ // Restore previous values (but not previous bindings, i.e. anchors).
+ // Also, don't drop any new bindings.
+ if (!qt_is_nan(d->rewindX) && d->rewindX != targetPrivate->x)
+ targetPrivate->x.setValueBypassingBindings(d->rewindX);
+ if (!qt_is_nan(d->rewindY) && d->rewindY != targetPrivate->y)
+ targetPrivate->y.setValueBypassingBindings(d->rewindY);
+
+ if (targetPrivate->widthValid() && !qt_is_nan(d->rewindWidth)) {
+ targetPrivate->widthValidFlag = true;
+ if (d->rewindWidth != targetPrivate->width)
+ targetPrivate->width.setValueBypassingBindings(d->rewindWidth);
+ }
- //restore previous values (but not previous bindings, i.e. anchors)
- d->target->setX(d->rewindX);
- d->target->setY(d->rewindY);
- if (targetPrivate->widthValid()) {
- d->target->setWidth(d->rewindWidth);
+ if (targetPrivate->heightValid() && !qt_is_nan(d->rewindHeight)) {
+ targetPrivate->heightValidFlag = true;
+ if (d->rewindHeight != targetPrivate->height)
+ targetPrivate->height.setValueBypassingBindings(d->rewindHeight);
}
- if (targetPrivate->heightValid()) {
- d->target->setHeight(d->rewindHeight);
+
+ const QRectF newGeometry(d->target->position(), d->target->size());
+ if (newGeometry != oldGeometry) {
+ targetPrivate->dirty(QQuickItemPrivate::Position);
+ d->target->geometryChange(newGeometry, oldGeometry);
}
}
diff --git a/src/quick/items/qquicktableview.cpp b/src/quick/items/qquicktableview.cpp
index 4ab8c954d1..adde42321c 100644
--- a/src/quick/items/qquicktableview.cpp
+++ b/src/quick/items/qquicktableview.cpp
@@ -556,8 +556,8 @@
/*!
\qmlmethod Point QtQuick::TableView::cellAtPos(point position, bool includeSpacing)
- Returns the cell at the given \a position in the view. If no cell intersects with
- \a position, the return value will be \c point(-1, -1).
+ Returns the cell at the given \a position in the view. If no \l {isRowLoaded()}{loaded}
+ cell intersects with \a position, the return value will be \c point(-1, -1).
If \a includeSpacing is set to \c true, a cell's bounding box will be considered
to include half the adjacent \l rowSpacing and \l columnSpacing on each side. The
@@ -643,6 +643,66 @@
*/
/*!
+ \qmlmethod QModelIndex QtQuick::TableView::modelIndex(int row, int column)
+ \since 6.4
+
+ Returns the \l QModelIndex that maps to \a row and \a column in the view.
+
+ \a row and \a column should be the row and column in the view (table row and
+ table column), and not a row and column in the model.
+
+ \sa rowAtIndex(), columnAtIndex()
+*/
+
+/*!
+ \qmlmethod QModelIndex QtQuick::TableView::modelIndex(point cell)
+ \since 6.4
+
+ Convenience function for doing:
+ \code
+ modelIndex(cell.y, cell.x)
+ \endcode
+
+ A cell is simply a \l point that combines row and column into
+ a single type. Note that \c point.x will map to the column, and
+ \c point.y will map to the row.
+*/
+
+/*!
+ \qmlmethod int QtQuick::TableView::rowAtIndex(QModelIndex modelIndex)
+ \since 6.4
+
+ Returns the row in the view that maps to \a modelIndex in the model.
+
+ \sa columnAtIndex(), modelIndex()
+*/
+
+/*!
+ \qmlmethod int QtQuick::TableView::columnAtIndex(QModelIndex modelIndex)
+ \since 6.4
+
+ Returns the column in the view that maps to \a modelIndex in the model.
+
+ \sa rowAtIndex(), modelIndex()
+*/
+
+/*!
+ \qmlmethod point QtQuick::TableView::cellAtIndex(QModelIndex modelIndex)
+ \since 6.4
+
+ Returns the cell in the view that maps to \a modelIndex in the model.
+ Convenience function for doing:
+
+ \code
+ Qt.point(columnAtIndex(modelIndex), rowAtIndex(modelIndex))
+ \endcode
+
+ A cell is simply a \l point that combines row and column into
+ a single type. Note that \c point.x will map to the column, and
+ \c point.y will map to the row.
+*/
+
+/*!
\qmlattachedproperty TableView QtQuick::TableView::view
This attached property holds the view that manages the delegate instance.
@@ -688,10 +748,9 @@ Q_LOGGING_CATEGORY(lcTableViewDelegateLifecycle, "qt.quick.tableview.lifecycle")
#define Q_TABLEVIEW_ASSERT(cond, output) Q_ASSERT((cond) || [&](){ dumpTable(); qWarning() << "output:" << output; return false;}())
static const Qt::Edge allTableEdges[] = { Qt::LeftEdge, Qt::RightEdge, Qt::TopEdge, Qt::BottomEdge };
-static const int kEdgeIndexNotSet = -2;
-static const int kEdgeIndexAtEnd = -3;
-static const char* kRequiredProperty = "_qt_isrequiredpropery_selected";
+static const char* kRequiredProperties = "_qt_tableview_requiredpropertymask";
+static const char* kRequiredProperty_selected = "selected";
const QPoint QQuickTableViewPrivate::kLeft = QPoint(-1, 0);
const QPoint QQuickTableViewPrivate::kRight = QPoint(1, 0);
@@ -782,6 +841,40 @@ void QQuickTableViewPrivate::dumpTable() const
qWarning() << "Window capture saved to:" << path;
}
+void QQuickTableViewPrivate::setRequiredProperty(const char *property,
+ const QVariant &value, int serializedModelIndex, QObject *object, bool init)
+{
+ if (!qobject_cast<QQmlTableInstanceModel *>(model)) {
+ // TableView only supports using required properties when backed by
+ // a QQmlTableInstanceModel. This is almost always the case, except
+ // if you assign it an ObjectModel or a DelegateModel (which are really
+ // not supported by TableView, it expects a QAIM).
+ return;
+ }
+
+ // Attaching a property list to the delegate item is just a
+ // work-around until QMetaProperty::isRequired() works (QTBUG-98846).
+ const QString propertyName = QString::fromUtf8(property);
+
+ if (init) {
+ const bool wasRequired = model->setRequiredProperty(serializedModelIndex, propertyName, value);
+ if (wasRequired) {
+ QStringList propertyList = object->property(kRequiredProperties).toStringList();
+ object->setProperty(kRequiredProperties, propertyList << propertyName);
+ }
+ } else {
+ const QStringList propertyList = object->property(kRequiredProperties).toStringList();
+ if (!propertyList.contains(propertyName)) {
+ // We only write to properties that are required
+ return;
+ }
+ const auto metaObject = object->metaObject();
+ const int propertyIndex = metaObject->indexOfProperty(property);
+ const auto metaProperty = metaObject->property(propertyIndex);
+ metaProperty.write(object, value);
+ }
+}
+
QQuickItem *QQuickTableViewPrivate::selectionPointerHandlerTarget() const
{
return const_cast<QQuickTableView *>(q_func())->contentItem();
@@ -993,7 +1086,7 @@ QSizeF QQuickTableViewPrivate::scrollTowardsSelectionPoint(const QPointF &pos, c
const bool outsideBottom = pos.y() >= viewportRect.bottom() - 1;
if (outsideLeft) {
- const bool firstColumnLoaded = nextVisibleEdgeIndexAroundLoadedTable(Qt::LeftEdge) == kEdgeIndexAtEnd;
+ const bool firstColumnLoaded = atTableEnd(Qt::LeftEdge);
const qreal remainingDist = viewportRect.left() - loadedTableOuterRect.left();
if (remainingDist > 0 || !firstColumnLoaded) {
qreal stepX = step.width();
@@ -1003,7 +1096,7 @@ QSizeF QQuickTableViewPrivate::scrollTowardsSelectionPoint(const QPointF &pos, c
dist.setWidth(pos.x() - viewportRect.left() - 1);
}
} else if (outsideRight) {
- const bool lastColumnLoaded = nextVisibleEdgeIndexAroundLoadedTable(Qt::RightEdge) == kEdgeIndexAtEnd;
+ const bool lastColumnLoaded = atTableEnd(Qt::RightEdge);
const qreal remainingDist = loadedTableOuterRect.right() - viewportRect.right();
if (remainingDist > 0 || !lastColumnLoaded) {
qreal stepX = step.width();
@@ -1015,7 +1108,7 @@ QSizeF QQuickTableViewPrivate::scrollTowardsSelectionPoint(const QPointF &pos, c
}
if (outsideTop) {
- const bool firstRowLoaded = nextVisibleEdgeIndexAroundLoadedTable(Qt::TopEdge) == kEdgeIndexAtEnd;
+ const bool firstRowLoaded = atTableEnd(Qt::TopEdge);
const qreal remainingDist = viewportRect.top() - loadedTableOuterRect.top();
if (remainingDist > 0 || !firstRowLoaded) {
qreal stepY = step.height();
@@ -1025,7 +1118,7 @@ QSizeF QQuickTableViewPrivate::scrollTowardsSelectionPoint(const QPointF &pos, c
dist.setHeight(pos.y() - viewportRect.top() - 1);
}
} else if (outsideBottom) {
- const bool lastRowLoaded = nextVisibleEdgeIndexAroundLoadedTable(Qt::BottomEdge) == kEdgeIndexAtEnd;
+ const bool lastRowLoaded = atTableEnd(Qt::BottomEdge);
const qreal remainingDist = loadedTableOuterRect.bottom() - viewportRect.bottom();
if (remainingDist > 0 || !lastRowLoaded) {
qreal stepY = step.height();
@@ -1081,14 +1174,13 @@ int QQuickTableViewPrivate::modelIndexToCellIndex(const QModelIndex &modelIndex)
{
// Convert QModelIndex to cell index. A cell index is just an
// integer representation of a cell instead of using a QPoint.
- if (modelIndex.parent().isValid()) {
- // TableView only uses the root items of the model
+ const QPoint cell = q_func()->cellAtIndex(modelIndex);
+ if (!cellIsValid(cell))
return -1;
- }
- return modelIndexAtCell(QPoint(modelIndex.column(), modelIndex.row()));
+ return modelIndexAtCell(cell);
}
-int QQuickTableViewPrivate::edgeToArrayIndex(Qt::Edge edge)
+int QQuickTableViewPrivate::edgeToArrayIndex(Qt::Edge edge) const
{
return int(log2(float(edge)));
}
@@ -1102,7 +1194,7 @@ void QQuickTableViewPrivate::clearEdgeSizeCache()
cachedNextVisibleEdgeIndex[edgeToArrayIndex(edge)].startIndex = kEdgeIndexNotSet;
}
-int QQuickTableViewPrivate::nextVisibleEdgeIndexAroundLoadedTable(Qt::Edge edge)
+int QQuickTableViewPrivate::nextVisibleEdgeIndexAroundLoadedTable(Qt::Edge edge) const
{
// Find the next column (or row) around the loaded table that is
// visible, and should be loaded next if the content item moves.
@@ -1117,7 +1209,7 @@ int QQuickTableViewPrivate::nextVisibleEdgeIndexAroundLoadedTable(Qt::Edge edge)
return nextVisibleEdgeIndex(edge, startIndex);
}
-int QQuickTableViewPrivate::nextVisibleEdgeIndex(Qt::Edge edge, int startIndex)
+int QQuickTableViewPrivate::nextVisibleEdgeIndex(Qt::Edge edge, int startIndex) const
{
// First check if we have already searched for the first visible index
// after the given startIndex recently, and if so, return the cached result.
@@ -1200,28 +1292,6 @@ int QQuickTableViewPrivate::nextVisibleEdgeIndex(Qt::Edge edge, int startIndex)
return foundIndex;
}
-bool QQuickTableViewPrivate::allColumnsLoaded()
-{
- // Returns true if all the columns in the model (that are not
- // hidden by the columnWidthProvider) are currently loaded and visible.
- const bool firstColumnLoaded = nextVisibleEdgeIndexAroundLoadedTable(Qt::LeftEdge) == kEdgeIndexAtEnd;
- if (!firstColumnLoaded)
- return false;
- bool lastColumnLoaded = nextVisibleEdgeIndexAroundLoadedTable(Qt::RightEdge) == kEdgeIndexAtEnd;
- return lastColumnLoaded;
-}
-
-bool QQuickTableViewPrivate::allRowsLoaded()
-{
- // Returns true if all the rows in the model (that are not hidden
- // by the columnWidthProvider) are currently loaded and visible.
- const bool firstColumnLoaded = nextVisibleEdgeIndexAroundLoadedTable(Qt::TopEdge) == kEdgeIndexAtEnd;
- if (!firstColumnLoaded)
- return false;
- bool lastColumnLoaded = nextVisibleEdgeIndexAroundLoadedTable(Qt::BottomEdge) == kEdgeIndexAtEnd;
- return lastColumnLoaded;
-}
-
void QQuickTableViewPrivate::updateContentWidth()
{
// Note that we actually never really know what the content size / size of the full table will
@@ -1941,6 +2011,13 @@ qreal QQuickTableViewPrivate::getColumnLayoutWidth(int column)
return columnWidth;
}
+qreal QQuickTableViewPrivate::getEffectiveRowY(int row) const
+{
+ // Return y pos of row after layout
+ Q_TABLEVIEW_ASSERT(loadedRows.contains(row), row);
+ return loadedTableItem(QPoint(leftColumn(), row))->geometry().y();
+}
+
qreal QQuickTableViewPrivate::getEffectiveRowHeight(int row) const
{
// Return row height after layout
@@ -1948,6 +2025,13 @@ qreal QQuickTableViewPrivate::getEffectiveRowHeight(int row) const
return loadedTableItem(QPoint(leftColumn(), row))->geometry().height();
}
+qreal QQuickTableViewPrivate::getEffectiveColumnX(int column) const
+{
+ // Return x pos of column after layout
+ Q_TABLEVIEW_ASSERT(loadedColumns.contains(column), column);
+ return loadedTableItem(QPoint(column, topRow()))->geometry().x();
+}
+
qreal QQuickTableViewPrivate::getEffectiveColumnWidth(int column) const
{
// Return column width after layout
@@ -1989,7 +2073,7 @@ qreal QQuickTableViewPrivate::getRowLayoutHeight(int row)
return rowHeight;
}
-qreal QQuickTableViewPrivate::getColumnWidth(int column)
+qreal QQuickTableViewPrivate::getColumnWidth(int column) const
{
// Return the width of the given column, if explicitly set. Return 0 if the column
// is hidden, and -1 if the width is not set (which means that the width should
@@ -2030,7 +2114,7 @@ qreal QQuickTableViewPrivate::getColumnWidth(int column)
return columnWidth;
}
-qreal QQuickTableViewPrivate::getRowHeight(int row)
+qreal QQuickTableViewPrivate::getRowHeight(int row) const
{
// Return the height of the given row, if explicitly set. Return 0 if the row
// is hidden, and -1 if the height is not set (which means that the height should
@@ -2071,14 +2155,14 @@ qreal QQuickTableViewPrivate::getRowHeight(int row)
return rowHeight;
}
-bool QQuickTableViewPrivate::isColumnHidden(int column)
+bool QQuickTableViewPrivate::isColumnHidden(int column) const
{
// A column is hidden if the width is explicit set to zero (either by
// using a columnWidthProvider, or by overriding getColumnWidth()).
return qFuzzyIsNull(getColumnWidth(column));
}
-bool QQuickTableViewPrivate::isRowHidden(int row)
+bool QQuickTableViewPrivate::isRowHidden(int row) const
{
// A row is hidden if the height is explicit set to zero (either by
// using a rowHeightProvider, or by overriding getRowHeight()).
@@ -2336,18 +2420,25 @@ void QQuickTableViewPrivate::processRebuildTable()
return;
}
+ if (rebuildState == RebuildState::CancelOvershoot) {
+ cancelOvershootAfterLayout();
+ loadAndUnloadVisibleEdges();
+ if (!moveToNextRebuildState())
+ return;
+ }
+
const bool preload = (rebuildOptions & RebuildOption::All
&& reusableFlag == QQmlTableInstanceModel::Reusable);
if (rebuildState == RebuildState::PreloadColumns) {
- if (preload && nextVisibleEdgeIndexAroundLoadedTable(Qt::RightEdge) != kEdgeIndexAtEnd)
+ if (preload && !atTableEnd(Qt::RightEdge))
loadEdge(Qt::RightEdge, QQmlIncubator::AsynchronousIfNested);
if (!moveToNextRebuildState())
return;
}
if (rebuildState == RebuildState::PreloadRows) {
- if (preload && nextVisibleEdgeIndexAroundLoadedTable(Qt::BottomEdge) != kEdgeIndexAtEnd)
+ if (preload && !atTableEnd(Qt::BottomEdge))
loadEdge(Qt::BottomEdge, QQmlIncubator::AsynchronousIfNested);
if (!moveToNextRebuildState())
return;
@@ -2585,12 +2676,14 @@ void QQuickTableViewPrivate::layoutAfterLoadingInitialTable()
relayoutTableItems();
syncLoadedTableRectFromLoadedTable();
- if (rebuildOptions.testFlag(RebuildOption::CalculateNewContentWidth) || allColumnsLoaded()) {
+ const bool allColumnsLoaded = atTableEnd(Qt::LeftEdge) && atTableEnd(Qt::RightEdge);
+ if (rebuildOptions.testFlag(RebuildOption::CalculateNewContentWidth) || allColumnsLoaded) {
updateAverageColumnWidth();
updateContentWidth();
}
- if (rebuildOptions.testFlag(RebuildOption::CalculateNewContentHeight) || allRowsLoaded()) {
+ const bool allRowsLoaded = atTableEnd(Qt::TopEdge) && atTableEnd(Qt::BottomEdge);
+ if (rebuildOptions.testFlag(RebuildOption::CalculateNewContentHeight) || allRowsLoaded) {
updateAverageRowHeight();
updateContentHeight();
}
@@ -2670,6 +2763,32 @@ void QQuickTableViewPrivate::adjustViewportYAccordingToAlignment()
syncViewportRect();
}
+void QQuickTableViewPrivate::cancelOvershootAfterLayout()
+{
+ Q_Q(QQuickTableView);
+
+ // Note: we only want to cancel overshoot from a rebuild if we're supposed to position
+ // the view on a specific cell. The app is allowed to overshoot by setting contentX and
+ // contentY manually. Also, if this view is a sync child, we should always stay in sync
+ // with the syncView, so then we don't do anything.
+ const bool positionVertically = rebuildOptions.testFlag(RebuildOption::PositionViewAtRow);
+ const bool positionHorizontally = rebuildOptions.testFlag(RebuildOption::PositionViewAtColumn);
+ const bool cancelVertically = positionVertically && !syncVertically;
+ const bool cancelHorizontally = positionHorizontally && !syncHorizontally;
+
+ if (cancelHorizontally && !qFuzzyIsNull(q->horizontalOvershoot())) {
+ qCDebug(lcTableViewDelegateLifecycle()) << "cancelling overshoot horizontally:" << q->horizontalOvershoot();
+ setLocalViewportX(q->horizontalOvershoot() < 0 ? -q->minXExtent() : -q->maxXExtent());
+ syncViewportRect();
+ }
+
+ if (cancelVertically && !qFuzzyIsNull(q->verticalOvershoot())) {
+ qCDebug(lcTableViewDelegateLifecycle()) << "cancelling overshoot vertically:" << q->verticalOvershoot();
+ setLocalViewportY(q->verticalOvershoot() < 0 ? -q->minYExtent() : -q->maxYExtent());
+ syncViewportRect();
+ }
+}
+
void QQuickTableViewPrivate::unloadEdge(Qt::Edge edge)
{
Q_Q(QQuickTableView);
@@ -2728,7 +2847,7 @@ void QQuickTableViewPrivate::loadEdge(Qt::Edge edge, QQmlIncubator::IncubationMo
processLoadRequest();
}
-void QQuickTableViewPrivate::loadAndUnloadVisibleEdges()
+void QQuickTableViewPrivate::loadAndUnloadVisibleEdges(QQmlIncubator::IncubationMode incubationMode)
{
// Unload table edges that have been moved outside the visible part of the
// table (including buffer area), and load new edges that has been moved inside.
@@ -2765,7 +2884,7 @@ void QQuickTableViewPrivate::loadAndUnloadVisibleEdges()
if (Qt::Edge edge = nextEdgeToLoad(viewportRect)) {
tableModified = true;
- loadEdge(edge, QQmlIncubator::AsynchronousIfNested);
+ loadEdge(edge, incubationMode);
if (loadRequest.isActive())
return;
}
@@ -2970,11 +3089,10 @@ bool QQuickTableViewPrivate::selectedInSelectionModel(const QPoint &cell) const
if (!model)
return false;
- const QModelIndex modelIndex = model->index(cell.y(), cell.x());
- return selectionModel->isSelected(modelIndex);
+ return selectionModel->isSelected(q_func()->modelIndex(cell));
}
-void QQuickTableViewPrivate::selectionChangedInSelectionModel(const QItemSelection &selected, const QItemSelection &deselected) const
+void QQuickTableViewPrivate::selectionChangedInSelectionModel(const QItemSelection &selected, const QItemSelection &deselected)
{
const auto &selectedIndexes = selected.indexes();
const auto &deselectedIndexes = deselected.indexes();
@@ -2984,40 +3102,25 @@ void QQuickTableViewPrivate::selectionChangedInSelectionModel(const QItemSelecti
setSelectedOnDelegateItem(deselectedIndexes.at(i), false);
}
-void QQuickTableViewPrivate::updateSelectedOnAllDelegateItems() const
-{
- for (auto it = loadedItems.keyBegin(), end = loadedItems.keyEnd(); it != end; ++it) {
- const QPoint cell = cellAtModelIndex(*it);
- const bool selected = selectedInSelectionModel(cell);
- setSelectedOnDelegateItem(loadedTableItem(cell)->item, selected);
- }
-}
-
-void QQuickTableViewPrivate::setSelectedOnDelegateItem(const QModelIndex &modelIndex, bool select) const
+void QQuickTableViewPrivate::setSelectedOnDelegateItem(const QModelIndex &modelIndex, bool select)
{
const int cellIndex = modelIndexToCellIndex(modelIndex);
if (!loadedItems.contains(cellIndex))
return;
const QPoint cell = cellAtModelIndex(cellIndex);
- setSelectedOnDelegateItem(loadedTableItem(cell)->item, select);
+ QQuickItem *item = loadedTableItem(cell)->item;
+ setRequiredProperty(kRequiredProperty_selected, QVariant::fromValue(select), cellIndex, item, false);
}
-void QQuickTableViewPrivate::setSelectedOnDelegateItem(QQuickItem *delegateItem, bool select) const
+void QQuickTableViewPrivate::updateSelectedOnAllDelegateItems()
{
- if (!delegateItem->property(kRequiredProperty).toBool()) {
- // We only assign to "selected" if it's a required property. Otherwise
- // we assume (for backwards compatibility) that the property is used
- // by the delegate for something else.
- // Note: kRequiredProperty is a work-around until QMetaProperty::isRequired() works.
- return;
+ for (auto it = loadedItems.keyBegin(), end = loadedItems.keyEnd(); it != end; ++it) {
+ const int cellIndex = *it;
+ const QPoint cell = cellAtModelIndex(cellIndex);
+ const bool selected = selectedInSelectionModel(cell);
+ QQuickItem *item = loadedTableItem(cell)->item;
+ setRequiredProperty(kRequiredProperty_selected, QVariant::fromValue(selected), cellIndex, item, false);
}
-
- // Note that several delegates might be in use (in case of a DelegateChooser), and
- // the delegate can also change. So we cannot cache the propertyIndex.
- const auto metaObject = delegateItem->metaObject();
- const int propertyIndex = metaObject->indexOfProperty("selected");
- const auto metaProperty = metaObject->property(propertyIndex);
- metaProperty.write(delegateItem, QVariant::fromValue(select));
}
void QQuickTableViewPrivate::itemCreatedCallback(int modelIndex, QObject*)
@@ -3048,14 +3151,7 @@ void QQuickTableViewPrivate::initItemCallback(int modelIndex, QObject *object)
const QPoint cell = cellAtModelIndex(modelIndex);
const bool selected = selectedInSelectionModel(cell);
-
- if (qobject_cast<QQmlTableInstanceModel *>(model)) {
- const bool wasRequired = model->setRequiredProperty(modelIndex, QStringLiteral("selected"), selected);
- if (wasRequired) {
- // Work-around until QMetaProperty::isRequired() works
- item->setProperty(kRequiredProperty, true);
- }
- }
+ setRequiredProperty(kRequiredProperty_selected, QVariant::fromValue(selected), modelIndex, object, true);
if (auto attached = getAttachedObject(object))
attached->setView(q);
@@ -3071,10 +3167,9 @@ void QQuickTableViewPrivate::itemPooledCallback(int modelIndex, QObject *object)
void QQuickTableViewPrivate::itemReusedCallback(int modelIndex, QObject *object)
{
- auto item = static_cast<QQuickItem*>(object);
const QPoint cell = cellAtModelIndex(modelIndex);
const bool selected = selectedInSelectionModel(cell);
- setSelectedOnDelegateItem(item, selected);
+ setRequiredProperty(kRequiredProperty_selected, QVariant::fromValue(selected), modelIndex, object, false);
if (auto attached = getAttachedObject(object))
emit attached->reused();
@@ -3886,27 +3981,29 @@ QPoint QQuickTableView::cellAtPos(const QPointF &position, bool includeSpacing)
{
Q_D(const QQuickTableView);
- if (!boundingRect().contains(position))
+ const QPointF localPos = mapToItem(d->contentItem, position);
+ if (!d->loadedTableOuterRect.contains(localPos))
return QPoint(-1, -1);
const qreal hSpace = d->cellSpacing.width();
const qreal vSpace = d->cellSpacing.height();
- qreal currentColumnEnd = d->loadedTableOuterRect.x() - contentX();
- qreal currentRowEnd = d->loadedTableOuterRect.y() - contentY();
+ qreal currentColumnEnd = d->loadedTableOuterRect.x();
+ qreal currentRowEnd = d->loadedTableOuterRect.y();
+
int foundColumn = -1;
int foundRow = -1;
for (const int column : d->loadedColumns) {
currentColumnEnd += d->getEffectiveColumnWidth(column);
- if (position.x() < currentColumnEnd) {
+ if (localPos.x() < currentColumnEnd) {
foundColumn = column;
break;
}
currentColumnEnd += hSpace;
- if (!includeSpacing && position.x() < currentColumnEnd) {
+ if (!includeSpacing && localPos.x() < currentColumnEnd) {
// Hit spacing
return QPoint(-1, -1);
- } else if (includeSpacing && position.x() < currentColumnEnd - (hSpace / 2)) {
+ } else if (includeSpacing && localPos.x() < currentColumnEnd - (hSpace / 2)) {
foundColumn = column;
break;
}
@@ -3914,16 +4011,16 @@ QPoint QQuickTableView::cellAtPos(const QPointF &position, bool includeSpacing)
for (const int row : d->loadedRows) {
currentRowEnd += d->getEffectiveRowHeight(row);
- if (position.y() < currentRowEnd) {
+ if (localPos.y() < currentRowEnd) {
foundRow = row;
break;
}
currentRowEnd += vSpace;
- if (!includeSpacing && position.y() < currentRowEnd) {
+ if (!includeSpacing && localPos.y() < currentRowEnd) {
// Hit spacing
return QPoint(-1, -1);
}
- if (includeSpacing && position.y() < currentRowEnd - (vSpace / 2)) {
+ if (includeSpacing && localPos.y() < currentRowEnd - (vSpace / 2)) {
foundRow = row;
break;
}
@@ -4000,6 +4097,41 @@ qreal QQuickTableView::implicitRowHeight(int row) const
return d->sizeHintForRow(row);
}
+QModelIndex QQuickTableView::modelIndex(const QPoint &cell) const
+{
+ Q_D(const QQuickTableView);
+ if (cell.x() < 0 || cell.x() >= columns() || cell.y() < 0 || cell.y() >= rows())
+ return {};
+
+ auto const qaim = d->model->abstractItemModel();
+ if (!qaim)
+ return {};
+
+ return qaim->index(cell.y(), cell.x());
+}
+
+QPoint QQuickTableView::cellAtIndex(const QModelIndex &index) const
+{
+ if (!index.isValid() || index.parent().isValid())
+ return {-1, -1};
+ return {index.column(), index.row()};
+}
+
+QModelIndex QQuickTableView::modelIndex(int row, int column) const
+{
+ return modelIndex({column, row});
+}
+
+int QQuickTableView::rowAtIndex(const QModelIndex &index) const
+{
+ return cellAtIndex(index).y();
+}
+
+int QQuickTableView::columnAtIndex(const QModelIndex &index) const
+{
+ return cellAtIndex(index).x();
+}
+
void QQuickTableView::forceLayout()
{
d_func()->forceLayout();
@@ -4092,9 +4224,9 @@ void QQuickTableSectionSizeProvider::setSize(int section, qreal size)
}
// return -1.0 if no valid explicit size retrieved
-qreal QQuickTableSectionSizeProvider::size(int section)
+qreal QQuickTableSectionSizeProvider::size(int section) const
{
- Q_D(QQuickTableSectionSizeProvider);
+ Q_D(const QQuickTableSectionSizeProvider);
auto it = d->hash.find(section);
if (it != d->hash.end())
return *it;
diff --git a/src/quick/items/qquicktableview_p.h b/src/quick/items/qquicktableview_p.h
index 40a0fae7c1..830bef6c68 100644
--- a/src/quick/items/qquicktableview_p.h
+++ b/src/quick/items/qquicktableview_p.h
@@ -156,6 +156,12 @@ public:
Q_REVISION(6, 2) Q_INVOKABLE qreal implicitColumnWidth(int column) const;
Q_REVISION(6, 2) Q_INVOKABLE qreal implicitRowHeight(int row) const;
+ Q_REVISION(6, 4) Q_INVOKABLE virtual QModelIndex modelIndex(const QPoint &cell) const;
+ Q_REVISION(6, 4) Q_INVOKABLE virtual QPoint cellAtIndex(const QModelIndex &index) const;
+ Q_REVISION(6, 4) Q_INVOKABLE virtual QModelIndex modelIndex(int row, int column) const;
+ Q_REVISION(6, 4) Q_INVOKABLE int rowAtIndex(const QModelIndex &index) const;
+ Q_REVISION(6, 4) Q_INVOKABLE int columnAtIndex(const QModelIndex &index) const;
+
static QQuickTableViewAttached *qmlAttachedProperties(QObject *);
Q_SIGNALS:
diff --git a/src/quick/items/qquicktableview_p_p.h b/src/quick/items/qquicktableview_p_p.h
index bbab9f6a25..5bbdd07528 100644
--- a/src/quick/items/qquicktableview_p_p.h
+++ b/src/quick/items/qquicktableview_p_p.h
@@ -71,6 +71,8 @@ Q_DECLARE_LOGGING_CATEGORY(lcTableViewDelegateLifecycle)
static const qreal kDefaultRowHeight = 50;
static const qreal kDefaultColumnWidth = 50;
+static const int kEdgeIndexNotSet = -2;
+static const int kEdgeIndexAtEnd = -3;
class FxTableItem;
class QQuickTableSectionSizeProviderPrivate;
@@ -81,7 +83,7 @@ class Q_QUICK_PRIVATE_EXPORT QQuickTableSectionSizeProvider : public QObject {
public:
QQuickTableSectionSizeProvider(QObject *parent=nullptr);
void setSize(int section, qreal size);
- qreal size(int section);
+ qreal size(int section) const;
bool resetSize(int section);
void resetAll();
@@ -202,6 +204,7 @@ public:
VerifyTable,
LayoutTable,
LoadAndUnloadAfterLayout,
+ CancelOvershoot,
PreloadColumns,
PreloadRows,
MovePreloadedItemsToPool,
@@ -276,7 +279,7 @@ public:
QQmlTableInstanceModel::ReusableFlag reusableFlag = QQmlTableInstanceModel::Reusable;
bool blockItemCreatedCallback = false;
- bool layoutWarningIssued = false;
+ mutable bool layoutWarningIssued = false;
bool polishing = false;
bool syncVertically = false;
bool syncHorizontally = false;
@@ -295,9 +298,9 @@ public:
QQuickTableSectionSizeProvider rowHeights;
QQuickTableSectionSizeProvider columnWidths;
- EdgeRange cachedNextVisibleEdgeIndex[4];
- EdgeRange cachedColumnWidth;
- EdgeRange cachedRowHeight;
+ mutable EdgeRange cachedNextVisibleEdgeIndex[4];
+ mutable EdgeRange cachedColumnWidth;
+ mutable EdgeRange cachedRowHeight;
// TableView uses contentWidth/height to report the size of the table (this
// will e.g make scrollbars written for Flickable work out of the box). This
@@ -358,14 +361,16 @@ public:
QSize calculateTableSize();
void updateTableSize();
- inline bool isColumnHidden(int column);
- inline bool isRowHidden(int row);
+ inline bool isColumnHidden(int column) const;
+ inline bool isRowHidden(int row) const;
qreal getColumnLayoutWidth(int column);
qreal getRowLayoutHeight(int row);
- qreal getColumnWidth(int column);
- qreal getRowHeight(int row);
+ qreal getColumnWidth(int column) const;
+ qreal getRowHeight(int row) const;
+ qreal getEffectiveRowY(int row) const;
qreal getEffectiveRowHeight(int row) const;
+ qreal getEffectiveColumnX(int column) const;
qreal getEffectiveColumnWidth(int column) const;
int topRow() const { return *loadedRows.cbegin(); }
@@ -396,11 +401,11 @@ public:
void syncLoadedTableFromLoadRequest();
void shiftLoadedTableRect(const QPointF newPosition);
- int nextVisibleEdgeIndex(Qt::Edge edge, int startIndex);
- int nextVisibleEdgeIndexAroundLoadedTable(Qt::Edge edge);
- bool allColumnsLoaded();
- bool allRowsLoaded();
- inline int edgeToArrayIndex(Qt::Edge edge);
+ int nextVisibleEdgeIndex(Qt::Edge edge, int startIndex) const;
+ int nextVisibleEdgeIndexAroundLoadedTable(Qt::Edge edge) const;
+ inline bool atTableEnd(Qt::Edge edge) const { return nextVisibleEdgeIndexAroundLoadedTable(edge) == kEdgeIndexAtEnd; }
+ inline bool atTableEnd(Qt::Edge edge, int startIndex) const { return nextVisibleEdgeIndex(edge, startIndex) == kEdgeIndexAtEnd; }
+ inline int edgeToArrayIndex(Qt::Edge edge) const;
void clearEdgeSizeCache();
bool canLoadTableEdge(Qt::Edge tableEdge, const QRectF fillRect) const;
@@ -421,7 +426,7 @@ public:
void unloadItem(const QPoint &cell);
void loadEdge(Qt::Edge edge, QQmlIncubator::IncubationMode incubationMode);
void unloadEdge(Qt::Edge edge);
- void loadAndUnloadVisibleEdges();
+ void loadAndUnloadVisibleEdges(QQmlIncubator::IncubationMode incubationMode = QQmlIncubator::AsynchronousIfNested);
void drainReusePoolAfterLoadRequest();
void processLoadRequest();
@@ -433,6 +438,7 @@ public:
void layoutAfterLoadingInitialTable();
void adjustViewportXAccordingToAlignment();
void adjustViewportYAccordingToAlignment();
+ void cancelOvershootAfterLayout();
void scheduleRebuildTable(QQuickTableViewPrivate::RebuildOptions options);
@@ -473,10 +479,9 @@ public:
void syncViewportPosRecursive();
bool selectedInSelectionModel(const QPoint &cell) const;
- void selectionChangedInSelectionModel(const QItemSelection &selected, const QItemSelection &deselected) const;
- void updateSelectedOnAllDelegateItems() const;
- void setSelectedOnDelegateItem(const QModelIndex &modelIndex, bool select) const;
- void setSelectedOnDelegateItem(QQuickItem *delegateItem, bool select) const;
+ void selectionChangedInSelectionModel(const QItemSelection &selected, const QItemSelection &deselected);
+ void updateSelectedOnAllDelegateItems();
+ void setSelectedOnDelegateItem(const QModelIndex &modelIndex, bool select);
void fetchMoreData();
@@ -486,6 +491,11 @@ public:
inline QString tableLayoutToString() const;
void dumpTable() const;
+ void setRequiredProperty(const char *property,
+ const QVariant &value,
+ int serializedModelIndex,
+ QObject *object, bool init);
+
// QQuickSelectable
QQuickItem *selectionPointerHandlerTarget() const override;
void setSelectionStartPos(const QPointF &pos) override;
diff --git a/src/quick/items/qquicktext.cpp b/src/quick/items/qquicktext.cpp
index f5dca6e0f5..66baa7ed7c 100644
--- a/src/quick/items/qquicktext.cpp
+++ b/src/quick/items/qquicktext.cpp
@@ -772,11 +772,15 @@ QRectF QQuickTextPrivate::setupTextLayout(qreal *const baseline)
const bool pixelSize = font.pixelSize() != -1;
QString layoutText = layout.text();
- int largeFont = pixelSize ? font.pixelSize() : font.pointSize();
- int smallFont = fontSizeMode() != QQuickText::FixedSize
- ? qMin(pixelSize ? minimumPixelSize() : minimumPointSize(), largeFont)
- : largeFont;
- int scaledFontSize = largeFont;
+ const qreal minimumSize = pixelSize
+ ? static_cast<qreal>(minimumPixelSize())
+ : minimumPointSize();
+ qreal largeFont = pixelSize ? font.pixelSize() : font.pointSizeF();
+ qreal smallFont = fontSizeMode() != QQuickText::FixedSize
+ ? qMin<qreal>(minimumSize, largeFont)
+ : largeFont;
+ qreal scaledFontSize = largeFont;
+ const qreal sizeFittingThreshold(0.01);
bool widthChanged = false;
widthExceeded = availableWidth() <= 0 && (singlelineElide || canWrap || horizontalFit);
@@ -805,7 +809,7 @@ QRectF QQuickTextPrivate::setupTextLayout(qreal *const baseline)
if (pixelSize)
scaledFont.setPixelSize(scaledFontSize);
else
- scaledFont.setPointSize(scaledFontSize);
+ scaledFont.setPointSizeF(scaledFontSize);
if (layout.font() != scaledFont)
layout.setFont(scaledFont);
}
@@ -1069,40 +1073,45 @@ QRectF QQuickTextPrivate::setupTextLayout(qreal *const baseline)
if (!horizontalFit && !verticalFit)
break;
+ // Can't find a better fit
+ if (qFuzzyCompare(smallFont, largeFont))
+ break;
+
// Try and find a font size that better fits the dimensions of the element.
if (horizontalFit) {
if (unelidedRect.width() > lineWidth || (!verticalFit && wrapped)) {
widthExceeded = true;
- largeFont = scaledFontSize - 1;
- if (smallFont > largeFont)
- break;
+ largeFont = scaledFontSize;
+
scaledFontSize = (smallFont + largeFont) / 2;
- if (pixelSize)
- scaledFont.setPixelSize(scaledFontSize);
- else
- scaledFont.setPointSize(scaledFontSize);
+
continue;
} else if (!verticalFit) {
smallFont = scaledFontSize;
- if (smallFont == largeFont)
+
+ // Check to see if the current scaledFontSize is acceptable
+ if ((largeFont - smallFont) < sizeFittingThreshold)
break;
- scaledFontSize = (smallFont + largeFont + 1) / 2;
+
+ scaledFontSize = (smallFont + largeFont) / 2;
}
}
if (verticalFit) {
if (truncateHeight || unelidedRect.height() > maxHeight) {
heightExceeded = true;
- largeFont = scaledFontSize - 1;
- if (smallFont > largeFont)
- break;
+ largeFont = scaledFontSize;
+
scaledFontSize = (smallFont + largeFont) / 2;
} else {
smallFont = scaledFontSize;
- if (smallFont == largeFont)
+
+ // Check to see if the current scaledFontSize is acceptable
+ if ((largeFont - smallFont) < sizeFittingThreshold)
break;
- scaledFontSize = (smallFont + largeFont + 1) / 2;
+
+ scaledFontSize = (smallFont + largeFont) / 2;
}
}
}
diff --git a/src/quick/items/qquicktreeview.cpp b/src/quick/items/qquicktreeview.cpp
index 271df508de..e6cf4a8305 100644
--- a/src/quick/items/qquicktreeview.cpp
+++ b/src/quick/items/qquicktreeview.cpp
@@ -149,126 +149,129 @@
\note this function will not affect the model, only
the visual representation in the view.
- \sa collapse(), isExpanded()
+ \sa collapse(), isExpanded(), expandRecursively()
*/
/*!
- \qmlmethod QtQuick::TreeView::collapse(row)
+ \qmlmethod QtQuick::TreeView::expandRecursively(row = -1, depth = -1)
+ \since 6.4
- Collapses the tree node at the given \a row in the view.
+ Expands the tree node at the given \a row in the view recursively down to
+ \a depth. \a depth should be relative to the depth of \a row. If
+ \a depth is \c -1, the tree will be expanded all the way down to all leaves.
+
+ For a model that has more than one root, you can also call this function
+ with \a row equal to \c -1. This will expand all roots. Hence, calling
+ expandRecursively(-1, -1), or simply expandRecursively(), will expand
+ all nodes in the model.
\a row should be the row in the view (table row), and not a row in the model.
- \note this function will not affect the model, only
- the visual representation in the view.
+ \note This function will not try to \l{QAbstractItemModel::fetchMore}{fetch more} data.
+ \note This function will not affect the model, only the visual representation in the view.
+ \warning If the model contains a large number of items, this function will
+ take some time to execute.
- \sa expand(), isExpanded()
+ \sa collapseRecursively(), expand(), collapse(), isExpanded(), depth()
*/
/*!
- \qmlmethod QtQuick::TreeView::toggleExpanded(row)
+ \qmlmethod QtQuick::TreeView::expandToIndex(QModelIndex index)
+ \since 6.4
- Toggles if the tree node at the given \a row should be expanded.
- This is a convenience for doing:
+ Expands the tree from the given model \a index, and recursively all the way up
+ to the root. The result will be that the delegate item that represents \a index
+ becomes visible in the view (unless it ends up outside the viewport). To
+ ensure that the row ends up visible in the viewport, you can do:
\code
- if (isExpanded(row))
- collapse(row)
- else
- expand(row)
+ expandToIndex(index)
+ forceLayout()
+ positionViewAtRow(rowAtIndex(index), Qt.AlignVCenter)
\endcode
- \a row should be the row in the view (table row), and not a row in the model.
+ \sa expand(), expandRecursively()
*/
/*!
- \qmlmethod QModelIndex QtQuick::TreeView::modelIndex(row, column)
-
- Returns the \l QModelIndex that maps to \a row and \a column in the view.
-
- \a row and \a column should be the row and column in the view (table row and
- table column), and not a row and column in the model.
-
- The assigned model, which is a tree model, is converted to a flat table
- model internally so that it can be shown in a TableView (which TreeView
- inherits). This function can be used whenever you need to know which
- index in the tree model maps to the given row and column in the view.
+ \qmlmethod QtQuick::TreeView::collapse(row)
- \sa rowAtIndex(), columnAtIndex()
-*/
+ Collapses the tree node at the given \a row in the view.
-/*!
- \qmlmethod QModelIndex QtQuick::TreeView::modelIndex(point cell)
+ \a row should be the row in the view (table row), and not a row in the model.
- Convenience function for doing:
- \code
- modelIndex(cell.y, cell.x)
- \endcode
+ \note this function will not affect the model, only
+ the visual representation in the view.
- A cell is simply a \l point that combines row and column into
- a single type. Note that \c point.x will map to the column, and
- \c point.y will map to the row.
+ \sa expand(), isExpanded()
*/
/*!
- \qmlmethod int QtQuick::TreeView::rowAtIndex(modelIndex)
-
- Returns the row in the view that maps to \a modelIndex in the model.
+ \qmlmethod QtQuick::TreeView::collapseRecursively(row = -1)
+ \since 6.4
- The assigned model, which is a tree model, is converted to a flat table
- model internally so that it can be shown in a TableView (which TreeView
- inherits). This function can be used whenever you need to know which
- row in the view the given model index maps to.
+ Collapses the tree node at the given \a row in the view recursively down to
+ all leaves.
- \note \a modelIndex must be a \l QModelIndex.
+ For a model has more than one root, you can also call this function
+ with \a row equal to \c -1. This will collapse all roots. Hence, calling
+ collapseRecursively(-1), or simply collapseRecursively(), will collapse
+ all nodes in the model.
- \sa columnAtIndex(), modelIndex()
-*/
-
-/*!
- \qmlmethod int QtQuick::TreeView::columnAtIndex(modelIndex)
-
- Returns the column in the view that maps to \a modelIndex in the model.
-
- The assigned model, which is a tree model, is converted to a flat table
- model internally so that it can be shown in a TableView (which TreeView
- inherits). This function can be used whenever you need to know which
- column in the view the given model index maps to.
+ \a row should be the row in the view (table row), and not a row in the model.
- \note \a modelIndex must be a \l QModelIndex.
+ \note this function will not affect the model, only
+ the visual representation in the view.
- \sa rowAtIndex(), modelIndex()
+ \sa expandRecursively(), expand(), collapse(), isExpanded(), depth()
*/
/*!
- \qmlmethod point QtQuick::TreeView::cellAtIndex(modelIndex)
+ \qmlmethod QtQuick::TreeView::toggleExpanded(row)
- Convenience function for doing:
+ Toggles if the tree node at the given \a row should be expanded.
+ This is a convenience for doing:
- \c {Qt.point(columnAtIndex(}\a {modelIndex}\c{), rowAtIndex(}\a {modelIndex}\c{))}
+ \code
+ if (isExpanded(row))
+ collapse(row)
+ else
+ expand(row)
+ \endcode
- A cell is simply a \l point that combines row and column into
- a single type. Note that \c point.x will map to the column, and
- \c point.y will map to the row.
+ \a row should be the row in the view (table row), and not a row in the model.
*/
/*!
- \qmlsignal QtQuick::TreeView::expanded(row)
+ \qmlsignal QtQuick::TreeView::expanded(row, depth)
This signal is emitted when a \a row is expanded in the view.
+ \a row and \a depth will be equal to the arguments given to the call
+ that caused the expansion to happen (\l expand() or \l expandRecursively()).
+ In case of \l expand(), \a depth will always be \c 1.
+ In case of \l expandToIndex(), \a depth will be the depth of the
+ target index.
+
+ \note when a row is expanded recursively, the expanded signal will
+ only be emitted for that one row, and not for its descendants.
\sa collapsed(), expand(), collapse(), toggleExpanded()
*/
/*!
- \qmlsignal QtQuick::TreeView::collapsed(row)
+ \qmlsignal QtQuick::TreeView::collapsed(row, recursively)
This signal is emitted when a \a row is collapsed in the view.
+ \a row will be equal to the argument given to the call that caused
+ the collapse to happen (\l collapse() or \l collapseRecursively()).
+ If the row was collapsed recursively, \a recursively will be \c true.
+
+ \note when a row is collapsed recursively, the collapsed signal will
+ only be emitted for that one row, and not for its descendants.
\sa expanded(), expand(), collapse(), toggleExpanded()
*/
-static const char* kRequiredProperties = "_qt_treeview_requiredpropertymask";
// Hard-code the tree column to be 0 for now
static const int kTreeColumn = 0;
@@ -343,32 +346,6 @@ void QQuickTreeViewPrivate::dataChangedCallback(
}
}
-void QQuickTreeViewPrivate::setRequiredProperty(const char *property,
- const QVariant &value, int serializedModelIndex, QObject *object, bool init)
-{
- // Attaching a property list to the delegate item is just a
- // work-around until QMetaProperty::isRequired() works!
- const QString propertyName = QString::fromUtf8(property);
-
- if (init) {
- const bool wasRequired = model->setRequiredProperty(serializedModelIndex, propertyName, value);
- if (wasRequired) {
- QStringList propertyList = object->property(kRequiredProperties).toStringList();
- object->setProperty(kRequiredProperties, propertyList << propertyName);
- }
- } else {
- const QStringList propertyList = object->property(kRequiredProperties).toStringList();
- if (!propertyList.contains(propertyName)) {
- // We only write to properties that are required
- return;
- }
- const auto metaObject = object->metaObject();
- const int propertyIndex = metaObject->indexOfProperty(property);
- const auto metaProperty = metaObject->property(propertyIndex);
- metaProperty.write(object, value);
- }
-}
-
void QQuickTreeViewPrivate::updateRequiredProperties(int serializedModelIndex, QObject *object, bool init)
{
Q_Q(QQuickTreeView);
@@ -420,22 +397,97 @@ bool QQuickTreeView::isExpanded(int row) const
void QQuickTreeView::expand(int row)
{
+ if (row >= 0)
+ expandRecursively(row, 1);
+}
+
+void QQuickTreeView::expandRecursively(int row, int depth)
+{
Q_D(QQuickTreeView);
- if (row < 0 || row >= d->m_treeModelToTableModel.rowCount())
+ if (row >= d->m_treeModelToTableModel.rowCount())
+ return;
+ if (row < 0 && row != -1)
+ return;
+ if (depth == 0 || depth < -1)
+ return;
+
+ auto expandRowRecursively = [=](int startRow) {
+ d->m_treeModelToTableModel.expandRecursively(startRow, depth);
+ // Update the expanded state of the startRow. The descendant rows that gets
+ // expanded will get the correct state set from initItem/itemReused instead.
+ for (int c = leftColumn(); c <= rightColumn(); ++c) {
+ const QPoint treeNodeCell(c, startRow);
+ if (const auto item = itemAtCell(treeNodeCell))
+ d->setRequiredProperty("expanded", true, d->modelIndexAtCell(treeNodeCell), item, false);
+ }
+ };
+
+ if (row >= 0) {
+ // Expand only one row recursively
+ const bool isExpanded = d->m_treeModelToTableModel.isExpanded(row);
+ if (isExpanded && depth == 1)
+ return;
+ expandRowRecursively(row);
+ } else {
+ // Expand all root nodes recursively
+ const auto model = d->m_treeModelToTableModel.model();
+ for (int r = 0; r < model->rowCount(); ++r) {
+ const int rootRow = d->m_treeModelToTableModel.itemIndex(model->index(r, 0));
+ if (rootRow != -1)
+ expandRowRecursively(rootRow);
+ }
+ }
+
+ emit expanded(row, depth);
+}
+
+void QQuickTreeView::expandToIndex(const QModelIndex &index)
+{
+ Q_D(QQuickTreeView);
+
+ if (!index.isValid()) {
+ qmlWarning(this) << "index is not valid: " << index;
return;
+ }
- if (d->m_treeModelToTableModel.isExpanded(row))
+ if (index.model() != d->m_treeModelToTableModel.model()) {
+ qmlWarning(this) << "index doesn't belong to correct model: " << index;
return;
+ }
- d->m_treeModelToTableModel.expandRow(row);
+ if (rowAtIndex(index) != -1) {
+ // index is already visible
+ return;
+ }
- for (int c = leftColumn(); c <= rightColumn(); ++c) {
- const QPoint treeNodeCell(c, row);
- if (const auto item = itemAtCell(treeNodeCell))
- d->setRequiredProperty("expanded", true, d->modelIndexAtCell(treeNodeCell), item, false);
+ int depth = 1;
+ QModelIndex parent = index.parent();
+ int row = rowAtIndex(parent);
+
+ while (parent.isValid()) {
+ if (row != -1) {
+ // The node is already visible, since it maps to a row in the table!
+ d->m_treeModelToTableModel.expandRow(row);
+
+ // Update the state of the already existing delegate item
+ for (int c = leftColumn(); c <= rightColumn(); ++c) {
+ const QPoint treeNodeCell(c, row);
+ if (const auto item = itemAtCell(treeNodeCell))
+ d->setRequiredProperty("expanded", true, d->modelIndexAtCell(treeNodeCell), item, false);
+ }
+
+ // When we hit a node that is visible, we know that all other nodes
+ // up to the parent have to be visible as well, so we can stop.
+ break;
+ } else {
+ d->m_treeModelToTableModel.expand(parent);
+ parent = parent.parent();
+ row = rowAtIndex(parent);
+ depth++;
+ }
}
- emit expanded(row);
+ emit expanded(row, depth);
}
void QQuickTreeView::collapse(int row)
@@ -455,7 +507,42 @@ void QQuickTreeView::collapse(int row)
d->setRequiredProperty("expanded", false, d->modelIndexAtCell(treeNodeCell), item, false);
}
- emit collapsed(row);
+ emit collapsed(row, false);
+}
+
+void QQuickTreeView::collapseRecursively(int row)
+{
+ Q_D(QQuickTreeView);
+ if (row >= d->m_treeModelToTableModel.rowCount())
+ return;
+ if (row < 0 && row != -1)
+ return;
+
+ auto collapseRowRecursive = [=](int startRow) {
+ // Always collapse descendants recursively,
+ // even if the top row itself is already collapsed.
+ d->m_treeModelToTableModel.collapseRecursively(startRow);
+ // Update the expanded state of the (still visible) startRow
+ for (int c = leftColumn(); c <= rightColumn(); ++c) {
+ const QPoint treeNodeCell(c, startRow);
+ if (const auto item = itemAtCell(treeNodeCell))
+ d->setRequiredProperty("expanded", false, d->modelIndexAtCell(treeNodeCell), item, false);
+ }
+ };
+
+ if (row >= 0) {
+ collapseRowRecursive(row);
+ } else {
+ // Collapse all root nodes recursively
+ const auto model = d->m_treeModelToTableModel.model();
+ for (int r = 0; r < model->rowCount(); ++r) {
+ const int rootRow = d->m_treeModelToTableModel.itemIndex(model->index(r, 0));
+ if (rootRow != -1)
+ collapseRowRecursive(rootRow);
+ }
+ }
+
+ emit collapsed(row, true);
}
void QQuickTreeView::toggleExpanded(int row)
@@ -466,32 +553,22 @@ void QQuickTreeView::toggleExpanded(int row)
expand(row);
}
-QModelIndex QQuickTreeView::modelIndex(int row, int column) const
+QModelIndex QQuickTreeView::modelIndex(const QPoint &cell) const
{
Q_D(const QQuickTreeView);
- const QModelIndex tableIndex = d->m_treeModelToTableModel.index(row, column);
+ const QModelIndex tableIndex = d->m_treeModelToTableModel.index(cell.y(), cell.x());
return d->m_treeModelToTableModel.mapToModel(tableIndex);
}
-QModelIndex QQuickTreeView::modelIndex(const QPoint &cell) const
-{
- return modelIndex(cell.y(), cell.x());
-}
-
-int QQuickTreeView::rowAtIndex(const QModelIndex &index) const
-{
- return d_func()->m_treeModelToTableModel.mapFromModel(index).row();
-}
-
-int QQuickTreeView::columnAtIndex(const QModelIndex &index) const
-{
- return d_func()->m_treeModelToTableModel.mapFromModel(index).column();
-}
-
QPoint QQuickTreeView::cellAtIndex(const QModelIndex &index) const
{
const QModelIndex tableIndex = d_func()->m_treeModelToTableModel.mapFromModel(index);
return QPoint(tableIndex.column(), tableIndex.row());
}
+QModelIndex QQuickTreeView::modelIndex(int row, int column) const
+{
+ return modelIndex({column, row});
+}
+
QT_END_NAMESPACE
diff --git a/src/quick/items/qquicktreeview_p.h b/src/quick/items/qquicktreeview_p.h
index c3e4b5a38f..870b29d329 100644
--- a/src/quick/items/qquicktreeview_p.h
+++ b/src/quick/items/qquicktreeview_p.h
@@ -75,15 +75,17 @@ public:
Q_INVOKABLE void collapse(int row);
Q_INVOKABLE void toggleExpanded(int row);
- Q_INVOKABLE QModelIndex modelIndex(int row, int column) const;
- Q_INVOKABLE QModelIndex modelIndex(const QPoint &cell) const;
- Q_INVOKABLE int rowAtIndex(const QModelIndex &index) const;
- Q_INVOKABLE int columnAtIndex(const QModelIndex &index) const;
- Q_INVOKABLE QPoint cellAtIndex(const QModelIndex &index) const;
+ Q_REVISION(6, 4) Q_INVOKABLE void expandRecursively(int row = -1, int depth = -1);
+ Q_REVISION(6, 4) Q_INVOKABLE void collapseRecursively(int row = -1);
+ Q_REVISION(6, 4) Q_INVOKABLE void expandToIndex(const QModelIndex &index);
+
+ Q_INVOKABLE QModelIndex modelIndex(const QPoint &cell) const override;
+ Q_INVOKABLE QPoint cellAtIndex(const QModelIndex &index) const override;
+ Q_INVOKABLE QModelIndex modelIndex(int row, int column) const override;
signals:
- void expanded(int row);
- void collapsed(int row);
+ void expanded(int row, int depth);
+ void collapsed(int row, bool recursively);
private:
Q_DISABLE_COPY(QQuickTreeView)
diff --git a/src/quick/items/qquicktreeview_p_p.h b/src/quick/items/qquicktreeview_p_p.h
index db974aefc9..47d87d2ac1 100644
--- a/src/quick/items/qquicktreeview_p_p.h
+++ b/src/quick/items/qquicktreeview_p_p.h
@@ -77,7 +77,6 @@ public:
const QModelIndex &bottomRight,
const QVector<int> &roles);
- void setRequiredProperty(const char *property, const QVariant &value, int serializedModelIndex, QObject *object, bool init);
void updateRequiredProperties(int serializedModelIndex, QObject *object, bool init);
public:
diff --git a/src/quick/items/qquickview_p.h b/src/quick/items/qquickview_p.h
index 1bc266bbbf..7018a84395 100644
--- a/src/quick/items/qquickview_p.h
+++ b/src/quick/items/qquickview_p.h
@@ -60,17 +60,12 @@
#include <QtCore/QWeakPointer>
#include <QtQml/qqmlengine.h>
-#include <private/qv4object_p.h>
#include "qquickwindow_p.h"
#include "qquickitemchangelistener_p.h"
QT_BEGIN_NAMESPACE
-namespace QV4 {
-struct ExecutionEngine;
-}
-
class QQmlContext;
class QQmlError;
class QQuickItem;
diff --git a/src/quick/items/qquickwindow.cpp b/src/quick/items/qquickwindow.cpp
index 156ecdaadb..f68848444e 100644
--- a/src/quick/items/qquickwindow.cpp
+++ b/src/quick/items/qquickwindow.cpp
@@ -428,10 +428,10 @@ static void updatePixelRatioHelper(QQuickItem *item, float pixelRatio)
void QQuickWindow::physicalDpiChanged()
{
Q_D(QQuickWindow);
- const qreal newPixelRatio = screen()->devicePixelRatio();
- if (qFuzzyCompare(newPixelRatio, d->devicePixelRatio))
+ const qreal newPixelRatio = effectiveDevicePixelRatio();
+ if (qFuzzyCompare(newPixelRatio, d->lastReportedItemDevicePixelRatio))
return;
- d->devicePixelRatio = newPixelRatio;
+ d->lastReportedItemDevicePixelRatio = newPixelRatio;
if (d->contentItem)
updatePixelRatioHelper(d->contentItem, newPixelRatio);
}
@@ -514,7 +514,6 @@ void QQuickWindowPrivate::ensureCustomRenderTarget()
redirect.renderTargetDirty = false;
redirect.rt.reset(rhi);
- redirect.devicePixelRatio = customRenderTarget.devicePixelRatio();
// a default constructed QQuickRenderTarget means no redirection
if (customRenderTarget.isNull())
@@ -535,11 +534,6 @@ void QQuickWindowPrivate::syncSceneGraph()
ensureCustomRenderTarget();
- // Calculate the dpr the same way renderSceneGraph() will.
- qreal devicePixelRatio = q->effectiveDevicePixelRatio();
- if (redirect.rt.renderTarget && !QQuickRenderControl::renderWindowFor(q))
- devicePixelRatio = redirect.devicePixelRatio;
-
QRhiCommandBuffer *cb = nullptr;
if (rhi) {
if (redirect.commandBuffer)
@@ -547,7 +541,7 @@ void QQuickWindowPrivate::syncSceneGraph()
else
cb = swapchain->currentFrameCommandBuffer();
}
- context->prepareSync(devicePixelRatio, cb, graphicsConfig);
+ context->prepareSync(q->effectiveDevicePixelRatio(), cb, graphicsConfig);
animationController->beforeNodeSync();
@@ -646,36 +640,21 @@ void QQuickWindowPrivate::renderSceneGraph(const QSize &size, const QSize &surfa
const bool flipY = rhi ? !rhi->isYUpInNDC() : false;
if (flipY)
matrixFlags |= QSGAbstractRenderer::MatrixTransformFlipY;
+
const qreal devicePixelRatio = q->effectiveDevicePixelRatio();
- if (redirect.rt.renderTarget) {
- const QSize pixelSize = redirect.rt.renderTarget->pixelSize();
- QRect rect(QPoint(0, 0), pixelSize);
- renderer->setDeviceRect(rect);
- renderer->setViewportRect(rect);
- if (QQuickRenderControl::renderWindowFor(q)) {
- renderer->setProjectionMatrixToRect(QRect(QPoint(0, 0), size), matrixFlags);
- renderer->setDevicePixelRatio(devicePixelRatio);
- } else {
- const QSizeF logicalSize = pixelSize / redirect.devicePixelRatio;
- renderer->setProjectionMatrixToRect(QRectF(QPointF(0, 0), logicalSize), matrixFlags);
- renderer->setDevicePixelRatio(redirect.devicePixelRatio);
- }
- } else {
- QSize pixelSize;
- QSizeF logicalSize;
- if (surfaceSize.isEmpty()) {
- pixelSize = size * devicePixelRatio;
- logicalSize = size;
- } else {
- pixelSize = surfaceSize;
- logicalSize = QSizeF(surfaceSize) / devicePixelRatio;
- }
- QRect rect(QPoint(0, 0), pixelSize);
- renderer->setDeviceRect(rect);
- renderer->setViewportRect(rect);
- renderer->setProjectionMatrixToRect(QRectF(QPoint(0, 0), logicalSize), matrixFlags);
- renderer->setDevicePixelRatio(devicePixelRatio);
- }
+ QSize pixelSize;
+ if (redirect.rt.renderTarget)
+ pixelSize = redirect.rt.renderTarget->pixelSize();
+ else if (surfaceSize.isEmpty())
+ pixelSize = size * devicePixelRatio;
+ else
+ pixelSize = surfaceSize;
+ QSizeF logicalSize = QSizeF(pixelSize) / devicePixelRatio;
+
+ renderer->setDevicePixelRatio(devicePixelRatio);
+ renderer->setDeviceRect(QRect(QPoint(0, 0), pixelSize));
+ renderer->setViewportRect(QRect(QPoint(0, 0), pixelSize));
+ renderer->setProjectionMatrixToRect(QRectF(QPointF(0, 0), logicalSize), matrixFlags);
if (rhi) {
context->renderNextRhiFrame(renderer);
@@ -705,7 +684,7 @@ void QQuickWindowPrivate::renderSceneGraph(const QSize &size, const QSize &surfa
QQuickWindowPrivate::QQuickWindowPrivate()
: contentItem(nullptr)
, dirtyItemList(nullptr)
- , devicePixelRatio(0)
+ , lastReportedItemDevicePixelRatio(0)
, context(nullptr)
, renderer(nullptr)
, windowManager(nullptr)
@@ -770,7 +749,7 @@ void QQuickWindowPrivate::init(QQuickWindow *c, QQuickRenderControl *control)
Q_ASSERT(windowManager || renderControl);
if (QScreen *screen = q->screen()) {
- devicePixelRatio = screen->devicePixelRatio();
+ lastReportedItemDevicePixelRatio = q->effectiveDevicePixelRatio();
// if the screen changes, then QQuickWindow::handleScreenChanged disconnects
// and connects to the new screen
physicalDpiChangedConnection = QObject::connect(screen, &QScreen::physicalDotsPerInchChanged,
@@ -1326,6 +1305,8 @@ QQuickItem *QQuickWindow::contentItem() const
\brief The item which currently has active focus or \c null if there is
no item with active focus.
+
+ \sa QQuickItem::forceActiveFocus(), {Keyboard Focus in Qt Quick}
*/
QQuickItem *QQuickWindow::activeFocusItem() const
{
@@ -3736,21 +3717,31 @@ void QQuickWindow::runJobsAfterSwap()
}
/*!
- * Returns the device pixel ratio for this window.
- *
- * This is different from QWindow::devicePixelRatio() in that it supports
- * redirected rendering via QQuickRenderControl. When using a
- * QQuickRenderControl, the QQuickWindow is often not created, meaning it is
- * never shown and there is no underlying native window created in the
- * windowing system. As a result, querying properties like the device pixel
- * ratio cannot give correct results. Use this function instead.
- *
- * \sa QWindow::devicePixelRatio()
+ Returns the device pixel ratio for this window.
+
+ This is different from QWindow::devicePixelRatio() in that it supports
+ redirected rendering via QQuickRenderControl and QQuickRenderTarget. When
+ using a QQuickRenderControl, the QQuickWindow is often not fully created,
+ meaning it is never shown and there is no underlying native window created
+ in the windowing system. As a result, querying properties like the device
+ pixel ratio cannot give correct results. This function takes into account
+ both QQuickRenderControl::renderWindowFor() and
+ QQuickRenderTarget::devicePixelRatio(). When no redirection is in effect,
+ the result is same as QWindow::devicePixelRatio().
+
+ \sa QQuickRenderControl, QQuickRenderTarget, setRenderTarget(), QWindow::devicePixelRatio()
*/
qreal QQuickWindow::effectiveDevicePixelRatio() const
{
+ Q_D(const QQuickWindow);
QWindow *w = QQuickRenderControl::renderWindowFor(const_cast<QQuickWindow *>(this));
- return w ? w->devicePixelRatio() : devicePixelRatio();
+ if (w)
+ return w->devicePixelRatio();
+
+ if (!d->customRenderTarget.isNull())
+ return d->customRenderTarget.devicePixelRatio();
+
+ return devicePixelRatio();
}
/*!
diff --git a/src/quick/items/qquickwindow_p.h b/src/quick/items/qquickwindow_p.h
index 0e69d63239..0fd09a1e33 100644
--- a/src/quick/items/qquickwindow_p.h
+++ b/src/quick/items/qquickwindow_p.h
@@ -193,7 +193,7 @@ public:
QVector<QQuickItem *> itemsToPolish;
- qreal devicePixelRatio;
+ qreal lastReportedItemDevicePixelRatio;
QMetaObject::Connection physicalDpiChangedConnection;
void updateDirtyNodes();
@@ -228,7 +228,6 @@ public:
struct Redirect {
QRhiCommandBuffer *commandBuffer = nullptr;
QQuickWindowRenderTarget rt;
- qreal devicePixelRatio = 1.0;
bool renderTargetDirty = false;
} redirect;
diff --git a/src/quick/scenegraph/coreapi/qsgbatchrenderer.cpp b/src/quick/scenegraph/coreapi/qsgbatchrenderer.cpp
index 95e6d35c1e..bda0085818 100644
--- a/src/quick/scenegraph/coreapi/qsgbatchrenderer.cpp
+++ b/src/quick/scenegraph/coreapi/qsgbatchrenderer.cpp
@@ -930,11 +930,10 @@ static void qsg_wipeBuffer(Buffer *buffer)
free(buffer->data);
}
-static void qsg_wipeBatch(Batch *batch, bool separateIndexBuffer)
+static void qsg_wipeBatch(Batch *batch)
{
qsg_wipeBuffer(&batch->vbo);
- if (separateIndexBuffer)
- qsg_wipeBuffer(&batch->ibo);
+ qsg_wipeBuffer(&batch->ibo);
delete batch->ubuf;
batch->stencilClipState.reset();
delete batch;
@@ -944,13 +943,12 @@ Renderer::~Renderer()
{
if (m_rhi) {
// Clean up batches and buffers
- const bool separateIndexBuffer = m_context->separateIndexBuffer();
for (int i = 0; i < m_opaqueBatches.size(); ++i)
- qsg_wipeBatch(m_opaqueBatches.at(i), separateIndexBuffer);
+ qsg_wipeBatch(m_opaqueBatches.at(i));
for (int i = 0; i < m_alphaBatches.size(); ++i)
- qsg_wipeBatch(m_alphaBatches.at(i), separateIndexBuffer);
+ qsg_wipeBatch(m_alphaBatches.at(i));
for (int i = 0; i < m_batchPool.size(); ++i)
- qsg_wipeBatch(m_batchPool.at(i), separateIndexBuffer);
+ qsg_wipeBatch(m_batchPool.at(i));
}
for (Node *n : qAsConst(m_nodes))
@@ -1008,8 +1006,7 @@ void Renderer::map(Buffer *buffer, int byteSize, bool isIndexBuf)
if (m_visualizer->mode() == Visualizer::VisualizeNothing) {
// Common case, use a shared memory pool for uploading vertex data to avoid
// excessive reevaluation
- QDataBuffer<char> &pool = m_context->separateIndexBuffer() && isIndexBuf
- ? m_indexUploadPool : m_vertexUploadPool;
+ QDataBuffer<char> &pool = isIndexBuf ? m_indexUploadPool : m_vertexUploadPool;
if (byteSize > pool.size())
pool.resize(byteSize);
buffer->data = pool.data();
@@ -2075,11 +2072,7 @@ void Renderer::uploadBatch(Batch *b)
ibufferSize = unmergedIndexSize;
}
- const bool separateIndexBuffer = m_context->separateIndexBuffer();
- if (separateIndexBuffer)
- map(&b->ibo, ibufferSize, true);
- else
- bufferSize += ibufferSize;
+ map(&b->ibo, ibufferSize, true);
map(&b->vbo, bufferSize);
if (Q_UNLIKELY(debug_upload())) qDebug() << " - batch" << b << " first:" << b->first << " root:"
@@ -2089,9 +2082,7 @@ void Renderer::uploadBatch(Batch *b)
if (b->merged) {
char *vertexData = b->vbo.data;
char *zData = vertexData + b->vertexCount * g->sizeOfVertex();
- char *indexData = separateIndexBuffer
- ? b->ibo.data
- : zData + (int(useDepthBuffer()) * b->vertexCount * sizeof(float));
+ char *indexData = b->ibo.data;
quint16 iOffset16 = 0;
quint32 iOffset32 = 0;
@@ -2103,8 +2094,8 @@ void Renderer::uploadBatch(Batch *b)
const uint verticesInSetLimit = m_uint32IndexForRhi ? 0xfffffffe : 0xfffe;
int indicesInSet = 0;
b->drawSets.reset();
- int drawSetIndices = separateIndexBuffer ? 0 : indexData - vertexData;
- const char *indexBase = separateIndexBuffer ? b->ibo.data : b->vbo.data;
+ int drawSetIndices = 0;
+ const char *indexBase = b->ibo.data;
b->drawSets << DrawSet(0, zData - vertexData, drawSetIndices);
while (e) {
verticesInSet += e->node->geometry()->vertexCount();
@@ -2138,8 +2129,7 @@ void Renderer::uploadBatch(Batch *b)
}
} else {
char *vboData = b->vbo.data;
- char *iboData = separateIndexBuffer ? b->ibo.data
- : vboData + b->vertexCount * g->sizeOfVertex();
+ char *iboData = b->ibo.data;
Element *e = b->first;
while (e) {
QSGGeometry *g = e->node->geometry();
@@ -2201,9 +2191,7 @@ void Renderer::uploadBatch(Batch *b)
if (!b->drawSets.isEmpty()) {
if (m_uint32IndexForRhi) {
- const quint32 *id = (const quint32 *)(separateIndexBuffer
- ? b->ibo.data
- : b->vbo.data + b->drawSets.at(0).indices);
+ const quint32 *id = (const quint32 *) b->ibo.data;
{
QDebug iDump = qDebug();
iDump << " -- Index Data, count:" << b->indexCount;
@@ -2214,9 +2202,7 @@ void Renderer::uploadBatch(Batch *b)
}
}
} else {
- const quint16 *id = (const quint16 *)(separateIndexBuffer
- ? b->ibo.data
- : b->vbo.data + b->drawSets.at(0).indices);
+ const quint16 *id = (const quint16 *) b->ibo.data;
{
QDebug iDump = qDebug();
iDump << " -- Index Data, count:" << b->indexCount;
@@ -2237,8 +2223,7 @@ void Renderer::uploadBatch(Batch *b)
#endif // QT_NO_DEBUG_OUTPUT
unmap(&b->vbo);
- if (separateIndexBuffer)
- unmap(&b->ibo, true);
+ unmap(&b->ibo, true);
if (Q_UNLIKELY(debug_upload())) qDebug() << " --- vertex/index buffers unmapped, batch upload completed...";
@@ -2669,6 +2654,7 @@ bool Renderer::ensurePipelineState(Element *e, const ShaderManager::Shader *sms,
ps->setFlags(flags);
ps->setTopology(qsg_topology(m_gstate.drawMode));
ps->setCullMode(m_gstate.cullMode);
+ ps->setPolygonMode(m_gstate.polygonMode);
QRhiGraphicsPipeline::TargetBlend blend;
blend.colorWrite = m_gstate.colorWrite;
@@ -2808,13 +2794,14 @@ static void rendererToMaterialGraphicsState(QSGMaterialShader::GraphicsPipelineS
Q_ASSERT(int(QSGMaterialShader::GraphicsPipelineState::OneMinusSrc1Alpha) == int(QRhiGraphicsPipeline::OneMinusSrc1Alpha));
Q_ASSERT(int(QSGMaterialShader::GraphicsPipelineState::A) == int(QRhiGraphicsPipeline::A));
Q_ASSERT(int(QSGMaterialShader::GraphicsPipelineState::CullBack) == int(QRhiGraphicsPipeline::Back));
-
+ Q_ASSERT(int(QSGMaterialShader::GraphicsPipelineState::Line) == int(QRhiGraphicsPipeline::Line));
dst->srcColor = QSGMaterialShader::GraphicsPipelineState::BlendFactor(src->srcColor);
dst->dstColor = QSGMaterialShader::GraphicsPipelineState::BlendFactor(src->dstColor);
dst->colorWrite = QSGMaterialShader::GraphicsPipelineState::ColorMask(int(src->colorWrite));
dst->cullMode = QSGMaterialShader::GraphicsPipelineState::CullMode(src->cullMode);
+ dst->polygonMode = QSGMaterialShader::GraphicsPipelineState::PolygonMode(src->polygonMode);
}
static void materialToRendererGraphicsState(GraphicsState *dst,
@@ -2825,6 +2812,7 @@ static void materialToRendererGraphicsState(GraphicsState *dst,
dst->dstColor = QRhiGraphicsPipeline::BlendFactor(src->dstColor);
dst->colorWrite = QRhiGraphicsPipeline::ColorMask(int(src->colorWrite));
dst->cullMode = QRhiGraphicsPipeline::CullMode(src->cullMode);
+ dst->polygonMode = QRhiGraphicsPipeline::PolygonMode(src->polygonMode);
}
void Renderer::updateMaterialDynamicData(ShaderManager::Shader *sms,
@@ -3695,7 +3683,7 @@ void Renderer::prepareRenderPass(RenderPassContext *ctx)
if (largestVBO * 2 < m_vertexUploadPool.size())
m_vertexUploadPool.resize(largestVBO * 2);
- if (m_context->separateIndexBuffer() && largestIBO * 2 < m_indexUploadPool.size())
+ if (largestIBO * 2 < m_indexUploadPool.size())
m_indexUploadPool.resize(largestIBO * 2);
if (Q_UNLIKELY(debug_render())) {
@@ -3727,6 +3715,7 @@ void Renderer::prepareRenderPass(RenderPassContext *ctx)
m_gstate.blending = false;
m_gstate.cullMode = QRhiGraphicsPipeline::None;
+ m_gstate.polygonMode = QRhiGraphicsPipeline::Fill;
m_gstate.colorWrite = QRhiGraphicsPipeline::R
| QRhiGraphicsPipeline::G
| QRhiGraphicsPipeline::B
@@ -4042,7 +4031,8 @@ bool operator==(const GraphicsState &a, const GraphicsState &b) noexcept
&& a.stencilTest == b.stencilTest
&& a.sampleCount == b.sampleCount
&& a.drawMode == b.drawMode
- && a.lineWidth == b.lineWidth;
+ && a.lineWidth == b.lineWidth
+ && a.polygonMode == b.polygonMode;
}
bool operator!=(const GraphicsState &a, const GraphicsState &b) noexcept
diff --git a/src/quick/scenegraph/coreapi/qsgbatchrenderer_p.h b/src/quick/scenegraph/coreapi/qsgbatchrenderer_p.h
index 241f5748b6..5cfc6c54c6 100644
--- a/src/quick/scenegraph/coreapi/qsgbatchrenderer_p.h
+++ b/src/quick/scenegraph/coreapi/qsgbatchrenderer_p.h
@@ -640,6 +640,7 @@ struct GraphicsState
int sampleCount = 1;
QSGGeometry::DrawingMode drawMode = QSGGeometry::DrawTriangles;
float lineWidth = 1.0f;
+ QRhiGraphicsPipeline::PolygonMode polygonMode = QRhiGraphicsPipeline::Fill;
};
bool operator==(const GraphicsState &a, const GraphicsState &b) noexcept;
diff --git a/src/quick/scenegraph/coreapi/qsgmaterialshader.cpp b/src/quick/scenegraph/coreapi/qsgmaterialshader.cpp
index bd17fd365a..3eb544f94d 100644
--- a/src/quick/scenegraph/coreapi/qsgmaterialshader.cpp
+++ b/src/quick/scenegraph/coreapi/qsgmaterialshader.cpp
@@ -684,6 +684,23 @@ bool QSGMaterialShader::updateGraphicsPipelineState(RenderState &state, Graphics
*/
/*!
+ \enum QSGMaterialShader::GraphicsPipelineState::PolygonMode
+ \since 6.4
+ \brief Specifies the polygon rasterization mode
+
+ Polygon Mode (Triangle Fill Mode in Metal, Fill Mode in D3D) specifies
+ the fill mode used when rasterizing polygons. Polygons may be drawn as
+ solids (Fill), or as a wire mesh (Line).
+
+ \warning OpenGL ES does not support the \c{Line} polygon mode. OpenGL ES
+ will rasterize all polygons as filled no matter what polygon mode is set.
+ Using \c{Line} will make your application non-portable.
+
+ \value Fill The interior of the polygon is filled (default)
+ \value Line Boundary edges of the polygon are drawn as line segments.
+ */
+
+/*!
Returns the accumulated opacity to be used for rendering.
*/
float QSGMaterialShader::RenderState::opacity() const
diff --git a/src/quick/scenegraph/coreapi/qsgmaterialshader.h b/src/quick/scenegraph/coreapi/qsgmaterialshader.h
index 566f954b06..a3c8afb875 100644
--- a/src/quick/scenegraph/coreapi/qsgmaterialshader.h
+++ b/src/quick/scenegraph/coreapi/qsgmaterialshader.h
@@ -130,12 +130,18 @@ public:
CullBack
};
+ enum PolygonMode {
+ Fill,
+ Line,
+ };
+
bool blendEnable;
BlendFactor srcColor;
BlendFactor dstColor;
ColorMask colorWrite;
QColor blendConstant;
CullMode cullMode;
+ PolygonMode polygonMode;
// This struct is extensible while keeping BC since apps only ever get
// a ptr to the struct, it is not created by them.
};
diff --git a/src/quick/scenegraph/coreapi/qsgnode.h b/src/quick/scenegraph/coreapi/qsgnode.h
index 19b8cf9354..49dc056c89 100644
--- a/src/quick/scenegraph/coreapi/qsgnode.h
+++ b/src/quick/scenegraph/coreapi/qsgnode.h
@@ -40,6 +40,7 @@
#ifndef QSGNODE_H
#define QSGNODE_H
+#include <QtCore/qlist.h>
#include <QtQuick/qsggeometry.h>
#include <QtGui/QMatrix4x4>
diff --git a/src/quick/scenegraph/qsgadaptationlayer_p.h b/src/quick/scenegraph/qsgadaptationlayer_p.h
index aa9f78f2c5..7d71c5248c 100644
--- a/src/quick/scenegraph/qsgadaptationlayer_p.h
+++ b/src/quick/scenegraph/qsgadaptationlayer_p.h
@@ -53,6 +53,7 @@
#include <QtQuick/qsgnode.h>
#include <QtQuick/qsgtexture.h>
+#include <QtQuick/qquickpainteditem.h>
#include <QtCore/qobject.h>
#include <QtCore/qrect.h>
#include <QtGui/qbrush.h>
diff --git a/src/quick/scenegraph/qsgdefaultrendercontext.cpp b/src/quick/scenegraph/qsgdefaultrendercontext.cpp
index 8579cb5e2a..a4337a58ca 100644
--- a/src/quick/scenegraph/qsgdefaultrendercontext.cpp
+++ b/src/quick/scenegraph/qsgdefaultrendercontext.cpp
@@ -62,7 +62,6 @@ QSGDefaultRenderContext::QSGDefaultRenderContext(QSGContext *context)
, m_rhiAtlasManager(nullptr)
, m_currentFrameCommandBuffer(nullptr)
, m_currentFrameRenderPass(nullptr)
- , m_separateIndexBuffer(false)
, m_useDepthBufferFor2D(true)
, m_glyphCacheResourceUpdates(nullptr)
{
@@ -87,8 +86,6 @@ void QSGDefaultRenderContext::initialize(const QSGRenderContext::InitParams *par
m_maxTextureSize = m_rhi->resourceLimit(QRhi::TextureSizeMax);
if (!m_rhiAtlasManager)
m_rhiAtlasManager = new QSGRhiAtlasTexture::Manager(this, m_initParams.initialSurfacePixelSize, m_initParams.maybeSurface);
- // unlike OpenGL (and like WebGL), QRhi does not guarantee buffer usage types can be mixed
- m_separateIndexBuffer = true;
m_glyphCacheResourceUpdates = nullptr;
diff --git a/src/quick/scenegraph/qsgdefaultrendercontext_p.h b/src/quick/scenegraph/qsgdefaultrendercontext_p.h
index e96bf045b5..a97347eaf0 100644
--- a/src/quick/scenegraph/qsgdefaultrendercontext_p.h
+++ b/src/quick/scenegraph/qsgdefaultrendercontext_p.h
@@ -120,7 +120,6 @@ public:
virtual void initializeRhiShader(QSGMaterialShader *shader, QShader::Variant shaderVariant);
int maxTextureSize() const override { return m_maxTextureSize; }
- bool separateIndexBuffer() const { return m_separateIndexBuffer; }
bool useDepthBufferFor2D() const { return m_useDepthBufferFor2D; }
int msaaSampleCount() const { return m_initParams.sampleCount; }
@@ -159,7 +158,6 @@ protected:
QRhiCommandBuffer *m_currentFrameCommandBuffer;
QRhiRenderPassDescriptor *m_currentFrameRenderPass;
qreal m_currentDevicePixelRatio;
- bool m_separateIndexBuffer;
bool m_useDepthBufferFor2D;
QRhiResourceUpdateBatch *m_glyphCacheResourceUpdates;
};
diff --git a/src/quick/scenegraph/qsgrenderloop.cpp b/src/quick/scenegraph/qsgrenderloop.cpp
index 98823794c4..b96f75ddbd 100644
--- a/src/quick/scenegraph/qsgrenderloop.cpp
+++ b/src/quick/scenegraph/qsgrenderloop.cpp
@@ -105,10 +105,6 @@ void QSGRenderLoop::cleanup()
}
delete s_instance;
s_instance = nullptr;
-
-#ifdef ENABLE_DEFAULT_BACKEND
- QSGRhiSupport::cleanupDefaultVulkanInstance();
-#endif
}
QSurface::SurfaceType QSGRenderLoop::windowSurfaceType() const
diff --git a/src/quick/scenegraph/qsgrhisupport.cpp b/src/quick/scenegraph/qsgrhisupport.cpp
index 7a2aeab7a6..da83e82b4b 100644
--- a/src/quick/scenegraph/qsgrhisupport.cpp
+++ b/src/quick/scenegraph/qsgrhisupport.cpp
@@ -39,14 +39,15 @@
#include "qsgrhisupport_p.h"
#include "qsgcontext_p.h"
-# include "qsgdefaultrendercontext_p.h"
+#include "qsgdefaultrendercontext_p.h"
#include <QtQuick/private/qquickitem_p.h>
#include <QtQuick/private/qquickwindow_p.h>
#include <QtGui/qwindow.h>
+
#if QT_CONFIG(vulkan)
-#include <QtGui/qvulkaninstance.h>
+#include <QtGui/private/qvulkandefaultinstance_p.h>
#endif
#include <QOperatingSystemVersion>
@@ -54,69 +55,6 @@
QT_BEGIN_NAMESPACE
-#if QT_CONFIG(vulkan)
-QVulkanInstance *s_vulkanInstance = nullptr;
-#endif
-
-QVulkanInstance *QSGRhiSupport::defaultVulkanInstance()
-{
-#if QT_CONFIG(vulkan)
- QSGRhiSupport *inst = QSGRhiSupport::instance();
- if (!inst->isRhiEnabled() || inst->rhiBackend() != QRhi::Vulkan)
- return nullptr;
-
- if (!s_vulkanInstance) {
- s_vulkanInstance = new QVulkanInstance;
-
- // With a Vulkan implementation >= 1.1 we can check what
- // vkEnumerateInstanceVersion() says and request 1.2 or 1.1 based on the
- // result. To prevent future surprises, be conservative and ignore any > 1.2
- // versions for now. For 1.0 implementations nothing will be requested, the
- // default 0 in VkApplicationInfo means 1.0.
- //
- // Vulkan 1.0 is actually sufficient for 99% of Qt Quick (3D)'s
- // functionality. In addition, Vulkan implementations tend to enable 1.1 and 1.2
- // functionality regardless of the VkInstance API request. However, the
- // validation layer seems to take this fairly seriously, so we should be
- // prepared for using 1.1 and 1.2 features in a fully correct manner. This also
- // helps custom Vulkan code in applications, which is not under out control; it
- // is ideal if Vulkan 1.1 and 1.2 are usable without requiring such applications
- // to create their own QVulkanInstance just to be able to make an appropriate
- // setApiVersion() call on it.
-
- const QVersionNumber supportedVersion = s_vulkanInstance->supportedApiVersion();
- if (supportedVersion >= QVersionNumber(1, 2))
- s_vulkanInstance->setApiVersion(QVersionNumber(1, 2));
- else if (supportedVersion >= QVersionNumber(1, 1))
- s_vulkanInstance->setApiVersion(QVersionNumber(1, 2));
- qCDebug(QSG_LOG_INFO) << "Requesting Vulkan API" << s_vulkanInstance->apiVersion()
- << "Instance-level version was reported as" << supportedVersion;
-
- if (inst->isDebugLayerRequested())
- s_vulkanInstance->setLayers({ "VK_LAYER_KHRONOS_validation" });
-
- s_vulkanInstance->setExtensions(QRhiVulkanInitParams::preferredInstanceExtensions());
-
- if (!s_vulkanInstance->create()) {
- qWarning("Failed to create Vulkan instance");
- delete s_vulkanInstance;
- s_vulkanInstance = nullptr;
- }
- }
- return s_vulkanInstance;
-#else
- return nullptr;
-#endif
-}
-
-void QSGRhiSupport::cleanupDefaultVulkanInstance()
-{
-#if QT_CONFIG(vulkan)
- delete s_vulkanInstance;
- s_vulkanInstance = nullptr;
-#endif
-}
-
QSGRhiSupport::QSGRhiSupport()
: m_settingsApplied(false),
m_enableRhi(false),
@@ -256,21 +194,14 @@ void QSGRhiSupport::applySettings()
void QSGRhiSupport::adjustToPlatformQuirks()
{
#if defined(Q_OS_MACOS) || defined(Q_OS_IOS)
-
- // ### For now just create a throwaway QRhi instance. This will be replaced
- // by a more lightweight way, once a helper function is added gui/rhi.
-
// A macOS VM may not have Metal support at all. We have to decide at this
// point, it will be too late afterwards, and the only way is to see if
// MTLCreateSystemDefaultDevice succeeds.
if (m_rhiBackend == QRhi::Metal) {
QRhiMetalInitParams rhiParams;
- QRhi *tempRhi = QRhi::create(m_rhiBackend, &rhiParams, {});
- if (!tempRhi) {
+ if (!QRhi::probe(m_rhiBackend, &rhiParams)) {
m_rhiBackend = QRhi::OpenGLES2;
qCDebug(QSG_LOG_INFO, "Metal does not seem to be supported. Falling back to OpenGL.");
- } else {
- delete tempRhi;
}
}
#endif
@@ -574,8 +505,14 @@ void QSGRhiSupport::prepareWindowForRhi(QQuickWindow *window)
// always be under the application's control then (since the default
// instance we could create here would not be configurable by the
// application in any way, and that is often not acceptable).
- if (!window->vulkanInstance() && !wd->renderControl)
- window->setVulkanInstance(QSGRhiSupport::defaultVulkanInstance());
+ if (!window->vulkanInstance() && !wd->renderControl) {
+ QVulkanInstance *vkinst = QVulkanDefaultInstance::instance();
+ if (vkinst)
+ qCDebug(QSG_LOG_INFO) << "Got Vulkan instance from QVulkanDefaultInstance, requested api version was" << vkinst->apiVersion();
+ else
+ qCDebug(QSG_LOG_INFO) << "No Vulkan instance from QVulkanDefaultInstance, expect problems";
+ window->setVulkanInstance(vkinst);
+ }
}
#else
Q_UNUSED(window);
@@ -648,6 +585,8 @@ QSGRhiSupport::RhiCreateResult QSGRhiSupport::createRhi(QQuickWindow *window, QO
#endif
#if QT_CONFIG(vulkan)
if (backend == QRhi::Vulkan) {
+ if (isDebugLayerRequested())
+ QVulkanDefaultInstance::setFlag(QVulkanDefaultInstance::EnableValidation, true);
QRhiVulkanInitParams rhiParams;
prepareWindowForRhi(window); // sets a vulkanInstance if not yet present
rhiParams.inst = window->vulkanInstance();
diff --git a/src/quick/scenegraph/qsgrhisupport_p.h b/src/quick/scenegraph/qsgrhisupport_p.h
index 90cc8328f9..101941875e 100644
--- a/src/quick/scenegraph/qsgrhisupport_p.h
+++ b/src/quick/scenegraph/qsgrhisupport_p.h
@@ -77,7 +77,6 @@
QT_BEGIN_NAMESPACE
class QSGDefaultRenderContext;
-class QVulkanInstance;
class QOffscreenSurface;
// Opting in/out of QRhi and choosing the default/requested backend is managed
@@ -85,9 +84,6 @@ class QOffscreenSurface;
// creating a render loop. A well-written render loop sets up its QRhi and
// related machinery using the helper functions in here.
//
-// cleanup() must be called to perform global (not per thread) cleanup, such
-// as, destroying the QVulkanInstance (if one was created in vulkanInstance()).
-//
// In addition, the class provides handy conversion and query stuff for the
// renderloop and the QSGRendererInterface implementations.
//
@@ -96,8 +92,6 @@ class Q_QUICK_PRIVATE_EXPORT QSGRhiSupport
public:
static QSGRhiSupport *instance_internal();
static QSGRhiSupport *instance();
- static QVulkanInstance *defaultVulkanInstance();
- static void cleanupDefaultVulkanInstance();
static int chooseSampleCountForWindowWithRhi(QWindow *window, QRhi *rhi);
static QImage grabAndBlockInCurrentFrame(QRhi *rhi, QRhiCommandBuffer *cb, QRhiTexture *src = nullptr);
static void checkEnvQSgInfo();
diff --git a/src/quick/scenegraph/util/qsgrhiatlastexture.cpp b/src/quick/scenegraph/util/qsgrhiatlastexture.cpp
index 2a7be48d3d..5541c4f2da 100644
--- a/src/quick/scenegraph/util/qsgrhiatlastexture.cpp
+++ b/src/quick/scenegraph/util/qsgrhiatlastexture.cpp
@@ -67,8 +67,13 @@ Manager::Manager(QSGDefaultRenderContext *rc, const QSize &surfacePixelSize, QSu
, m_rhi(rc->rhi())
{
const int maxSize = m_rhi->resourceLimit(QRhi::TextureSizeMax);
- int w = qMin(maxSize, qt_sg_envInt("QSG_ATLAS_WIDTH", qMax(512U, qNextPowerOfTwo(surfacePixelSize.width() - 1))));
- int h = qMin(maxSize, qt_sg_envInt("QSG_ATLAS_HEIGHT", qMax(512U, qNextPowerOfTwo(surfacePixelSize.height() - 1))));
+ // surfacePixelSize is just a hint that was passed in when initializing the
+ // rendercontext, likely based on the window size, if it was available,
+ // that is. Therefore, it may be anything, incl. zero and negative.
+ const int widthHint = qMax(1, surfacePixelSize.width());
+ const int heightHint = qMax(1, surfacePixelSize.height());
+ int w = qMin(maxSize, qt_sg_envInt("QSG_ATLAS_WIDTH", qMax(512U, qNextPowerOfTwo(widthHint - 1))));
+ int h = qMin(maxSize, qt_sg_envInt("QSG_ATLAS_HEIGHT", qMax(512U, qNextPowerOfTwo(heightHint - 1))));
if (maybeSurface && maybeSurface->surfaceClass() == QSurface::Window) {
QWindow *window = static_cast<QWindow *>(maybeSurface);
diff --git a/src/quick/scenegraph/util/qsgtexturematerial.cpp b/src/quick/scenegraph/util/qsgtexturematerial.cpp
index 82cdd03acc..92f66af011 100644
--- a/src/quick/scenegraph/util/qsgtexturematerial.cpp
+++ b/src/quick/scenegraph/util/qsgtexturematerial.cpp
@@ -309,6 +309,8 @@ int QSGOpaqueTextureMaterial::compare(const QSGMaterial *o) const
{
Q_ASSERT(o && type() == o->type());
const QSGOpaqueTextureMaterial *other = static_cast<const QSGOpaqueTextureMaterial *>(o);
+ Q_ASSERT(m_texture);
+ Q_ASSERT(other->texture());
const qint64 diff = m_texture->comparisonKey() - other->texture()->comparisonKey();
if (diff != 0)
return diff < 0 ? -1 : 1;
diff --git a/src/quick/util/qquickapplication.cpp b/src/quick/util/qquickapplication.cpp
index 0ed3990738..e850249b65 100644
--- a/src/quick/util/qquickapplication.cpp
+++ b/src/quick/util/qquickapplication.cpp
@@ -210,6 +210,32 @@ QT_BEGIN_NAMESPACE
*/
/*!
+ \qmlproperty StyleHints Application::styleHints
+
+ The \c styleHints property provides platform-specific style hints and settings.
+ See the \l QStyleHints documentation for further details.
+
+ The following example uses \c styleHints to determine whether an
+ item should gain focus on mouse press or touch release:
+ \code
+ import QtQuick
+
+ MouseArea {
+ id: button
+
+ onPressed: {
+ if (!Application.styleHints.setFocusOnTouchRelease)
+ button.forceActiveFocus()
+ }
+ onReleased: {
+ if (Application.styleHints.setFocusOnTouchRelease)
+ button.forceActiveFocus()
+ }
+ }
+ \endcode
+ */
+
+/*!
\qmlsignal Application::aboutToQuit()
This signal is emitted when the application is about to quit the main
@@ -273,6 +299,11 @@ QString QQuickApplication::displayName() const
return QGuiApplication::applicationDisplayName();
}
+QStyleHints *QQuickApplication::styleHints()
+{
+ return QGuiApplication::styleHints();
+}
+
void QQuickApplication::setDisplayName(const QString &displayName)
{
return QGuiApplication::setApplicationDisplayName(displayName);
diff --git a/src/quick/util/qquickapplication_p.h b/src/quick/util/qquickapplication_p.h
index dd67b4b11d..d8f4b3a6ee 100644
--- a/src/quick/util/qquickapplication_p.h
+++ b/src/quick/util/qquickapplication_p.h
@@ -58,6 +58,7 @@
#include <QtQml/private/qqmlglobal_p.h>
#include <QtGui/qfont.h>
+#include <QtGui/qstylehints.h>
#include <QtCore/qobject.h>
@@ -73,6 +74,7 @@ class Q_QUICK_PRIVATE_EXPORT QQuickApplication : public QQmlApplication
Q_PROPERTY(QFont font READ font CONSTANT)
Q_PROPERTY(QString displayName READ displayName WRITE setDisplayName NOTIFY displayNameChanged)
Q_PROPERTY(QQmlListProperty<QQuickScreenInfo> screens READ screens NOTIFY screensChanged)
+ Q_PROPERTY(QStyleHints *styleHints READ styleHints CONSTANT)
QML_NAMED_ELEMENT(Application)
QML_SINGLETON
@@ -89,6 +91,7 @@ public:
QQmlListProperty<QQuickScreenInfo> screens();
QString displayName() const;
void setDisplayName(const QString &displayName);
+ QStyleHints *styleHints();
Q_SIGNALS:
void activeChanged();
diff --git a/src/quick/util/qquickfontloader.cpp b/src/quick/util/qquickfontloader.cpp
index 3242defceb..a5c40f6139 100644
--- a/src/quick/util/qquickfontloader.cpp
+++ b/src/quick/util/qquickfontloader.cpp
@@ -58,6 +58,7 @@
#endif
#include <QtCore/QCoreApplication>
+#include <QtCore/private/qduplicatetracker_p.h>
#include <QtGui/private/qfontdatabase_p.h>
@@ -172,13 +173,10 @@ public:
void reset()
{
- QVector<QQuickFontObject *> deleted;
- QHash<QUrl, QQuickFontObject*>::iterator it;
- for (it = map.begin(); it != map.end(); ++it) {
- if (!deleted.contains(it.value())) {
- deleted.append(it.value());
- delete it.value();
- }
+ QDuplicateTracker<QQuickFontObject *, 256> deleted(map.size());
+ for (QQuickFontObject *fo : std::as_const(map)) {
+ if (!deleted.hasSeen(fo))
+ delete fo;
}
map.clear();
}
diff --git a/src/quick/util/qquickforeignutils_p.h b/src/quick/util/qquickforeignutils_p.h
index 4d6288bc36..0f7869531f 100644
--- a/src/quick/util/qquickforeignutils_p.h
+++ b/src/quick/util/qquickforeignutils_p.h
@@ -67,6 +67,14 @@
QT_BEGIN_NAMESPACE
+struct QStyleHintsForeign
+{
+ Q_GADGET
+ QML_FOREIGN(QStyleHints)
+ QML_ANONYMOUS
+ QML_ADDED_IN_VERSION(6, 4)
+};
+
#if QT_CONFIG(validator)
struct QValidatorForeign
{
@@ -95,6 +103,7 @@ struct QInputMethodForeign
QML_FOREIGN(QInputMethod)
QML_NAMED_ELEMENT(InputMethod)
QML_ADDED_IN_VERSION(2, 0)
+ QML_REMOVED_IN_VERSION(6, 4)
QML_UNCREATABLE("InputMethod is an abstract class.")
};
#endif // QT_CONFIG(im)
diff --git a/src/quick/util/qquickinputmethod.cpp b/src/quick/util/qquickinputmethod.cpp
new file mode 100644
index 0000000000..09f1e63016
--- /dev/null
+++ b/src/quick/util/qquickinputmethod.cpp
@@ -0,0 +1,159 @@
+/****************************************************************************
+**
+** Copyright (C) 2022 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtQuick module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qquickinputmethod_p.h"
+
+#include <QtGui/qguiapplication.h>
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \qmltype InputMethod
+ \inqmlmodule QtQuick.
+
+ \brief Provides access to \l QInputMethod for QML applications.
+
+ The InputMethod singleton allows access to application's \l QInputMethod object
+ and all its properties and slots. See the \l QInputMethod documentation for
+ further details.
+*/
+
+QQuickInputMethod::QQuickInputMethod(QObject *parent) : QObject(parent)
+{
+ QInputMethod *inputMethod = QGuiApplication::inputMethod();
+ connect(inputMethod, &QInputMethod::anchorRectangleChanged, this,
+ &QQuickInputMethod::anchorRectangleChanged);
+ connect(inputMethod, &QInputMethod::animatingChanged, this,
+ &QQuickInputMethod::animatingChanged);
+ connect(inputMethod, &QInputMethod::cursorRectangleChanged, this,
+ &QQuickInputMethod::cursorRectangleChanged);
+ connect(inputMethod, &QInputMethod::inputDirectionChanged, this,
+ &QQuickInputMethod::inputDirectionChanged);
+ connect(inputMethod, &QInputMethod::inputItemClipRectangleChanged, this,
+ &QQuickInputMethod::inputItemClipRectangleChanged);
+ connect(inputMethod, &QInputMethod::keyboardRectangleChanged, this,
+ &QQuickInputMethod::keyboardRectangleChanged);
+ connect(inputMethod, &QInputMethod::localeChanged, this, &QQuickInputMethod::localeChanged);
+ connect(inputMethod, &QInputMethod::visibleChanged, this, &QQuickInputMethod::visibleChanged);
+}
+
+void QQuickInputMethod::commit()
+{
+ QGuiApplication::inputMethod()->commit();
+}
+void QQuickInputMethod::hide()
+{
+ QGuiApplication::inputMethod()->hide();
+}
+void QQuickInputMethod::invokeAction(QInputMethod::Action a, int cursorPosition)
+{
+ QGuiApplication::inputMethod()->invokeAction(a, cursorPosition);
+}
+void QQuickInputMethod::reset()
+{
+ QGuiApplication::inputMethod()->reset();
+}
+void QQuickInputMethod::show()
+{
+ QGuiApplication::inputMethod()->show();
+}
+void QQuickInputMethod::update(Qt::InputMethodQueries queries)
+{
+ QGuiApplication::inputMethod()->update(queries);
+}
+
+QRectF QQuickInputMethod::anchorRectangle() const
+{
+ return QGuiApplication::inputMethod()->cursorRectangle();
+}
+QRectF QQuickInputMethod::cursorRectangle() const
+{
+ return QGuiApplication::inputMethod()->cursorRectangle();
+}
+Qt::LayoutDirection QQuickInputMethod::inputDirection() const
+{
+ return QGuiApplication::inputMethod()->inputDirection();
+}
+QRectF QQuickInputMethod::inputItemClipRectangle() const
+{
+ return QGuiApplication::inputMethod()->inputItemClipRectangle();
+}
+
+QRectF QQuickInputMethod::inputItemRectangle() const
+{
+ return QGuiApplication::inputMethod()->inputItemRectangle();
+}
+void QQuickInputMethod::setInputItemRectangle(const QRectF &rect)
+{
+ QGuiApplication::inputMethod()->setInputItemRectangle(rect);
+}
+
+QTransform QQuickInputMethod::inputItemTransform() const
+{
+ return QGuiApplication::inputMethod()->inputItemTransform();
+}
+void QQuickInputMethod::setInputItemTransform(const QTransform &transform)
+{
+ QGuiApplication::inputMethod()->setInputItemTransform(transform);
+}
+
+bool QQuickInputMethod::isAnimating() const
+{
+ return QGuiApplication::inputMethod()->isAnimating();
+}
+
+bool QQuickInputMethod::isVisible() const
+{
+ return QGuiApplication::inputMethod()->isVisible();
+}
+void QQuickInputMethod::setVisible(bool visible)
+{
+ QGuiApplication::inputMethod()->setVisible(visible);
+}
+
+QRectF QQuickInputMethod::keyboardRectangle() const
+{
+ return QGuiApplication::inputMethod()->keyboardRectangle();
+}
+QLocale QQuickInputMethod::locale() const
+{
+ return QGuiApplication::inputMethod()->locale();
+}
+
+QT_END_NAMESPACE
diff --git a/src/quick/util/qquickinputmethod_p.h b/src/quick/util/qquickinputmethod_p.h
new file mode 100644
index 0000000000..fe94da667b
--- /dev/null
+++ b/src/quick/util/qquickinputmethod_p.h
@@ -0,0 +1,122 @@
+/****************************************************************************
+**
+** Copyright (C) 2022 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtQuick module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQUICKINPUTMETHOD_P_H
+#define QQUICKINPUTMETHOD_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QtCore/qobject.h>
+#include <QtCore/qlocale.h>
+#include <QtCore/qrect.h>
+#include <QtGui/qtransform.h>
+#include <QtGui/qinputmethod.h>
+#include <QtQml/qqml.h>
+
+#include <private/qtquickglobal_p.h>
+
+QT_BEGIN_NAMESPACE
+class Q_QUICK_PRIVATE_EXPORT QQuickInputMethod : public QObject
+{
+ Q_OBJECT
+ QML_NAMED_ELEMENT(InputMethod)
+ QML_ADDED_IN_VERSION(6, 4)
+ QML_SINGLETON
+
+ Q_PROPERTY(QRectF cursorRectangle READ cursorRectangle NOTIFY cursorRectangleChanged)
+ Q_PROPERTY(QRectF anchorRectangle READ anchorRectangle NOTIFY anchorRectangleChanged)
+ Q_PROPERTY(QRectF keyboardRectangle READ keyboardRectangle NOTIFY keyboardRectangleChanged)
+ Q_PROPERTY(QRectF inputItemClipRectangle READ inputItemClipRectangle NOTIFY
+ inputItemClipRectangleChanged)
+ Q_PROPERTY(bool visible READ isVisible NOTIFY visibleChanged)
+ Q_PROPERTY(bool animating READ isAnimating NOTIFY animatingChanged)
+ Q_PROPERTY(QLocale locale READ locale NOTIFY localeChanged)
+ Q_PROPERTY(Qt::LayoutDirection inputDirection READ inputDirection NOTIFY inputDirectionChanged)
+public:
+ explicit QQuickInputMethod(QObject *parent = nullptr);
+
+ QRectF anchorRectangle() const;
+ QRectF cursorRectangle() const;
+ Qt::LayoutDirection inputDirection() const;
+ QRectF inputItemClipRectangle() const;
+
+ QRectF inputItemRectangle() const;
+ void setInputItemRectangle(const QRectF &rect);
+
+ QTransform inputItemTransform() const;
+ void setInputItemTransform(const QTransform &transform);
+
+ bool isAnimating() const;
+
+ bool isVisible() const;
+ void setVisible(bool visible);
+
+ QRectF keyboardRectangle() const;
+ QLocale locale() const;
+signals:
+ void anchorRectangleChanged();
+ void animatingChanged();
+ void cursorRectangleChanged();
+ void inputDirectionChanged(Qt::LayoutDirection newDirection);
+ void inputItemClipRectangleChanged();
+ void keyboardRectangleChanged();
+ void localeChanged();
+ void visibleChanged();
+
+public slots:
+ void commit();
+ void hide();
+ void invokeAction(QInputMethod::Action a, int cursorPosition);
+ void reset();
+ void show();
+ void update(Qt::InputMethodQueries queries);
+};
+
+QT_END_NAMESPACE
+
+#endif // QQUICKINPUTMETHOD_P_H
diff --git a/src/quick/util/qquickpath_p.h b/src/quick/util/qquickpath_p.h
index 5a4c72848c..f8af708ae7 100644
--- a/src/quick/util/qquickpath_p.h
+++ b/src/quick/util/qquickpath_p.h
@@ -62,6 +62,7 @@ QT_REQUIRE_CONFIG(quick_path);
#include <private/qtquickglobal_p.h>
#include <QtCore/QObject>
+#include <QtCore/QHash>
#include <QtGui/QPainterPath>
#include <QtGui/QFont>
diff --git a/src/quick/util/qquickpixmapcache.cpp b/src/quick/util/qquickpixmapcache.cpp
index f403615d83..9ecdbc1846 100644
--- a/src/quick/util/qquickpixmapcache.cpp
+++ b/src/quick/util/qquickpixmapcache.cpp
@@ -328,6 +328,7 @@ public:
QQuickImageProviderOptions::AutoTransform appliedTransform;
QColorSpace targetColorSpace;
+ QIODevice *specialDevice = nullptr;
QQuickTextureFactory *textureFactory;
QIntrusiveList<QQuickPixmap, &QQuickPixmap::dataListNode> declarativePixmaps;
@@ -895,40 +896,54 @@ void QQuickPixmapReader::processJob(QQuickPixmapReply *runningJob, const QUrl &u
QImage image;
QQuickPixmapReply::ReadError errorCode = QQuickPixmapReply::NoError;
QString errorStr;
- QFile f(existingImageFileForPath(localFile));
QSize readSize;
- if (f.open(QIODevice::ReadOnly)) {
- QSGTextureReader texReader(&f, localFile);
- if (backendSupport()->hasOpenGL && texReader.isTexture()) {
- QQuickTextureFactory *factory = texReader.read();
- if (factory) {
- readSize = factory->textureSize();
+
+ if (runningJob->data && runningJob->data->specialDevice) {
+ int frameCount;
+ int const frame = runningJob->data ? runningJob->data->frame : 0;
+ if (!readImage(url, runningJob->data->specialDevice, &image, &errorStr, &readSize, &frameCount,
+ runningJob->requestRegion, runningJob->requestSize,
+ runningJob->providerOptions, nullptr, frame)) {
+ errorCode = QQuickPixmapReply::Loading;
+ } else if (runningJob->data) {
+ runningJob->data->frameCount = frameCount;
+ }
+ } else {
+ QFile f(existingImageFileForPath(localFile));
+ if (f.open(QIODevice::ReadOnly)) {
+ QSGTextureReader texReader(&f, localFile);
+ if (backendSupport()->hasOpenGL && texReader.isTexture()) {
+ QQuickTextureFactory *factory = texReader.read();
+ if (factory) {
+ readSize = factory->textureSize();
+ } else {
+ errorStr = QQuickPixmap::tr("Error decoding: %1").arg(url.toString());
+ if (f.fileName() != localFile)
+ errorStr += QString::fromLatin1(" (%1)").arg(f.fileName());
+ errorCode = QQuickPixmapReply::Decoding;
+ }
+ mutex.lock();
+ if (!cancelled.contains(runningJob))
+ runningJob->postReply(errorCode, errorStr, readSize, factory);
+ mutex.unlock();
+ return;
} else {
- errorStr = QQuickPixmap::tr("Error decoding: %1").arg(url.toString());
- if (f.fileName() != localFile)
- errorStr += QString::fromLatin1(" (%1)").arg(f.fileName());
- errorCode = QQuickPixmapReply::Decoding;
+ int frameCount;
+ int const frame = runningJob->data ? runningJob->data->frame : 0;
+ if (!readImage(url, &f, &image, &errorStr, &readSize, &frameCount,
+ runningJob->requestRegion, runningJob->requestSize,
+ runningJob->providerOptions, nullptr, frame)) {
+ errorCode = QQuickPixmapReply::Loading;
+ if (f.fileName() != localFile)
+ errorStr += QString::fromLatin1(" (%1)").arg(f.fileName());
+ } else if (runningJob->data) {
+ runningJob->data->frameCount = frameCount;
+ }
}
- mutex.lock();
- if (!cancelled.contains(runningJob))
- runningJob->postReply(errorCode, errorStr, readSize, factory);
- mutex.unlock();
- return;
} else {
- int frameCount;
- int const frame = runningJob->data ? runningJob->data->frame : 0;
- if (!readImage(url, &f, &image, &errorStr, &readSize, &frameCount, runningJob->requestRegion, runningJob->requestSize,
- runningJob->providerOptions, nullptr, frame)) {
- errorCode = QQuickPixmapReply::Loading;
- if (f.fileName() != localFile)
- errorStr += QString::fromLatin1(" (%1)").arg(f.fileName());
- } else if (runningJob->data) {
- runningJob->data->frameCount = frameCount;
- }
+ errorStr = QQuickPixmap::tr("Cannot open: %1").arg(url.toString());
+ errorCode = QQuickPixmapReply::Loading;
}
- } else {
- errorStr = QQuickPixmap::tr("Cannot open: %1").arg(url.toString());
- errorCode = QQuickPixmapReply::Loading;
}
mutex.lock();
if (!cancelled.contains(runningJob))
@@ -1738,6 +1753,47 @@ void QQuickPixmap::load(QQmlEngine *engine, const QUrl &url, const QRect &reques
}
}
+/*! \internal
+ Attempts to load an image from the given \a url via the given \a device.
+ This is for special cases when the QImageIOHandler can benefit from reusing
+ the I/O device, or from something extra that a subclass of QIODevice
+ carries with it. So far, this code doesn't support loading anything other
+ than a QImage, for example compressed textures. It can be added if needed.
+*/
+void QQuickPixmap::loadImageFromDevice(QQmlEngine *engine, QIODevice *device, const QUrl &url,
+ const QRect &requestRegion, const QSize &requestSize,
+ const QQuickImageProviderOptions &providerOptions, int frame, int frameCount)
+{
+ auto oldD = d;
+ QQuickPixmapKey key = { &url, &requestRegion, &requestSize, frame, providerOptions };
+ QQuickPixmapStore *store = pixmapStore();
+ QHash<QQuickPixmapKey, QQuickPixmapData *>::Iterator iter = store->m_cache.end();
+ iter = store->m_cache.find(key);
+ if (iter == store->m_cache.end()) {
+ if (!engine)
+ return;
+
+ d = new QQuickPixmapData(this, url, requestRegion, requestSize, providerOptions,
+ QQuickImageProviderOptions::UsePluginDefaultTransform, frame, frameCount);
+ d->specialDevice = device;
+ d->addToCache();
+
+ QQuickPixmapReader::readerMutex.lock();
+ d->reply = QQuickPixmapReader::instance(engine)->getImage(d);
+ if (oldD) {
+ QObject::connect(d->reply, &QQuickPixmapReply::finished, [oldD, this]() {
+ oldD->declarativePixmaps.remove(this);
+ oldD->release();
+ });
+ }
+ QQuickPixmapReader::readerMutex.unlock();
+ } else {
+ d = *iter;
+ d->addref();
+ d->declarativePixmaps.insert(this);
+ }
+}
+
void QQuickPixmap::clear()
{
if (d) {
diff --git a/src/quick/util/qquickpixmapcache_p.h b/src/quick/util/qquickpixmapcache_p.h
index 5600443d31..68691b54e3 100644
--- a/src/quick/util/qquickpixmapcache_p.h
+++ b/src/quick/util/qquickpixmapcache_p.h
@@ -174,6 +174,9 @@ public:
void load(QQmlEngine *, const QUrl &, const QRect &requestRegion, const QSize &requestSize,
QQuickPixmap::Options options, const QQuickImageProviderOptions &providerOptions, int frame = 0, int frameCount = 1,
qreal devicePixelRatio = 1.0);
+ void loadImageFromDevice(QQmlEngine *engine, QIODevice *device, const QUrl &url,
+ const QRect &requestRegion, const QSize &requestSize,
+ const QQuickImageProviderOptions &providerOptions, int frame = 0, int frameCount = 1);
void clear();
void clear(QObject *);
diff --git a/src/quick/util/qquickstate_p_p.h b/src/quick/util/qquickstate_p_p.h
index d75cfc32ee..3f0545df91 100644
--- a/src/quick/util/qquickstate_p_p.h
+++ b/src/quick/util/qquickstate_p_p.h
@@ -212,13 +212,19 @@ public:
struct OperationGuard : public QQmlGuard<QQuickStateOperation>
{
- OperationGuard(QObject *obj, QList<OperationGuard> *l) : list(l) {
+ OperationGuard(QObject *obj, QList<OperationGuard> *l) : QQmlGuard<QQuickStateOperation>(
+ OperationGuard::objectDestroyedImpl, nullptr)
+ ,list(l)
+ {
setObject(static_cast<QQuickStateOperation *>(obj));
}
QList<OperationGuard> *list;
- void objectDestroyed(QQuickStateOperation *) override {
+
+ private:
+ static void objectDestroyedImpl(QQmlGuardImpl *guard) {
+ auto This = static_cast<OperationGuard *>(guard);
// we assume priv will always be destroyed after objectDestroyed calls
- list->removeOne(*this);
+ This->list->removeOne(*This);
}
};
QList<OperationGuard> operations;
diff --git a/src/quick/util/qquickstategroup.cpp b/src/quick/util/qquickstategroup.cpp
index d664b67485..781d2cf1fb 100644
--- a/src/quick/util/qquickstategroup.cpp
+++ b/src/quick/util/qquickstategroup.cpp
@@ -376,7 +376,15 @@ bool QQuickStateGroupPrivate::updateAutoState()
QQuickState *state = states.at(ii);
if (state->isWhenKnown()) {
if (state->isNamed()) {
- if (state->when()) {
+ bool whenValue = state->when();
+ const QQmlProperty whenProp(state, u"when"_qs);
+ const auto potentialWhenBinding = QQmlAnyBinding::ofProperty(whenProp);
+ Q_ASSERT(!potentialWhenBinding.isUntypedPropertyBinding());
+ // if there is a binding, the value in when might not be up-to-date at this point
+ // so we manually reevaluate the binding
+ if (auto abstractBinding = dynamic_cast<QQmlBinding *>( potentialWhenBinding.asAbstractBinding()))
+ whenValue = abstractBinding->evaluate().toBool();
+ if (whenValue) {
qCDebug(lcStates) << "Setting auto state due to expression";
if (currentState != state->name()) {
q->setState(state->name());
diff --git a/src/quick/util/qquickvalidator.cpp b/src/quick/util/qquickvalidator.cpp
index c309460263..7e93d87555 100644
--- a/src/quick/util/qquickvalidator.cpp
+++ b/src/quick/util/qquickvalidator.cpp
@@ -56,6 +56,8 @@ QT_BEGIN_NAMESPACE
interpret the number and will accept locale specific digits, group separators, and positive
and negative signs. In addition, IntValidator is always guaranteed to accept a number
formatted according to the "C" locale.
+
+ \sa DoubleValidator, RegularExpressionValidator, {Validating Input Text}
*/
QQuickIntValidator::QQuickIntValidator(QObject *parent)
@@ -131,6 +133,8 @@ void QQuickIntValidator::resetLocaleName()
it is also rejected. If \l notation is DoubleValidator.ScientificNotation,
and the input is not in the valid range, it is accecpted but invalid. The
value may yet become valid by changing the exponent.
+
+ \sa IntValidator, RegularExpressionValidator, {Validating Input Text}
*/
QQuickDoubleValidator::QQuickDoubleValidator(QObject *parent)
@@ -210,6 +214,8 @@ void QQuickDoubleValidator::resetLocaleName()
The RegularExpressionValidator type provides a validator, that counts as valid any string which
matches a specified regular expression.
+
+ \sa IntValidator, DoubleValidator, {Validating Input Text}
*/
/*!
\qmlproperty regularExpression QtQuick::RegularExpressionValidator::regularExpression