aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/quick/items/qquickflickable.cpp10
-rw-r--r--src/quick/items/qquickflickable_p_p.h3
-rw-r--r--src/quick/items/qquicklistview.cpp56
-rw-r--r--src/quick/items/qquicklistview_p.h2
-rw-r--r--tests/auto/quick/qquicklistview/data/clickHeaderAndFooterWhenClip.qml60
-rw-r--r--tests/auto/quick/qquicklistview/tst_qquicklistview.cpp27
6 files changed, 142 insertions, 16 deletions
diff --git a/src/quick/items/qquickflickable.cpp b/src/quick/items/qquickflickable.cpp
index f222a4a32e..9a68be4c49 100644
--- a/src/quick/items/qquickflickable.cpp
+++ b/src/quick/items/qquickflickable.cpp
@@ -1424,7 +1424,7 @@ void QQuickFlickablePrivate::handleMouseReleaseEvent(QMouseEvent *event)
void QQuickFlickable::mousePressEvent(QMouseEvent *event)
{
Q_D(QQuickFlickable);
- if (d->interactive) {
+ if (d->interactive && d->wantsPointerEvent(event)) {
if (!d->pressed)
d->handleMousePressEvent(event);
event->accept();
@@ -1436,7 +1436,7 @@ void QQuickFlickable::mousePressEvent(QMouseEvent *event)
void QQuickFlickable::mouseMoveEvent(QMouseEvent *event)
{
Q_D(QQuickFlickable);
- if (d->interactive) {
+ if (d->interactive && d->wantsPointerEvent(event)) {
d->handleMouseMoveEvent(event);
event->accept();
} else {
@@ -1447,7 +1447,7 @@ void QQuickFlickable::mouseMoveEvent(QMouseEvent *event)
void QQuickFlickable::mouseReleaseEvent(QMouseEvent *event)
{
Q_D(QQuickFlickable);
- if (d->interactive) {
+ if (d->interactive && d->wantsPointerEvent(event)) {
if (d->delayedPressEvent) {
d->replayDelayedPress();
@@ -1475,7 +1475,7 @@ void QQuickFlickable::mouseReleaseEvent(QMouseEvent *event)
void QQuickFlickable::wheelEvent(QWheelEvent *event)
{
Q_D(QQuickFlickable);
- if (!d->interactive) {
+ if (!d->interactive || !d->wantsPointerEvent(event)) {
QQuickItem::wheelEvent(event);
return;
}
@@ -2445,7 +2445,7 @@ bool QQuickFlickable::filterMouseEvent(QQuickItem *receiver, QMouseEvent *event)
bool QQuickFlickable::childMouseEventFilter(QQuickItem *i, QEvent *e)
{
Q_D(QQuickFlickable);
- if (!isVisible() || !isEnabled() || !isInteractive()) {
+ if (!isVisible() || !isEnabled() || !isInteractive() || !d->wantsPointerEvent(e)) {
d->cancelInteraction();
return QQuickItem::childMouseEventFilter(i, e);
}
diff --git a/src/quick/items/qquickflickable_p_p.h b/src/quick/items/qquickflickable_p_p.h
index 3f5f11effd..414c9c33d6 100644
--- a/src/quick/items/qquickflickable_p_p.h
+++ b/src/quick/items/qquickflickable_p_p.h
@@ -208,6 +208,9 @@ public:
void addPointerHandler(QQuickPointerHandler *h) override;
+ // TODO Qt 6: QPointerEvent
+ virtual bool wantsPointerEvent(const QEvent *) { return true; }
+
public:
QQuickItem *contentItem;
diff --git a/src/quick/items/qquicklistview.cpp b/src/quick/items/qquicklistview.cpp
index 9dd85ded19..0f9394f695 100644
--- a/src/quick/items/qquicklistview.cpp
+++ b/src/quick/items/qquicklistview.cpp
@@ -58,6 +58,8 @@ QT_BEGIN_NAMESPACE
#define QML_FLICK_SNAPONETHRESHOLD 30
#endif
+Q_LOGGING_CATEGORY(lcEvents, "qt.quick.listview.events")
+
class FxListItemSG;
class QQuickListViewPrivate : public QQuickItemViewPrivate
@@ -143,6 +145,9 @@ public:
void fixupHeader();
void fixupHeaderCompleted();
+
+ bool wantsPointerEvent(const QEvent *event) override;
+
QQuickListView::Orientation orient;
qreal visiblePos;
qreal averageSize;
@@ -179,6 +184,7 @@ public:
bool correctFlick : 1;
bool inFlickCorrection : 1;
+ bool wantedMousePress : 1;
QQuickListViewPrivate()
: orient(QQuickListView::Vertical)
@@ -192,7 +198,7 @@ public:
, sectionCriteria(nullptr), currentSectionItem(nullptr), nextSectionItem(nullptr)
, overshootDist(0.0), desiredViewportPosition(0.0), fixupHeaderPosition(0.0)
, headerNeedsSeparateFixup(false), desiredHeaderVisible(false)
- , correctFlick(false), inFlickCorrection(false)
+ , correctFlick(false), inFlickCorrection(false), wantedMousePress(false)
{
highlightMoveDuration = -1; //override default value set in base class
}
@@ -3819,20 +3825,52 @@ QQuickListViewAttached *QQuickListView::qmlAttachedProperties(QObject *obj)
return new QQuickListViewAttached(obj);
}
-bool QQuickListView::contains(const QPointF &point) const
+/*! \internal
+ Prevents clicking or dragging through floating headers (QTBUG-74046).
+*/
+bool QQuickListViewPrivate::wantsPointerEvent(const QEvent *event)
{
- bool ret = QQuickItemView::contains(point);
- // QTBUG-74046: if a mouse press "falls through" a floating header or footer, don't allow dragging the list from there
- if (ret) {
- if (auto header = headerItem()) {
- if (headerPositioning() != QQuickListView::InlineHeader && header->contains(mapToItem(header, point)))
+ Q_Q(const QQuickListView);
+ bool ret = true;
+
+ QPointF pos;
+ // TODO switch not needed in Qt 6: use points().first().position()
+ switch (event->type()) {
+ case QEvent::Wheel:
+ pos = static_cast<const QWheelEvent *>(event)->position();
+ break;
+ case QEvent::MouseButtonPress:
+ pos = static_cast<const QMouseEvent *>(event)->localPos();
+ break;
+ default:
+ break;
+ }
+
+ if (!pos.isNull()) {
+ if (auto header = q->headerItem()) {
+ if (q->headerPositioning() != QQuickListView::InlineHeader &&
+ header->contains(q->mapToItem(header, pos)))
ret = false;
}
- if (auto footer = footerItem()) {
- if (footerPositioning() != QQuickListView::InlineFooter && footer->contains(mapToItem(footer, point)))
+ if (auto footer = q->footerItem()) {
+ if (q->footerPositioning() != QQuickListView::InlineFooter &&
+ footer->contains(q->mapToItem(footer, pos)))
ret = false;
}
}
+
+ switch (event->type()) {
+ case QEvent::MouseButtonPress:
+ wantedMousePress = ret;
+ break;
+ case QEvent::MouseMove:
+ ret = wantedMousePress;
+ break;
+ default:
+ break;
+ }
+
+ qCDebug(lcEvents) << q << (ret ? "WANTS" : "DOESN'T want") << event;
return ret;
}
diff --git a/src/quick/items/qquicklistview_p.h b/src/quick/items/qquicklistview_p.h
index be21b93155..1c72a10190 100644
--- a/src/quick/items/qquicklistview_p.h
+++ b/src/quick/items/qquicklistview_p.h
@@ -179,8 +179,6 @@ public:
static QQuickListViewAttached *qmlAttachedProperties(QObject *);
- bool contains(const QPointF &point) const override;
-
public Q_SLOTS:
void incrementCurrentIndex();
void decrementCurrentIndex();
diff --git a/tests/auto/quick/qquicklistview/data/clickHeaderAndFooterWhenClip.qml b/tests/auto/quick/qquicklistview/data/clickHeaderAndFooterWhenClip.qml
new file mode 100644
index 0000000000..c48e2d47d1
--- /dev/null
+++ b/tests/auto/quick/qquicklistview/data/clickHeaderAndFooterWhenClip.qml
@@ -0,0 +1,60 @@
+import QtQuick 2.9
+import QtQuick.Window 2.15
+
+ListView {
+ id: list
+ anchors.fill: parent
+ property bool headerPressed: false
+ property bool footerPressed: false
+ model: ListModel {
+ ListElement {
+ name: "Element 1"
+ }
+ ListElement {
+ name: "Element 2"
+ }
+ ListElement {
+ name: "Element 3"
+ }
+ ListElement {
+ name: "Element 4"
+ }
+ ListElement {
+ name: "Element 5"
+ }
+ ListElement {
+ name: "Element 6"
+ }
+ }
+ clip: true
+ headerPositioning: ListView.OverlayHeader
+ footerPositioning: ListView.OverlayHeader
+
+ delegate: Text {
+ height: 100
+ text: name
+ }
+
+ header: Rectangle {
+ width: parent.width
+ height: 50
+ z: 2
+ color: "blue"
+ MouseArea {
+ objectName: "header"
+ anchors.fill: parent
+ onClicked: list.headerPressed = true
+ }
+ }
+ footer: Rectangle {
+ width: parent.width
+ height: 50
+ color: "red"
+ z: 2
+ MouseArea {
+ objectName: "footer"
+ anchors.fill: parent
+ onClicked: list.footerPressed = true
+ }
+ }
+}
diff --git a/tests/auto/quick/qquicklistview/tst_qquicklistview.cpp b/tests/auto/quick/qquicklistview/tst_qquicklistview.cpp
index f63793ca80..2af6b084fb 100644
--- a/tests/auto/quick/qquicklistview/tst_qquicklistview.cpp
+++ b/tests/auto/quick/qquicklistview/tst_qquicklistview.cpp
@@ -297,6 +297,7 @@ private slots:
void objectModelCulling();
void requiredObjectListModel();
+ void clickHeaderAndFooterWhenClip();
private:
template <class T> void items(const QUrl &source);
@@ -10067,6 +10068,32 @@ void tst_QQuickListView::requiredObjectListModel()
}
}
+void tst_QQuickListView::clickHeaderAndFooterWhenClip() // QTBUG-85302
+{
+ QScopedPointer<QQuickView> window(createView());
+ window->setSource(testFileUrl("clickHeaderAndFooterWhenClip.qml"));
+ window->resize(640, 480);
+ window->show();
+
+ QVERIFY(QTest::qWaitForWindowExposed(window.data()));
+ auto *root = window->rootObject();
+ QVERIFY(root);
+
+ auto *header = root->findChild<QQuickItem *>("header");
+ QVERIFY(header);
+
+ auto *footer = root->findChild<QQuickItem *>("footer");
+ QVERIFY(footer);
+
+ QVERIFY(root->property("headerPressed").isValid() && root->property("headerPressed").canConvert<bool>() && !root->property("headerPressed").toBool());
+ QTest::mouseClick(window.data(), Qt::LeftButton, Qt::NoModifier, header->mapToItem(root, QPoint(header->width() / 2, header->height() / 2)).toPoint());
+ QVERIFY(root->property("headerPressed").toBool());
+
+ QVERIFY(root->property("footerPressed").isValid() && root->property("footerPressed").canConvert<bool>() && !root->property("footerPressed").toBool());
+ QTest::mouseClick(window.data(), Qt::LeftButton, Qt::NoModifier, footer->mapToItem(root, QPoint(footer->width() / 2, footer->height() / 2)).toPoint());
+ QVERIFY(root->property("footerPressed").toBool());
+}
+
QTEST_MAIN(tst_QQuickListView)
#include "tst_qquicklistview.moc"