Add QQuickWindow::closing signal, and ability to ignore the event
authorShawn Rutledge <shawn.rutledge@digia.com>
Mon, 6 May 2013 12:40:28 +0000 (14:40 +0200)
committerThe Qt Project <gerrit-noreply@qt-project.org>
Wed, 8 May 2013 13:01:47 +0000 (15:01 +0200)
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
src/quick/items/qquickwindow.cpp
src/quick/items/qquickwindow.h
src/quick/items/qquickwindow_p.h
tests/auto/quick/qquickwindow/data/ucantclosethis.qml [new file with mode: 0644]
tests/auto/quick/qquickwindow/tst_qquickwindow.cpp

index f5bcf35..7f80697 100644 (file)
@@ -167,6 +167,7 @@ static void qt_quickitems_defineModule(const char *uri, int major, int minor)
     qmlRegisterType<QQuickKeyEvent>();
     qmlRegisterType<QQuickMouseEvent>();
     qmlRegisterType<QQuickWheelEvent>();
+    qmlRegisterType<QQuickCloseEvent>();
     qmlRegisterType<QQuickTransform>();
     qmlRegisterType<QQuickPathElement>();
     qmlRegisterType<QQuickCurve>();
index ad13489..4a34ada 100644 (file)
@@ -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<QCloseEvent *>(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.
index 3adc0be..fc148aa 100644 (file)
@@ -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 *);
index afcf4a9..9e3251b 100644 (file)
@@ -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 (file)
index 0000000..aa68cf5
--- /dev/null
@@ -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<br/>U can't <font color='#b40000' size='+1'>close</font> 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"
+        }
+    }
+}
index c3308bf..e2bb6b4 100644 (file)
@@ -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<QQuickWindow *>(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"