aboutsummaryrefslogtreecommitdiffstats
path: root/src/quick/items
diff options
context:
space:
mode:
Diffstat (limited to 'src/quick/items')
-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
23 files changed, 624 insertions, 355 deletions
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;