From 81b3c4bbb085c9d60dd935e5c74e86988d81dca7 Mon Sep 17 00:00:00 2001 From: Shawn Rutledge Date: Mon, 6 May 2013 14:40:28 +0200 Subject: [PATCH] Add QQuickWindow::closing signal, and ability to ignore the event An application can implement onClosing() and set closeEvent.accepted = false to delay the closing (for example to prompt the user to save changes). Depends on change I9abed47fca02a002b78727f98d678a824854adfc in qtbase. Task-number: QTBUG-31019 Change-Id: Icfd4a03ecef3621bdbbee2e2c3157b897a9b6524 Reviewed-by: Alan Alpert (Personal) <416365416c@gmail.com> --- src/quick/items/qquickitemsmodule.cpp | 1 + src/quick/items/qquickwindow.cpp | 64 ++++++++++++++++++++++ src/quick/items/qquickwindow.h | 3 + src/quick/items/qquickwindow_p.h | 17 ++++++ .../quick/qquickwindow/data/ucantclosethis.qml | 32 +++++++++++ tests/auto/quick/qquickwindow/tst_qquickwindow.cpp | 21 +++++++ 6 files changed, 138 insertions(+) create mode 100644 tests/auto/quick/qquickwindow/data/ucantclosethis.qml diff --git a/src/quick/items/qquickitemsmodule.cpp b/src/quick/items/qquickitemsmodule.cpp index f5bcf35..7f80697 100644 --- a/src/quick/items/qquickitemsmodule.cpp +++ b/src/quick/items/qquickitemsmodule.cpp @@ -167,6 +167,7 @@ static void qt_quickitems_defineModule(const char *uri, int major, int minor) qmlRegisterType(); qmlRegisterType(); qmlRegisterType(); + qmlRegisterType(); qmlRegisterType(); qmlRegisterType(); qmlRegisterType(); diff --git a/src/quick/items/qquickwindow.cpp b/src/quick/items/qquickwindow.cpp index ad13489..4a34ada 100644 --- a/src/quick/items/qquickwindow.cpp +++ b/src/quick/items/qquickwindow.cpp @@ -840,6 +840,11 @@ void QQuickWindowPrivate::cleanup(QSGNode *n) Alternatively you can set or bind \l x and \l y to position the Window explicitly on the screen. + + When the user attempts to close a window, the \a closing signal will be + emitted. You can force the window to stay open (for example to prompt the + user to save changes) by writing an onClosing handler and setting + close.accepted = false. */ /*! \class QQuickWindow @@ -1174,6 +1179,14 @@ bool QQuickWindow::event(QEvent *e) case QEvent::WindowDeactivate: contentItem()->windowDeactivateEvent(); break; + case QEvent::Close: { + // TOOD Qt 6 (binary incompatible) + // closeEvent(static_cast(e)); + QQuickCloseEvent qev; + qev.setAccepted(e->isAccepted()); + emit closing(&qev); + e->setAccepted(qev.isAccepted()); + } break; case QEvent::FocusAboutToChange: #ifndef QT_NO_IM if (d->activeFocusItem) @@ -2558,6 +2571,57 @@ QOpenGLContext *QQuickWindow::openglContext() const This signal will be emitted from the scene graph rendering thread. */ +/*! + \class QQuickCloseEvent + \internal + \since QtQuick 2.1 + + \inmodule QtQuick.Window + + \brief Notification that a \l QQuickWindow is about to be closed +*/ +/*! + \qmltype CloseEvent + \instantiates QQuickCloseEvent + \inqmlmodule QtQuick.Window 2 + \ingroup qtquick-visual + \brief Notification that a \l Window is about to be closed + \since Qt 5.1 + + Notification that a window is about to be closed by the windowing system + (e.g. the user clicked the titlebar close button). The CloseEvent contains + an accepted property which can be set to false to abort closing the window. + + \sa Window.closing() +*/ + +/*! + \qmlproperty bool QtQuick.Window2::CloseEvent::accepted + + This property indicates whether the application will allow the user to + close the window. It is true by default. +*/ + +/*! + \fn void QQuickWindow::closing() + \since QtQuick 2.1 + + This signal is emitted when the window receives a QCloseEvent from the + windowing system. +*/ + +/*! + \qmlsignal QtQuick.Window2::closing(CloseEvent close) + \since Qt 5.1 + + This signal is emitted when the user tries to close the window. + + This signal includes a closeEvent parameter. The \a close \l accepted + property is true by default so that the window is allowed to close; but you + can implement an onClosing() handler and set close.accepted = false if + you need to do something else before the window can be closed. + */ + /*! Sets the render target for this window to be \a fbo. diff --git a/src/quick/items/qquickwindow.h b/src/quick/items/qquickwindow.h index 3adc0be..fc148aa 100644 --- a/src/quick/items/qquickwindow.h +++ b/src/quick/items/qquickwindow.h @@ -57,6 +57,7 @@ class QQuickWindowPrivate; class QOpenGLFramebufferObject; class QQmlIncubationController; class QInputMethodEvent; +class QQuickCloseEvent; class Q_QUICK_EXPORT QQuickWindow : public QWindow { @@ -129,6 +130,7 @@ Q_SIGNALS: void beforeSynchronizing(); void beforeRendering(); void afterRendering(); + Q_REVISION(1) void closing(QQuickCloseEvent *close); void colorChanged(const QColor &); Q_REVISION(1) void activeFocusItemChanged(); @@ -144,6 +146,7 @@ protected: virtual void showEvent(QShowEvent *); virtual void hideEvent(QHideEvent *); + // TODO Qt 6: reimplement QWindow::closeEvent to emit closing virtual void focusInEvent(QFocusEvent *); virtual void focusOutEvent(QFocusEvent *); diff --git a/src/quick/items/qquickwindow_p.h b/src/quick/items/qquickwindow_p.h index afcf4a9..9e3251b 100644 --- a/src/quick/items/qquickwindow_p.h +++ b/src/quick/items/qquickwindow_p.h @@ -231,9 +231,26 @@ private: static void cleanupNodesOnShutdown(QQuickItem *); }; +class Q_QUICK_PRIVATE_EXPORT QQuickCloseEvent : public QObject +{ + Q_OBJECT + Q_PROPERTY(bool accepted READ isAccepted WRITE setAccepted) + +public: + QQuickCloseEvent() + : _accepted(true) {} + + bool isAccepted() { return _accepted; } + void setAccepted(bool accepted) { _accepted = accepted; } + +private: + bool _accepted; +}; Q_DECLARE_OPERATORS_FOR_FLAGS(QQuickWindowPrivate::FocusOptions) QT_END_NAMESPACE +QML_DECLARE_TYPE(QQuickCloseEvent) + #endif // QQUICKWINDOW_P_H diff --git a/tests/auto/quick/qquickwindow/data/ucantclosethis.qml b/tests/auto/quick/qquickwindow/data/ucantclosethis.qml new file mode 100644 index 0000000..aa68cf5 --- /dev/null +++ b/tests/auto/quick/qquickwindow/data/ucantclosethis.qml @@ -0,0 +1,32 @@ +import QtQuick 2.1 +import QtQuick.Window 2.1 + +Window { + width: 240 + height: 75 + title: "Hammer sez" + color: "#e0c31e" + property bool canCloseThis: false; + Rectangle { + color: "#14148c" + width: parent.width * 0.85 + height: parent.height * 0.7 + anchors.horizontalCenter: parent.horizontalCenter + Text { + id: text + anchors.centerIn: parent + color: "white" + textFormat: Text.StyledText + text: "whoa-oa-oa-oh
U can't close this" + } + } + onClosing: { + if (canCloseThis) { + text.text = "uncle! I give up" + // the event is accepted by default + } else { + close.accepted = false + text.text = "...but you still can't close this" + } + } +} diff --git a/tests/auto/quick/qquickwindow/tst_qquickwindow.cpp b/tests/auto/quick/qquickwindow/tst_qquickwindow.cpp index c3308bf..e2bb6b4 100644 --- a/tests/auto/quick/qquickwindow/tst_qquickwindow.cpp +++ b/tests/auto/quick/qquickwindow/tst_qquickwindow.cpp @@ -326,6 +326,8 @@ private slots: void requestActivate(); + void blockClosing(); + #ifndef QT_NO_CURSOR void cursor(); #endif @@ -1466,6 +1468,25 @@ void tst_qquickwindow::requestActivate() QVERIFY(windows.at(0)->isActive()); } +void tst_qquickwindow::blockClosing() +{ + QQmlEngine engine; + QQmlComponent component(&engine); + component.loadUrl(testFileUrl("ucantclosethis.qml")); + QQuickWindow* window = qobject_cast(component.create()); + QVERIFY(window); + window->show(); + QTest::qWaitForWindowExposed(window); + QVERIFY(window->isVisible()); + QWindowSystemInterface::handleCloseEvent(window); + QVERIFY(window->isVisible()); + QWindowSystemInterface::handleCloseEvent(window); + QVERIFY(window->isVisible()); + window->setProperty("canCloseThis", true); + QWindowSystemInterface::handleCloseEvent(window); + QTRY_VERIFY(!window->isVisible()); +} + QTEST_MAIN(tst_qquickwindow) #include "tst_qquickwindow.moc" -- 2.7.4