aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJ-P Nurmi <jpnurmi@qt.io>2017-04-27 15:29:53 +0200
committerJ-P Nurmi <jpnurmi@qt.io>2017-04-27 18:44:08 +0000
commit09b9a551c8eadc4e406468af09b44c14ea6c7b7f (patch)
tree64836931a529019e2a1dfa488d71e134bae840ee
parentf9552a96a7c6f8ea58d8ea90cf3027cc0636bf64 (diff)
Fix Popup.CloseOnRelease for non-modal popups
Change-Id: I70ac251a02a7856e6770cdb9b3e5b2a2d027d133 Reviewed-by: Mitch Curtis <mitch.curtis@qt.io>
-rw-r--r--src/quicktemplates2/qquickoverlay.cpp76
-rw-r--r--src/quicktemplates2/qquickoverlay_p.h1
-rw-r--r--tests/auto/popup/tst_popup.cpp56
3 files changed, 111 insertions, 22 deletions
diff --git a/src/quicktemplates2/qquickoverlay.cpp b/src/quicktemplates2/qquickoverlay.cpp
index 308eda86..60f2a36f 100644
--- a/src/quicktemplates2/qquickoverlay.cpp
+++ b/src/quicktemplates2/qquickoverlay.cpp
@@ -200,9 +200,6 @@ bool QQuickOverlayPrivate::startDrag(QEvent *event)
bool QQuickOverlayPrivate::handlePress(QQuickItem *source, QEvent *event, QQuickPopup *target)
{
- Q_Q(QQuickOverlay);
- emit q->pressed();
-
if (target) {
if (target->overlayEvent(source, event)) {
setMouseGrabberPopup(target);
@@ -234,9 +231,6 @@ bool QQuickOverlayPrivate::handleMove(QQuickItem *source, QEvent *event, QQuickP
bool QQuickOverlayPrivate::handleRelease(QQuickItem *source, QEvent *event, QQuickPopup *target)
{
- Q_Q(QQuickOverlay);
- emit q->released();
-
if (target) {
setMouseGrabberPopup(nullptr);
if (target->overlayEvent(source, event)) {
@@ -350,6 +344,10 @@ QQuickOverlay::QQuickOverlay(QQuickItem *parent)
if (parent) {
setSize(QSizeF(parent->width(), parent->height()));
QQuickItemPrivate::get(parent)->addItemChangeListener(d, QQuickItemPrivate::Geometry);
+ parent->setAcceptedMouseButtons(Qt::AllButtons);
+ parent->installEventFilter(this);
+ if (QQuickWindow *window = parent->window())
+ window->installEventFilter(this);
}
}
@@ -535,4 +533,70 @@ bool QQuickOverlay::childMouseEventFilter(QQuickItem *item, QEvent *event)
return false;
}
+bool QQuickOverlay::eventFilter(QObject *object, QEvent *event)
+{
+ Q_D(QQuickOverlay);
+ if (!isVisible() || !d->window)
+ return false;
+
+ if (object == d->window) {
+ switch (event->type()) {
+ case QEvent::TouchBegin:
+ case QEvent::TouchUpdate:
+ case QEvent::TouchEnd:
+ if (static_cast<QTouchEvent *>(event)->touchPointStates() & Qt::TouchPointPressed)
+ emit pressed();
+ if (static_cast<QTouchEvent *>(event)->touchPointStates() & Qt::TouchPointReleased)
+ emit released();
+
+ // allow non-modal popups to close on touch release outside
+ if (!d->mouseGrabberPopup) {
+ for (const QTouchEvent::TouchPoint &point : static_cast<QTouchEvent *>(event)->touchPoints()) {
+ if (point.state() == Qt::TouchPointReleased) {
+ if (d->handleRelease(d->window->contentItem(), event, nullptr))
+ break;
+ }
+ }
+ }
+ break;
+
+ case QEvent::MouseButtonPress:
+ // do not emit pressed() twice when mouse events have been synthesized from touch events
+ if (static_cast<QMouseEvent *>(event)->source() == Qt::MouseEventNotSynthesized)
+ emit pressed();
+ break;
+
+ case QEvent::MouseButtonRelease:
+ // do not emit released() twice when mouse events have been synthesized from touch events
+ if (static_cast<QMouseEvent *>(event)->source() == Qt::MouseEventNotSynthesized)
+ emit released();
+
+ // allow non-modal popups to close on mouse release outside
+ if (!d->mouseGrabberPopup)
+ d->handleRelease(d->window->contentItem(), event, nullptr);
+ break;
+
+ default:
+ break;
+ }
+ } else if (object == d->window->contentItem()) {
+ // A touch or mouse press has reached the content item of the window,
+ // meaning that nothing at the press point was interested in touch or
+ // mouse events. Make sure to accept the press in order to receive the
+ // consequent move and release events to be able to close non-modal
+ // popups on release outside.
+ switch (event->type()) {
+ case QEvent::TouchBegin:
+ case QEvent::TouchUpdate:
+ case QEvent::MouseButtonPress:
+ event->accept();
+ break;
+ default:
+ break;
+ }
+ }
+
+ return false;
+}
+
QT_END_NAMESPACE
diff --git a/src/quicktemplates2/qquickoverlay_p.h b/src/quicktemplates2/qquickoverlay_p.h
index 3a535b93..7d1ff143 100644
--- a/src/quicktemplates2/qquickoverlay_p.h
+++ b/src/quicktemplates2/qquickoverlay_p.h
@@ -92,6 +92,7 @@ protected:
void wheelEvent(QWheelEvent *event) override;
#endif
bool childMouseEventFilter(QQuickItem *item, QEvent *event) override;
+ bool eventFilter(QObject *object, QEvent *event) override;
private:
Q_DISABLE_COPY(QQuickOverlay)
diff --git a/tests/auto/popup/tst_popup.cpp b/tests/auto/popup/tst_popup.cpp
index 0e9b55f7..686a5923 100644
--- a/tests/auto/popup/tst_popup.cpp
+++ b/tests/auto/popup/tst_popup.cpp
@@ -39,6 +39,7 @@
#include "../shared/util.h"
#include "../shared/visualtestutil.h"
+#include <QtGui/qpa/qwindowsysteminterface.h>
#include <QtQuickTemplates2/private/qquickapplicationwindow_p.h>
#include <QtQuickTemplates2/private/qquickoverlay_p.h>
#include <QtQuickTemplates2/private/qquickpopup_p.h>
@@ -207,17 +208,20 @@ void tst_popup::overlay()
QQuickButton *button = window->property("button").value<QQuickButton*>();
QVERIFY(button);
+ int overlayPressCount = 0;
+ int overlayReleaseCount = 0;
+
popup->open();
QVERIFY(popup->isVisible());
QVERIFY(overlay->isVisible());
QTest::mousePress(window, Qt::LeftButton, Qt::NoModifier, QPoint(1, 1));
- QCOMPARE(overlayPressedSignal.count(), 1);
- QCOMPARE(overlayReleasedSignal.count(), 0);
+ QCOMPARE(overlayPressedSignal.count(), ++overlayPressCount);
+ QCOMPARE(overlayReleasedSignal.count(), overlayReleaseCount);
QTest::mouseRelease(window, Qt::LeftButton, Qt::NoModifier, QPoint(1, 1));
- QCOMPARE(overlayPressedSignal.count(), 1);
- QCOMPARE(overlayReleasedSignal.count(), 0); // no modal-popups open
+ QCOMPARE(overlayPressedSignal.count(), overlayPressCount);
+ QCOMPARE(overlayReleasedSignal.count(), overlayReleaseCount); // no modal-popups open
popup->close();
QVERIFY(!popup->isVisible());
@@ -227,28 +231,48 @@ void tst_popup::overlay()
popup->setModal(modal);
popup->setClosePolicy(QQuickPopup::CloseOnReleaseOutside);
+ // mouse
popup->open();
QVERIFY(popup->isVisible());
QVERIFY(overlay->isVisible());
QTest::mousePress(window, Qt::LeftButton, Qt::NoModifier, QPoint(1, 1));
- QCOMPARE(overlayPressedSignal.count(), 2);
- QCOMPARE(overlayReleasedSignal.count(), 0);
+ QCOMPARE(overlayPressedSignal.count(), ++overlayPressCount);
+ QCOMPARE(overlayReleasedSignal.count(), overlayReleaseCount);
QTest::mouseRelease(window, Qt::LeftButton, Qt::NoModifier, QPoint(1, 1));
- QCOMPARE(overlayPressedSignal.count(), 2);
+ QCOMPARE(overlayPressedSignal.count(), overlayPressCount);
+ QCOMPARE(overlayReleasedSignal.count(), ++overlayReleaseCount);
+
+ QVERIFY(!popup->isVisible());
+ QCOMPARE(overlay->isVisible(), popup->isVisible());
+
+ // touch
+ popup->open();
+ QVERIFY(popup->isVisible());
+ QVERIFY(overlay->isVisible());
+
+ struct TouchDeviceDeleter
+ {
+ static inline void cleanup(QTouchDevice *device)
+ {
+ QWindowSystemInterface::unregisterTouchDevice(device);
+ delete device;
+ }
+ };
+
+ QScopedPointer<QTouchDevice, TouchDeviceDeleter> device(new QTouchDevice);
+ device->setType(QTouchDevice::TouchScreen);
+ QWindowSystemInterface::registerTouchDevice(device.data());
- #define comment "Non-modal popups do not yet support CloseOnReleaseXxx"
- #define QEXPECT_NON_MODAL_POPUP_FAILS() \
- QEXPECT_FAIL("Window", comment, Continue); \
- QEXPECT_FAIL("Window,dim", comment, Continue); \
- QEXPECT_FAIL("ApplicationWindow", comment, Continue); \
- QEXPECT_FAIL("ApplicationWindow,dim", comment, Continue);
+ QTest::touchEvent(window, device.data()).press(0, QPoint(1, 1));
+ QCOMPARE(overlayPressedSignal.count(), ++overlayPressCount);
+ QCOMPARE(overlayReleasedSignal.count(), overlayReleaseCount);
- QEXPECT_NON_MODAL_POPUP_FAILS()
- QCOMPARE(overlayReleasedSignal.count(), 1);
+ QTest::touchEvent(window, device.data()).release(0, QPoint(1, 1));
+ QCOMPARE(overlayPressedSignal.count(), overlayPressCount);
+ QCOMPARE(overlayReleasedSignal.count(), ++overlayReleaseCount);
- QEXPECT_NON_MODAL_POPUP_FAILS()
QVERIFY(!popup->isVisible());
QCOMPARE(overlay->isVisible(), popup->isVisible());
}