aboutsummaryrefslogtreecommitdiffstats
path: root/src/quick/items
diff options
context:
space:
mode:
Diffstat (limited to 'src/quick/items')
-rw-r--r--src/quick/items/qquickaccessibleattached.cpp2
-rw-r--r--src/quick/items/qquickdrag_p.h3
-rw-r--r--src/quick/items/qquickflickable.cpp94
-rw-r--r--src/quick/items/qquickflickable_p_p.h5
-rw-r--r--src/quick/items/qquickgridview.cpp10
-rw-r--r--src/quick/items/qquickitem.cpp27
-rw-r--r--src/quick/items/qquickitem_p.h2
-rw-r--r--src/quick/items/qquickitemview.cpp19
-rw-r--r--src/quick/items/qquickitemview_p_p.h1
-rw-r--r--src/quick/items/qquickitemviewtransition.cpp5
-rw-r--r--src/quick/items/qquicklistview.cpp10
-rw-r--r--src/quick/items/qquickpathview.cpp10
-rw-r--r--src/quick/items/qquickpathview_p_p.h6
-rw-r--r--src/quick/items/qquickpincharea.cpp10
-rw-r--r--src/quick/items/qquickrepeater.cpp6
-rw-r--r--src/quick/items/qquicktext.cpp34
-rw-r--r--src/quick/items/qquicktextedit.cpp63
-rw-r--r--src/quick/items/qquicktextedit_p_p.h13
-rw-r--r--src/quick/items/qquicktextinput.cpp23
-rw-r--r--src/quick/items/qquicktreeview.cpp2
-rw-r--r--src/quick/items/qquickwindow.cpp19
-rw-r--r--src/quick/items/qquickwindow_p.h2
22 files changed, 284 insertions, 82 deletions
diff --git a/src/quick/items/qquickaccessibleattached.cpp b/src/quick/items/qquickaccessibleattached.cpp
index 730bbe4404..f63ab764f1 100644
--- a/src/quick/items/qquickaccessibleattached.cpp
+++ b/src/quick/items/qquickaccessibleattached.cpp
@@ -109,7 +109,7 @@ QT_BEGIN_NAMESPACE
This property sets an accessible description.
Similar to the name it describes the item. The description
can be a little more verbose and tell what the item does,
- for example the functionallity of the button it describes.
+ for example the functionality of the button it describes.
*/
/*!
diff --git a/src/quick/items/qquickdrag_p.h b/src/quick/items/qquickdrag_p.h
index e17a28d07e..26191c6545 100644
--- a/src/quick/items/qquickdrag_p.h
+++ b/src/quick/items/qquickdrag_p.h
@@ -108,9 +108,12 @@ public:
void grab(QQuickItem *item) { m_items.insert(new Item(item)); }
iterator release(iterator at) { Item *item = *at; at = at.erase(); delete item; return at; }
+ auto& ignoreList() { return m_ignoreDragItems; }
+
private:
ItemList m_items;
+ QVarLengthArray<QQuickItem *, 4> m_ignoreDragItems;
QObject *m_target;
};
diff --git a/src/quick/items/qquickflickable.cpp b/src/quick/items/qquickflickable.cpp
index 8dc9a9afe6..4ddbfa509a 100644
--- a/src/quick/items/qquickflickable.cpp
+++ b/src/quick/items/qquickflickable.cpp
@@ -43,6 +43,8 @@
#include "qquickwindow.h"
#include "qquickwindow_p.h"
#include "qquickevents_p_p.h"
+#include "qquickmousearea_p.h"
+#include "qquickdrag_p.h"
#include <QtQuick/private/qquickpointerhandler_p.h>
#include <QtQuick/private/qquicktransition_p.h>
@@ -352,7 +354,7 @@ void QQuickFlickablePrivate::AxisData::updateVelocity()
}
}
-void QQuickFlickablePrivate::itemGeometryChanged(QQuickItem *item, QQuickGeometryChange change, const QRectF &)
+void QQuickFlickablePrivate::itemGeometryChanged(QQuickItem *item, QQuickGeometryChange change, const QRectF &oldGeom)
{
Q_Q(QQuickFlickable);
if (item == contentItem) {
@@ -361,8 +363,14 @@ void QQuickFlickablePrivate::itemGeometryChanged(QQuickItem *item, QQuickGeometr
orient |= Qt::Horizontal;
if (change.yChange())
orient |= Qt::Vertical;
- if (orient)
+ if (orient) {
q->viewportMoved(orient);
+ const QPointF deltaMoved = item->position() - oldGeom.topLeft();
+ if (hData.contentPositionChangedExternallyDuringDrag)
+ hData.pressPos += deltaMoved.x();
+ if (vData.contentPositionChangedExternallyDuringDrag)
+ vData.pressPos += deltaMoved.y();
+ }
if (orient & Qt::Horizontal)
emit q->contentXChanged();
if (orient & Qt::Vertical)
@@ -554,8 +562,8 @@ void QQuickFlickablePrivate::updateBeginningEnd()
const qreal maxyextent = -q->maxYExtent();
const qreal minyextent = -q->minYExtent();
const qreal ypos = -vData.move.value();
- bool atBeginning = fuzzyLessThanOrEqualTo(ypos, minyextent);
- bool atEnd = fuzzyLessThanOrEqualTo(maxyextent, ypos);
+ bool atBeginning = fuzzyLessThanOrEqualTo(ypos, std::ceil(minyextent));
+ bool atEnd = fuzzyLessThanOrEqualTo(std::floor(maxyextent), ypos);
if (atBeginning != vData.atBeginning) {
vData.atBeginning = atBeginning;
@@ -574,8 +582,8 @@ void QQuickFlickablePrivate::updateBeginningEnd()
const qreal maxxextent = -q->maxXExtent();
const qreal minxextent = -q->minXExtent();
const qreal xpos = -hData.move.value();
- atBeginning = fuzzyLessThanOrEqualTo(xpos, minxextent);
- atEnd = fuzzyLessThanOrEqualTo(maxxextent, xpos);
+ atBeginning = fuzzyLessThanOrEqualTo(xpos, std::ceil(minxextent));
+ atEnd = fuzzyLessThanOrEqualTo(std::floor(maxxextent), xpos);
if (atBeginning != hData.atBeginning) {
hData.atBeginning = atBeginning;
@@ -822,8 +830,11 @@ void QQuickFlickable::setContentX(qreal pos)
d->hData.vTime = d->timeline.time();
if (isMoving() || isFlicking())
movementEnding(true, false);
- if (!qFuzzyCompare(-pos, d->hData.move.value()))
+ if (!qFuzzyCompare(-pos, d->hData.move.value())) {
+ d->hData.contentPositionChangedExternallyDuringDrag = d->hData.dragging;
d->hData.move.setValue(-pos);
+ d->hData.contentPositionChangedExternallyDuringDrag = false;
+ }
}
qreal QQuickFlickable::contentY() const
@@ -840,8 +851,11 @@ void QQuickFlickable::setContentY(qreal pos)
d->vData.vTime = d->timeline.time();
if (isMoving() || isFlicking())
movementEnding(false, true);
- if (!qFuzzyCompare(-pos, d->vData.move.value()))
+ if (!qFuzzyCompare(-pos, d->vData.move.value())) {
+ d->vData.contentPositionChangedExternallyDuringDrag = d->vData.dragging;
d->vData.move.setValue(-pos);
+ d->vData.contentPositionChangedExternallyDuringDrag = false;
+ }
}
/*!
@@ -1655,9 +1669,9 @@ void QQuickFlickable::wheelEvent(QWheelEvent *event)
d->vData.addVelocitySample(instVelocity, d->maxVelocity);
d->vData.updateVelocity();
if ((yDelta > 0 && contentY() > -minYExtent()) || (yDelta < 0 && contentY() < -maxYExtent())) {
- d->flickY(d->vData.velocity);
- d->flickingStarted(false, true);
- if (d->vData.flicking) {
+ const bool newFlick = d->flickY(d->vData.velocity);
+ if (newFlick && (d->vData.atBeginning != (yDelta > 0) || d->vData.atEnd != (yDelta < 0))) {
+ d->flickingStarted(false, true);
d->vMoved = true;
movementStarting();
}
@@ -1672,9 +1686,9 @@ void QQuickFlickable::wheelEvent(QWheelEvent *event)
d->hData.addVelocitySample(instVelocity, d->maxVelocity);
d->hData.updateVelocity();
if ((xDelta > 0 && contentX() > -minXExtent()) || (xDelta < 0 && contentX() < -maxXExtent())) {
- d->flickX(d->hData.velocity);
- d->flickingStarted(true, false);
- if (d->hData.flicking) {
+ const bool newFlick = d->flickX(d->hData.velocity);
+ if (newFlick && (d->hData.atBeginning != (xDelta > 0) || d->hData.atEnd != (xDelta < 0))) {
+ d->flickingStarted(true, false);
d->hMoved = true;
movementStarting();
}
@@ -2553,6 +2567,23 @@ bool QQuickFlickable::filterPointerEvent(QQuickItem *receiver, QPointerEvent *ev
bool receiverDisabled = receiver && !receiver->isEnabled();
bool stealThisEvent = d->stealMouse;
bool receiverKeepsGrab = receiver && (receiver->keepMouseGrab() || receiver->keepTouchGrab());
+ bool receiverRelinquishGrab = false;
+
+ // Special case for MouseArea, try to guess what it does with the event
+ if (auto *mouseArea = qmlobject_cast<QQuickMouseArea *>(receiver)) {
+ bool preventStealing = mouseArea->preventStealing();
+ if (mouseArea->drag() && mouseArea->drag()->target())
+ preventStealing = true;
+ if (!preventStealing && receiverKeepsGrab) {
+ receiverRelinquishGrab = !receiverDisabled
+ || (QQuickDeliveryAgentPrivate::isMouseEvent(event)
+ && firstPoint.state() == QEventPoint::State::Pressed
+ && (receiver->acceptedMouseButtons() & static_cast<QMouseEvent *>(event)->button()));
+ if (receiverRelinquishGrab)
+ receiverKeepsGrab = false;
+ }
+ }
+
if ((stealThisEvent || contains(localPos)) && (!receiver || !receiverKeepsGrab || receiverDisabled)) {
QScopedPointer<QPointerEvent> localizedEvent(QQuickDeliveryAgentPrivate::clonePointerEvent(event, localPos));
localizedEvent->setAccepted(false);
@@ -2563,7 +2594,9 @@ bool QQuickFlickable::filterPointerEvent(QQuickItem *receiver, QPointerEvent *ev
case QEventPoint::State::Pressed:
d->handlePressEvent(localizedEvent.data());
d->captureDelayedPress(receiver, event);
- stealThisEvent = d->stealMouse; // Update stealThisEvent in case changed by function call above
+ // never grab the pointing device on press during filtering: do it later, during a move
+ d->stealMouse = false;
+ stealThisEvent = false;
break;
case QEventPoint::State::Released:
d->handleReleaseEvent(localizedEvent.data());
@@ -2580,7 +2613,7 @@ bool QQuickFlickable::filterPointerEvent(QQuickItem *receiver, QPointerEvent *ev
event->setExclusiveGrabber(firstPoint, this);
}
- const bool filtered = stealThisEvent || d->delayedPressEvent || receiverDisabled;
+ const bool filtered = !receiverRelinquishGrab && (stealThisEvent || d->delayedPressEvent || receiverDisabled);
if (filtered) {
event->setAccepted(true);
}
@@ -2606,18 +2639,19 @@ bool QQuickFlickable::filterPointerEvent(QQuickItem *receiver, QPointerEvent *ev
bool QQuickFlickable::childMouseEventFilter(QQuickItem *i, QEvent *e)
{
Q_D(QQuickFlickable);
+ QPointerEvent *pointerEvent = e->isPointerEvent() ? static_cast<QPointerEvent *>(e) : nullptr;
- auto wantsPointerEvent_helper = [this, d, i, e]() {
- QPointerEvent *pe = static_cast<QPointerEvent *>(e);
- QQuickDeliveryAgentPrivate::localizePointerEvent(pe, this);
- const bool wants = d->wantsPointerEvent(pe);
+ auto wantsPointerEvent_helper = [this, d, i, pointerEvent]() {
+ Q_ASSERT(pointerEvent);
+ QQuickDeliveryAgentPrivate::localizePointerEvent(pointerEvent, this);
+ const bool wants = d->wantsPointerEvent(pointerEvent);
// re-localize event back to \a i before returning
- QQuickDeliveryAgentPrivate::localizePointerEvent(pe, i);
+ QQuickDeliveryAgentPrivate::localizePointerEvent(pointerEvent, i);
return wants;
};
if (!isVisible() || !isEnabled() || !isInteractive() ||
- (e->isPointerEvent() && !wantsPointerEvent_helper())) {
+ (pointerEvent && !wantsPointerEvent_helper())) {
d->cancelInteraction();
return QQuickItem::childMouseEventFilter(i, e);
}
@@ -2629,8 +2663,8 @@ bool QQuickFlickable::childMouseEventFilter(QQuickItem *i, QEvent *e)
qCDebug(lcFilter) << "filtering UngrabMouse" << spe->points().first() << "for" << i << "grabber is" << grabber;
if (grabber != this)
mouseUngrabEvent(); // A child has been ungrabbed
- } else if (e->isPointerEvent()) {
- return filterPointerEvent(i, static_cast<QPointerEvent *>(e));
+ } else if (pointerEvent) {
+ return filterPointerEvent(i, pointerEvent);
}
return QQuickItem::childMouseEventFilter(i, e);
@@ -2898,6 +2932,12 @@ void QQuickFlickable::movementStarting()
if (!wasMoving && (d->hData.moving || d->vData.moving)) {
emit movingChanged();
emit movementStarted();
+#if QT_CONFIG(accessibility)
+ if (QAccessible::isActive()) {
+ QAccessibleEvent ev(this, QAccessible::ScrollingStart);
+ QAccessible::updateAccessibility(&ev);
+ }
+#endif
}
}
@@ -2942,6 +2982,12 @@ void QQuickFlickable::movementEnding(bool hMovementEnding, bool vMovementEnding)
if (wasMoving && !isMoving()) {
emit movingChanged();
emit movementEnded();
+#if QT_CONFIG(accessibility)
+ if (QAccessible::isActive()) {
+ QAccessibleEvent ev(this, QAccessible::ScrollingEnd);
+ QAccessible::updateAccessibility(&ev);
+ }
+#endif
}
if (hMovementEnding) {
diff --git a/src/quick/items/qquickflickable_p_p.h b/src/quick/items/qquickflickable_p_p.h
index 9bc33d436f..a0c3d4ad6c 100644
--- a/src/quick/items/qquickflickable_p_p.h
+++ b/src/quick/items/qquickflickable_p_p.h
@@ -109,6 +109,7 @@ public:
, fixingUp(false), inOvershoot(false), inRebound(false), moving(false), flicking(false)
, dragging(false), extentsChanged(false)
, explicitValue(false), minExtentDirty(true), maxExtentDirty(true)
+ , contentPositionChangedExternallyDuringDrag(false)
, unused(0)
{}
@@ -119,6 +120,7 @@ public:
dragStartOffset = 0;
fixingUp = false;
inOvershoot = false;
+ contentPositionChangedExternallyDuringDrag = false;
}
void markExtentsDirty() {
@@ -169,7 +171,8 @@ public:
bool explicitValue : 1;
mutable bool minExtentDirty : 1;
mutable bool maxExtentDirty : 1;
- uint unused : 19;
+ bool contentPositionChangedExternallyDuringDrag : 1;
+ uint unused : 18;
};
bool flickX(qreal velocity);
diff --git a/src/quick/items/qquickgridview.cpp b/src/quick/items/qquickgridview.cpp
index 5c4e4d7018..e0adac3337 100644
--- a/src/quick/items/qquickgridview.cpp
+++ b/src/quick/items/qquickgridview.cpp
@@ -208,6 +208,8 @@ public:
void updateHeader() override;
void updateFooter() override;
+ void initializeComponentItem(QQuickItem *item) const override;
+
void changedVisibleIndex(int newIndex) override;
void initializeCurrentItem() override;
@@ -853,6 +855,14 @@ void QQuickGridViewPrivate::updateFooter()
emit q->footerItemChanged();
}
+void QQuickGridViewPrivate::initializeComponentItem(QQuickItem *item) const
+{
+ QQuickGridViewAttached *attached = static_cast<QQuickGridViewAttached *>(
+ qmlAttachedPropertiesObject<QQuickGridView>(item));
+ if (attached)
+ attached->setView(const_cast<QQuickGridView*>(q_func()));
+}
+
void QQuickGridViewPrivate::updateHeader()
{
Q_Q(QQuickGridView);
diff --git a/src/quick/items/qquickitem.cpp b/src/quick/items/qquickitem.cpp
index 8102a473db..008c078f5d 100644
--- a/src/quick/items/qquickitem.cpp
+++ b/src/quick/items/qquickitem.cpp
@@ -4087,8 +4087,9 @@ void QQuickItem::mouseReleaseEvent(QMouseEvent *event)
\input item.qdocinc accepting-events
*/
-void QQuickItem::mouseDoubleClickEvent(QMouseEvent *)
+void QQuickItem::mouseDoubleClickEvent(QMouseEvent *event)
{
+ event->ignore();
}
/*!
@@ -5521,20 +5522,26 @@ bool QQuickItemPrivate::anyPointerHandlerWants(const QPointerEvent *event, const
/*!
\internal
- Deliver the \a event to all PointerHandlers which are in the pre-determined
- eventDeliveryTargets() vector. If \a avoidExclusiveGrabber is true, it skips
- delivery to any handler which is the exclusive grabber of any point within this event
- (because delivery to exclusive grabbers is handled separately).
+ Deliver the \a event to all this item's PointerHandlers, but skip
+ HoverHandlers if the event is a QMouseEvent (they are visited in
+ QQuickDeliveryAgentPrivate::deliverHoverEventToItem()), and skip handlers
+ that are in QQuickPointerHandlerPrivate::deviceDeliveryTargets().
+ If \a avoidGrabbers is true, also skip delivery to any handler that
+ is exclusively or passively grabbing any point within \a event
+ (because delivery to grabbers is handled separately).
*/
-bool QQuickItemPrivate::handlePointerEvent(QPointerEvent *event, bool avoidExclusiveGrabber)
+bool QQuickItemPrivate::handlePointerEvent(QPointerEvent *event, bool avoidGrabbers)
{
bool delivered = false;
if (extra.isAllocated()) {
for (QQuickPointerHandler *handler : extra->pointerHandlers) {
bool avoidThisHandler = false;
- if (avoidExclusiveGrabber) {
+ if (QQuickDeliveryAgentPrivate::isMouseEvent(event) &&
+ qmlobject_cast<const QQuickHoverHandler *>(handler)) {
+ avoidThisHandler = true;
+ } else if (avoidGrabbers) {
for (auto &p : event->points()) {
- if (event->exclusiveGrabber(p) == handler) {
+ if (event->exclusiveGrabber(p) == handler || event->passiveGrabbers(p).contains(handler)) {
avoidThisHandler = true;
break;
}
@@ -9508,7 +9515,9 @@ void QQuickItemLayer::updateGeometry()
{
QQuickItem *l = m_effect ? (QQuickItem *) m_effect : (QQuickItem *) m_effectSource;
Q_ASSERT(l);
- QRectF bounds = m_item->boundingRect();
+ // Avoid calling QQuickImage::boundingRect() or other overrides
+ // which may not be up-to-date at this time (QTBUG-104442, 104536)
+ QRectF bounds = m_item->QQuickItem::boundingRect();
l->setSize(bounds.size());
l->setPosition(bounds.topLeft() + m_item->position());
}
diff --git a/src/quick/items/qquickitem_p.h b/src/quick/items/qquickitem_p.h
index 839cc5bdb4..ce094b15f4 100644
--- a/src/quick/items/qquickitem_p.h
+++ b/src/quick/items/qquickitem_p.h
@@ -669,7 +669,7 @@ public:
void deliverShortcutOverrideEvent(QKeyEvent *);
bool anyPointerHandlerWants(const QPointerEvent *event, const QEventPoint &point) const;
- virtual bool handlePointerEvent(QPointerEvent *, bool avoidExclusiveGrabber = false);
+ virtual bool handlePointerEvent(QPointerEvent *, bool avoidGrabbers = false);
virtual void setVisible(bool visible);
diff --git a/src/quick/items/qquickitemview.cpp b/src/quick/items/qquickitemview.cpp
index 39e1f42fe5..943d24b32c 100644
--- a/src/quick/items/qquickitemview.cpp
+++ b/src/quick/items/qquickitemview.cpp
@@ -57,8 +57,6 @@ FxViewItem::FxViewItem(QQuickItem *i, QQuickItemView *v, bool own, QQuickItemVie
, view(v)
, attached(attached)
{
- if (attached) // can be null for default components (see createComponentItem)
- attached->setView(view);
}
QQuickItemViewChangeSet::QQuickItemViewChangeSet()
@@ -2502,12 +2500,29 @@ QQuickItem *QQuickItemViewPrivate::createComponentItem(QQmlComponent *component,
item->setZ(zValue);
QQml_setParent_noEvent(item, q->contentItem());
item->setParentItem(q->contentItem());
+
+ initializeComponentItem(item);
}
if (component)
component->completeCreate();
return item;
}
+/*!
+ \internal
+
+ Allows derived classes to do any initialization required for \a item
+ before completeCreate() is called on it. For example, any attached
+ properties required by the item can be set.
+
+ This is similar to initItem(), but as that has logic specific to
+ delegate items, we use a separate function for non-delegates.
+*/
+void QQuickItemViewPrivate::initializeComponentItem(QQuickItem *item) const
+{
+ Q_UNUSED(item);
+}
+
void QQuickItemViewPrivate::updateTrackedItem()
{
Q_Q(QQuickItemView);
diff --git a/src/quick/items/qquickitemview_p_p.h b/src/quick/items/qquickitemview_p_p.h
index d3b12268aa..d48e4160ac 100644
--- a/src/quick/items/qquickitemview_p_p.h
+++ b/src/quick/items/qquickitemview_p_p.h
@@ -178,6 +178,7 @@ public:
QQuickItem *createHighlightItem() const;
QQuickItem *createComponentItem(QQmlComponent *component, qreal zValue, bool createDefault = false) const;
+ virtual void initializeComponentItem(QQuickItem *) const;
void updateCurrent(int modelIndex);
void updateTrackedItem();
diff --git a/src/quick/items/qquickitemviewtransition.cpp b/src/quick/items/qquickitemviewtransition.cpp
index 3c84468370..6b03d6c16b 100644
--- a/src/quick/items/qquickitemviewtransition.cpp
+++ b/src/quick/items/qquickitemviewtransition.cpp
@@ -524,7 +524,8 @@ void QQuickItemViewTransitionableItem::completeTransition(QQuickTransition *quic
QQuickStateOperation::ActionList actions; // not used
QList<QQmlProperty> after; // not used
- auto instance = quickTransition->prepare(actions, after, transition, item);
+ QScopedPointer<QQuickTransitionInstance> instance(
+ quickTransition->prepare(actions, after, transition, item));
RETURN_IF_DELETED(instance->complete());
clearCurrentScheduledTransition();
@@ -579,6 +580,8 @@ void QQuickItemViewTransitionableItem::stopTransition()
{
if (transition)
RETURN_IF_DELETED(transition->cancel());
+ delete transition;
+ transition = nullptr;
clearCurrentScheduledTransition();
resetNextTransitionPos();
}
diff --git a/src/quick/items/qquicklistview.cpp b/src/quick/items/qquicklistview.cpp
index 7ddda6196f..868d70b3fe 100644
--- a/src/quick/items/qquicklistview.cpp
+++ b/src/quick/items/qquicklistview.cpp
@@ -130,6 +130,8 @@ public:
bool hasStickyHeader() const override;
bool hasStickyFooter() const override;
+ void initializeComponentItem(QQuickItem *item) const override;
+
void changedVisibleIndex(int newIndex) override;
void initializeCurrentItem() override;
@@ -1575,6 +1577,14 @@ bool QQuickListViewPrivate::hasStickyFooter() const
return footer && footerPositioning != QQuickListView::InlineFooter;
}
+void QQuickListViewPrivate::initializeComponentItem(QQuickItem *item) const
+{
+ QQuickListViewAttached *attached = static_cast<QQuickListViewAttached *>(
+ qmlAttachedPropertiesObject<QQuickListView>(item));
+ if (attached) // can be null for default components (see createComponentItem)
+ attached->setView(const_cast<QQuickListView*>(q_func()));
+}
+
void QQuickListViewPrivate::itemGeometryChanged(QQuickItem *item, QQuickGeometryChange change,
const QRectF &oldGeometry)
{
diff --git a/src/quick/items/qquickpathview.cpp b/src/quick/items/qquickpathview.cpp
index d6ce5d7769..80299b3c38 100644
--- a/src/quick/items/qquickpathview.cpp
+++ b/src/quick/items/qquickpathview.cpp
@@ -146,7 +146,8 @@ QQuickItem *QQuickPathViewPrivate::getItem(int modelIndex, qreal z, bool async)
item->setParentItem(q);
requestedIndex = -1;
QQuickItemPrivate *itemPrivate = QQuickItemPrivate::get(item);
- itemPrivate->addItemChangeListener(this, QQuickItemPrivate::Geometry);
+ itemPrivate->addItemChangeListener(
+ this, QQuickItemPrivate::Geometry | QQuickItemPrivate::Destroyed);
}
inRequest = false;
return item;
@@ -199,11 +200,14 @@ void QQuickPathView::initItem(int index, QObject *object)
void QQuickPathViewPrivate::releaseItem(QQuickItem *item)
{
- if (!item || !model)
+ if (!item)
return;
qCDebug(lcItemViewDelegateLifecycle) << "release" << item;
QQuickItemPrivate *itemPrivate = QQuickItemPrivate::get(item);
- itemPrivate->removeItemChangeListener(this, QQuickItemPrivate::Geometry);
+ itemPrivate->removeItemChangeListener(
+ this, QQuickItemPrivate::Geometry | QQuickItemPrivate::Destroyed);
+ if (!model)
+ return;
QQmlInstanceModel::ReleaseFlags flags = model->release(item);
if (!flags) {
// item was not destroyed, and we no longer reference it.
diff --git a/src/quick/items/qquickpathview_p_p.h b/src/quick/items/qquickpathview_p_p.h
index 274086ea7c..b83cd95b95 100644
--- a/src/quick/items/qquickpathview_p_p.h
+++ b/src/quick/items/qquickpathview_p_p.h
@@ -88,6 +88,12 @@ public:
}
}
+ void itemDestroyed(QQuickItem *item) override
+ {
+ if (!items.removeOne(item))
+ itemCache.removeOne(item);
+ }
+
void scheduleLayout() {
Q_Q(QQuickPathView);
if (!layoutScheduled) {
diff --git a/src/quick/items/qquickpincharea.cpp b/src/quick/items/qquickpincharea.cpp
index b6e22169b2..37458542d3 100644
--- a/src/quick/items/qquickpincharea.cpp
+++ b/src/quick/items/qquickpincharea.cpp
@@ -390,6 +390,7 @@ void QQuickPinchArea::clearPinch(QTouchEvent *event)
}
}
setKeepTouchGrab(false);
+ setKeepMouseGrab(false);
}
void QQuickPinchArea::cancelPinch(QTouchEvent *event)
@@ -431,6 +432,7 @@ void QQuickPinchArea::cancelPinch(QTouchEvent *event)
event->setExclusiveGrabber(point, nullptr);
}
setKeepTouchGrab(false);
+ setKeepMouseGrab(false);
}
void QQuickPinchArea::updatePinch(QTouchEvent *event, bool filtering)
@@ -440,6 +442,7 @@ void QQuickPinchArea::updatePinch(QTouchEvent *event, bool filtering)
if (d->touchPoints.count() < 2) {
// A pinch gesture is not occurring, so stealing the grab is permitted.
setKeepTouchGrab(false);
+ setKeepMouseGrab(false);
// During filtering, there's no need to hold a grab for one point,
// because filtering happens for every event anyway.
// But if we receive the event via direct delivery, and give up the grab,
@@ -463,6 +466,8 @@ void QQuickPinchArea::updatePinch(QTouchEvent *event, bool filtering)
pe.setStartPoint2(mapFromScene(d->sceneStartPoint2));
pe.setPoint1(mapFromScene(d->lastPoint1));
pe.setPoint2(mapFromScene(d->lastPoint2));
+ setKeepTouchGrab(false);
+ setKeepMouseGrab(false);
emit pinchFinished(&pe);
d->pinchStartDist = 0;
d->pinchActivated = false;
@@ -499,6 +504,8 @@ void QQuickPinchArea::updatePinch(QTouchEvent *event, bool filtering)
d->initPinch = true;
event->setExclusiveGrabber(touchPoint1, this);
event->setExclusiveGrabber(touchPoint2, this);
+ setKeepTouchGrab(true);
+ setKeepMouseGrab(true);
}
if (d->pinchActivated && !d->pinchRejected) {
const int dragThreshold = QGuiApplication::styleHints()->startDragDistance();
@@ -561,6 +568,9 @@ void QQuickPinchArea::updatePinch(QTouchEvent *event, bool filtering)
event->setExclusiveGrabber(touchPoint1, this);
event->setExclusiveGrabber(touchPoint2, this);
setKeepTouchGrab(true);
+ // So that PinchArea works in PathView, grab mouse events too.
+ // We should be able to remove these setKeepMouseGrab calls when QTBUG-105567 is fixed.
+ setKeepMouseGrab(true);
d->inPinch = true;
if (d->pinch && d->pinch->target()) {
auto targetParent = pinch()->target()->parentItem();
diff --git a/src/quick/items/qquickrepeater.cpp b/src/quick/items/qquickrepeater.cpp
index 3703bb38cf..35d9da976d 100644
--- a/src/quick/items/qquickrepeater.cpp
+++ b/src/quick/items/qquickrepeater.cpp
@@ -439,6 +439,12 @@ void QQuickRepeater::initItem(int index, QObject *object)
}
d->deletables[index] = item;
item->setParentItem(parentItem());
+
+ // If the item comes from an ObjectModel, it might be used as
+ // ComboBox/Menu/TabBar's contentItem. These types unconditionally cull items
+ // that are inserted, so account for that here.
+ if (d->dataSourceIsObject)
+ QQuickItemPrivate::get(item)->setCulled(false);
if (index > 0 && d->deletables.at(index-1)) {
item->stackAfter(d->deletables.at(index-1));
} else {
diff --git a/src/quick/items/qquicktext.cpp b/src/quick/items/qquicktext.cpp
index 61f4e7af99..a476a906f5 100644
--- a/src/quick/items/qquicktext.cpp
+++ b/src/quick/items/qquicktext.cpp
@@ -2445,21 +2445,23 @@ void QQuickText::geometryChange(const QRectF &newGeometry, const QRectF &oldGeom
goto geomChangeDone;
if (!(widthChanged || widthMaximum) && !d->isLineLaidOutConnected()) { // only height has changed
- if (newGeometry.height() > oldGeometry.height()) {
- if (!d->heightExceeded && !qFuzzyIsNull(oldGeometry.height())) {
- // Height is adequate and growing, and it wasn't 0 previously.
- goto geomChangeDone;
- }
- if (d->lineCount == d->maximumLineCount()) // Reached maximum line and height is growing.
- goto geomChangeDone;
- } else if (newGeometry.height() < oldGeometry.height()) {
- if (d->lineCount < 2 && !verticalScale && newGeometry.height() > 0) // A single line won't be truncated until the text is 0 height.
- goto geomChangeDone;
-
- if (!verticalScale // no scaling, no eliding, and either unwrapped, or no maximum line count.
- && d->elideMode != QQuickText::ElideRight
- && !(d->maximumLineCountValid && d->widthExceeded)) {
- goto geomChangeDone;
+ if (!verticalPositionChanged) {
+ if (newGeometry.height() > oldGeometry.height()) {
+ if (!d->heightExceeded && !qFuzzyIsNull(oldGeometry.height())) {
+ // Height is adequate and growing, and it wasn't 0 previously.
+ goto geomChangeDone;
+ }
+ if (d->lineCount == d->maximumLineCount()) // Reached maximum line and height is growing.
+ goto geomChangeDone;
+ } else if (newGeometry.height() < oldGeometry.height()) {
+ if (d->lineCount < 2 && !verticalScale && newGeometry.height() > 0) // A single line won't be truncated until the text is 0 height.
+ goto geomChangeDone;
+
+ if (!verticalScale // no scaling, no eliding, and either unwrapped, or no maximum line count.
+ && d->elideMode != QQuickText::ElideRight
+ && !(d->maximumLineCountValid && d->widthExceeded)) {
+ goto geomChangeDone;
+ }
}
}
} else if (!heightChanged && widthMaximum) {
@@ -2987,7 +2989,7 @@ void QQuickTextPrivate::processHoverEvent(QHoverEvent *event)
emit q->linkHovered(extra->hoveredLink);
}
}
- event->setAccepted(!link.isEmpty());
+ event->ignore();
}
void QQuickText::hoverEnterEvent(QHoverEvent *event)
diff --git a/src/quick/items/qquicktextedit.cpp b/src/quick/items/qquicktextedit.cpp
index f739474908..0df71fc559 100644
--- a/src/quick/items/qquicktextedit.cpp
+++ b/src/quick/items/qquicktextedit.cpp
@@ -1592,15 +1592,20 @@ bool QQuickTextEdit::selectByMouse() const
void QQuickTextEdit::setSelectByMouse(bool on)
{
Q_D(QQuickTextEdit);
- if (d->selectByMouse != on) {
- d->selectByMouse = on;
- setKeepMouseGrab(on);
- if (on)
- d->control->setTextInteractionFlags(d->control->textInteractionFlags() | Qt::TextSelectableByMouse);
- else
- d->control->setTextInteractionFlags(d->control->textInteractionFlags() & ~Qt::TextSelectableByMouse);
- emit selectByMouseChanged(on);
- }
+ if (d->selectByMouse == on)
+ return;
+
+ d->selectByMouse = on;
+ setKeepMouseGrab(on);
+ if (on)
+ d->control->setTextInteractionFlags(d->control->textInteractionFlags() | Qt::TextSelectableByMouse);
+ else
+ d->control->setTextInteractionFlags(d->control->textInteractionFlags() & ~Qt::TextSelectableByMouse);
+
+#if QT_CONFIG(cursor)
+ d->updateMouseCursorShape();
+#endif
+ emit selectByMouseChanged(on);
}
/*!
@@ -1663,6 +1668,9 @@ void QQuickTextEdit::setReadOnly(bool r)
#if QT_CONFIG(im)
updateInputMethod(Qt::ImEnabled);
#endif
+#if QT_CONFIG(cursor)
+ d->updateMouseCursorShape();
+#endif
q_canPasteChanged();
emit readOnlyChanged(r);
if (!d->selectByKeyboardSet)
@@ -2247,9 +2255,13 @@ QSGNode *QQuickTextEdit::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *
}
}
+ bool createdNodeInView = false;
if (inView) {
if (!engine.hasContents()) {
+ if (node && !node->parent())
+ d->addCurrentTextNodeToRoot(&engine, rootNode, node, nodeIterator, nodeStart);
node = d->createTextNode();
+ createdNodeInView = true;
updateNodeTransform(node, nodeOffset);
nodeStart = block.position();
}
@@ -2259,13 +2271,13 @@ QSGNode *QQuickTextEdit::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *
if ((it.atEnd()) || block.next().position() >= firstCleanNode.startPos())
break; // last node that needed replacing or last block of the frame
-
QList<int>::const_iterator lowerBound = std::lower_bound(frameBoundaries.constBegin(), frameBoundaries.constEnd(), block.next().position());
if (node && (currentNodeSize > nodeBreakingSize || lowerBound == frameBoundaries.constEnd() || *lowerBound > nodeStart)) {
currentNodeSize = 0;
if (!node->parent())
d->addCurrentTextNodeToRoot(&engine, rootNode, node, nodeIterator, nodeStart);
- node = d->createTextNode();
+ if (!createdNodeInView)
+ node = d->createTextNode();
resetEngine(&engine, d->color, d->selectedTextColor, d->selectionColor);
nodeStart = block.next().position();
}
@@ -2450,7 +2462,7 @@ void QQuickTextEditPrivate::init()
updateDefaultTextOption();
q->updateSize();
#if QT_CONFIG(cursor)
- q->setCursor(Qt::IBeamCursor);
+ updateMouseCursorShape();
#endif
}
@@ -2734,9 +2746,8 @@ void QQuickTextEdit::q_linkHovered(const QString &link)
emit linkHovered(link);
#if QT_CONFIG(cursor)
if (link.isEmpty()) {
- setCursor(d->cursorToRestoreAfterHover);
+ d->updateMouseCursorShape();
} else if (cursor().shape() != Qt::PointingHandCursor) {
- d->cursorToRestoreAfterHover = cursor().shape();
setCursor(Qt::PointingHandCursor);
}
#endif
@@ -2747,9 +2758,8 @@ void QQuickTextEdit::q_markerHovered(bool hovered)
Q_D(QQuickTextEdit);
#if QT_CONFIG(cursor)
if (!hovered) {
- setCursor(d->cursorToRestoreAfterHover);
+ d->updateMouseCursorShape();
} else if (cursor().shape() != Qt::PointingHandCursor) {
- d->cursorToRestoreAfterHover = cursor().shape();
setCursor(Qt::PointingHandCursor);
}
#endif
@@ -3020,6 +3030,14 @@ bool QQuickTextEditPrivate::isLinkHoveredConnected()
IS_SIGNAL_CONNECTED(q, QQuickTextEdit, linkHovered, (const QString &));
}
+#if QT_CONFIG(cursor)
+void QQuickTextEditPrivate::updateMouseCursorShape()
+{
+ Q_Q(QQuickTextEdit);
+ q->setCursor(q->isReadOnly() && !q->selectByMouse() ? Qt::ArrowCursor : Qt::IBeamCursor);
+}
+#endif
+
/*!
\qmlsignal QtQuick::TextEdit::linkHovered(string link)
\since 5.2
@@ -3070,6 +3088,7 @@ void QQuickTextEdit::hoverEnterEvent(QHoverEvent *event)
Q_D(QQuickTextEdit);
if (d->isLinkHoveredConnected())
d->control->processEvent(event, QPointF(-d->xoff, -d->yoff));
+ event->ignore();
}
void QQuickTextEdit::hoverMoveEvent(QHoverEvent *event)
@@ -3077,6 +3096,7 @@ void QQuickTextEdit::hoverMoveEvent(QHoverEvent *event)
Q_D(QQuickTextEdit);
if (d->isLinkHoveredConnected())
d->control->processEvent(event, QPointF(-d->xoff, -d->yoff));
+ event->ignore();
}
void QQuickTextEdit::hoverLeaveEvent(QHoverEvent *event)
@@ -3084,6 +3104,7 @@ void QQuickTextEdit::hoverLeaveEvent(QHoverEvent *event)
Q_D(QQuickTextEdit);
if (d->isLinkHoveredConnected())
d->control->processEvent(event, QPointF(-d->xoff, -d->yoff));
+ event->ignore();
}
/*!
@@ -3303,6 +3324,16 @@ void QQuickTextEdit::clear()
d->control->clear();
}
+#ifndef QT_NO_DEBUG_STREAM
+QDebug operator<<(QDebug debug, const QQuickTextEditPrivate::Node &n)
+{
+ QDebugStateSaver saver(debug);
+ debug.space();
+ debug << "Node(startPos:" << n.m_startPos << "dirty:" << n.m_dirty << n.m_node << ')';
+ return debug;
+}
+#endif
+
QT_END_NAMESPACE
#include "moc_qquicktextedit_p.cpp"
diff --git a/src/quick/items/qquicktextedit_p_p.h b/src/quick/items/qquicktextedit_p_p.h
index 2381b46a05..1f0099e00e 100644
--- a/src/quick/items/qquicktextedit_p_p.h
+++ b/src/quick/items/qquicktextedit_p_p.h
@@ -89,6 +89,10 @@ public:
int m_startPos;
QQuickTextNode* m_node;
bool m_dirty;
+
+#ifndef QT_NO_DEBUG_STREAM
+ friend QDebug Q_QUICK_PRIVATE_EXPORT operator<<(QDebug, const Node &);
+#endif
};
typedef QList<Node>::iterator TextNodeIterator;
@@ -147,6 +151,10 @@ public:
Qt::LayoutDirection textDirection(const QString &text) const;
bool isLinkHoveredConnected();
+#if QT_CONFIG(cursor)
+ void updateMouseCursorShape();
+#endif
+
void setNativeCursorEnabled(bool) {}
void handleFocusEvent(QFocusEvent *event);
void addCurrentTextNodeToRoot(QQuickTextNodeEngine *, QSGTransformNode *, QQuickTextNode*, TextNodeIterator&, int startPos);
@@ -211,7 +219,6 @@ public:
Qt::InputMethodHints inputMethodHints;
#endif
UpdateType updateType;
- Qt::CursorShape cursorToRestoreAfterHover = Qt::IBeamCursor;
bool dirty : 1;
bool richText : 1;
@@ -234,6 +241,10 @@ public:
static const int largeTextSizeThreshold;
};
+#ifndef QT_NO_DEBUG_STREAM
+QDebug Q_QUICK_PRIVATE_EXPORT operator<<(QDebug debug, const QQuickTextEditPrivate::Node &);
+#endif
+
QT_END_NAMESPACE
#endif // QQUICKTEXTEDIT_P_P_H
diff --git a/src/quick/items/qquicktextinput.cpp b/src/quick/items/qquicktextinput.cpp
index 72fe2a56fe..cb50462761 100644
--- a/src/quick/items/qquicktextinput.cpp
+++ b/src/quick/items/qquicktextinput.cpp
@@ -517,8 +517,16 @@ void QQuickTextInput::setSelectedTextColor(const QColor &color)
}
/*!
- \qmlproperty enumeration QtQuick::TextInput::horizontalAlignment
\qmlproperty enumeration QtQuick::TextInput::effectiveHorizontalAlignment
+ \readonly
+
+ When using the attached property LayoutMirroring::enabled to mirror application
+ layouts, the horizontal alignment of text will also be mirrored. However, the property
+ \l horizontalAlignment will remain unchanged. To query the effective horizontal alignment
+ of TextInput, use the read-only property \c effectiveHorizontalAlignment.
+*/
+/*!
+ \qmlproperty enumeration QtQuick::TextInput::horizontalAlignment
\qmlproperty enumeration QtQuick::TextInput::verticalAlignment
Sets the horizontal alignment of the text within the TextInput item's
@@ -541,7 +549,7 @@ void QQuickTextInput::setSelectedTextColor(const QColor &color)
When using the attached property LayoutMirroring::enabled to mirror application
layouts, the horizontal alignment of text will also be mirrored. However, the property
\c horizontalAlignment will remain unchanged. To query the effective horizontal alignment
- of TextInput, use the read-only property \c effectiveHorizontalAlignment.
+ of TextInput, use the read-only property \l effectiveHorizontalAlignment.
*/
QQuickTextInput::HAlignment QQuickTextInput::hAlign() const
{
@@ -861,6 +869,7 @@ void QQuickTextInput::setCursorPosition(int cp)
/*!
\qmlproperty rectangle QtQuick::TextInput::cursorRectangle
+ \readonly
The rectangle where the standard text cursor is rendered within the text input. Read only.
@@ -902,6 +911,7 @@ QRectF QQuickTextInput::cursorRectangle() const
This property is read-only. To change the selection, use select(start,end),
selectAll(), or selectWord().
+ \readonly
\sa selectionEnd, cursorPosition, selectedText
*/
int QQuickTextInput::selectionStart() const
@@ -917,6 +927,7 @@ int QQuickTextInput::selectionStart() const
This property is read-only. To change the selection, use select(start,end),
selectAll(), or selectWord().
+ \readonly
\sa selectionStart, cursorPosition, selectedText
*/
int QQuickTextInput::selectionEnd() const
@@ -947,6 +958,7 @@ void QQuickTextInput::select(int start, int end)
/*!
\qmlproperty string QtQuick::TextInput::selectedText
+ \readonly
This read-only property provides the text currently selected in the
text input.
@@ -2470,6 +2482,7 @@ void QQuickTextInput::setPersistentSelection(bool on)
/*!
\qmlproperty bool QtQuick::TextInput::canPaste
+ \readonly
Returns true if the TextInput is writable and the content of the clipboard is
suitable for pasting into the TextInput.
@@ -2491,6 +2504,7 @@ bool QQuickTextInput::canPaste() const
/*!
\qmlproperty bool QtQuick::TextInput::canUndo
+ \readonly
Returns true if the TextInput is writable and there are previous operations
that can be undone.
@@ -2504,6 +2518,7 @@ bool QQuickTextInput::canUndo() const
/*!
\qmlproperty bool QtQuick::TextInput::canRedo
+ \readonly
Returns true if the TextInput is writable and there are \l {undo}{undone}
operations that can be redone.
@@ -2517,6 +2532,7 @@ bool QQuickTextInput::canRedo() const
/*!
\qmlproperty real QtQuick::TextInput::contentWidth
+ \readonly
Returns the width of the text, including the width past the width
which is covered due to insufficient wrapping if \l wrapMode is set.
@@ -2530,6 +2546,7 @@ qreal QQuickTextInput::contentWidth() const
/*!
\qmlproperty real QtQuick::TextInput::contentHeight
+ \readonly
Returns the height of the text, including the height past the height
that is covered if the text does not fit within the set height.
@@ -2693,7 +2710,7 @@ void QQuickTextInput::focusOutEvent(QFocusEvent *event)
/*!
\qmlproperty bool QtQuick::TextInput::inputMethodComposing
-
+ \readonly
This property holds whether the TextInput has partial text input from an
input method.
diff --git a/src/quick/items/qquicktreeview.cpp b/src/quick/items/qquicktreeview.cpp
index 2e5c516529..78ac1d7716 100644
--- a/src/quick/items/qquicktreeview.cpp
+++ b/src/quick/items/qquicktreeview.cpp
@@ -72,7 +72,7 @@
Even if TreeViewDelegate is customizable, there might be situations
where you want to render the tree in a different way, or ensure that
- the delegate ends up as mininal as possible, e.g for performance reasons.
+ the delegate ends up as minimal as possible, perhaps for performance reasons.
Creating your own delegate from scratch is easy, since TreeView offers
a set of properties that can be used to position and render each node
in the tree correctly.
diff --git a/src/quick/items/qquickwindow.cpp b/src/quick/items/qquickwindow.cpp
index 04dd650c77..5c1c01e8c9 100644
--- a/src/quick/items/qquickwindow.cpp
+++ b/src/quick/items/qquickwindow.cpp
@@ -1102,7 +1102,11 @@ QQuickWindow::QQuickWindow(QQuickWindowPrivate &dd, QWindow *parent)
}
/*!
- \internal
+ Constructs a window for displaying a QML scene, whose rendering will
+ be controlled by the \a control object.
+ Please refer to QQuickRenderControl's documentation for more information.
+
+ \since 5.4
*/
QQuickWindow::QQuickWindow(QQuickRenderControl *control)
: QWindow(*(new QQuickWindowPrivate), nullptr)
@@ -1497,8 +1501,11 @@ bool QQuickWindow::event(QEvent *e)
// or fix QTBUG-90851 so that the event always has points?
bool ret = (da && da->event(e));
- // failsafe: never allow any kind of grab to persist after release
- if (pe->isEndEvent()) {
+ // failsafe: never allow any kind of grab to persist after release,
+ // unless we're waiting for a synth event from QtGui (as with most tablet events)
+ if (pe->isEndEvent() && !(QQuickDeliveryAgentPrivate::isTabletEvent(pe) &&
+ (qApp->testAttribute(Qt::AA_SynthesizeMouseForUnhandledTabletEvents) ||
+ QWindowSystemInterfacePrivate::TabletEvent::platformSynthesizesMouse))) {
if (pe->isSinglePointEvent()) {
if (static_cast<QSinglePointEvent *>(pe)->buttons() == Qt::NoButton) {
auto &firstPt = pe->point(0);
@@ -1732,6 +1739,12 @@ QPair<QQuickItem*, QQuickPointerHandler*> QQuickWindowPrivate::findCursorItemAnd
}
#endif
+void QQuickWindowPrivate::clearFocusObject()
+{
+ if (auto da = deliveryAgentPrivate())
+ da->clearFocusObject();
+}
+
/*!
\qmlproperty list<QtObject> Window::data
\qmldefault
diff --git a/src/quick/items/qquickwindow_p.h b/src/quick/items/qquickwindow_p.h
index 0e69d63239..7dbb337e1f 100644
--- a/src/quick/items/qquickwindow_p.h
+++ b/src/quick/items/qquickwindow_p.h
@@ -160,6 +160,8 @@ public:
QPair<QQuickItem*, QQuickPointerHandler*> findCursorItemAndHandler(QQuickItem *item, const QPointF &scenePos) const;
#endif
+ void clearFocusObject() override;
+
void dirtyItem(QQuickItem *);
void cleanup(QSGNode *);