diff options
-rw-r--r-- | src/widgets/dialogs/qcolordialog.cpp | 34 | ||||
-rw-r--r-- | src/widgets/dialogs/qfiledialog.cpp | 48 | ||||
-rw-r--r-- | src/widgets/dialogs/qfiledialog_p.h | 1 | ||||
-rw-r--r-- | src/widgets/dialogs/qfontdialog.cpp | 29 | ||||
-rw-r--r-- | src/widgets/dialogs/qfontdialog_p.h | 1 | ||||
-rw-r--r-- | tests/auto/printsupport/dialogs/qabstractprintdialog/tst_qabstractprintdialog.cpp | 17 | ||||
-rw-r--r-- | tests/auto/widgets/dialogs/qcolordialog/tst_qcolordialog.cpp | 29 | ||||
-rw-r--r-- | tests/auto/widgets/dialogs/qfiledialog/tst_qfiledialog.cpp | 48 | ||||
-rw-r--r-- | tests/auto/widgets/dialogs/qfontdialog/tst_qfontdialog.cpp | 28 | ||||
-rw-r--r-- | tests/auto/widgets/dialogs/qmessagebox/tst_qmessagebox.cpp | 29 |
10 files changed, 224 insertions, 40 deletions
diff --git a/src/widgets/dialogs/qcolordialog.cpp b/src/widgets/dialogs/qcolordialog.cpp index 8b3fb28c7d..5ec2424b5c 100644 --- a/src/widgets/dialogs/qcolordialog.cpp +++ b/src/widgets/dialogs/qcolordialog.cpp @@ -120,6 +120,7 @@ public: bool handleColorPickingKeyPress(QKeyEvent *e); bool canBeNativeDialog() const override; + void setVisible(bool visible) override; QWellArray *custom; QWellArray *standard; @@ -2139,30 +2140,42 @@ QColorDialog::ColorDialogOptions QColorDialog::options() const */ void QColorDialog::setVisible(bool visible) { - Q_D(QColorDialog); + // will call QColorDialogPrivate::setVisible override + QDialog::setVisible(visible); +} +/*! + \internal + + The implementation of QColorDialog::setVisible() has to live here so that the call + to hide() in ~QDialog calls this function; it wouldn't call the override of + QDialog::setVisible(). +*/ +void QColorDialogPrivate::setVisible(bool visible) +{ + Q_Q(QColorDialog); if (visible){ - if (testAttribute(Qt::WA_WState_ExplicitShowHide) && !testAttribute(Qt::WA_WState_Hidden)) + if (q->testAttribute(Qt::WA_WState_ExplicitShowHide) && !q->testAttribute(Qt::WA_WState_Hidden)) return; - } else if (testAttribute(Qt::WA_WState_ExplicitShowHide) && testAttribute(Qt::WA_WState_Hidden)) + } else if (q->testAttribute(Qt::WA_WState_ExplicitShowHide) && q->testAttribute(Qt::WA_WState_Hidden)) return; if (visible) - d->selectedQColor = QColor(); + selectedQColor = QColor(); - if (d->nativeDialogInUse) { - if (d->setNativeDialogVisible(visible)) { + if (nativeDialogInUse) { + if (setNativeDialogVisible(visible)) { // Set WA_DontShowOnScreen so that QDialog::setVisible(visible) below // updates the state correctly, but skips showing the non-native version: - setAttribute(Qt::WA_DontShowOnScreen); + q->setAttribute(Qt::WA_DontShowOnScreen); } else { - d->initWidgets(); + initWidgets(); } } else { - setAttribute(Qt::WA_DontShowOnScreen, false); + q->setAttribute(Qt::WA_DontShowOnScreen, false); } - QDialog::setVisible(visible); + QDialogPrivate::setVisible(visible); } /*! @@ -2210,7 +2223,6 @@ QColor QColorDialog::getColor(const QColor &initial, QWidget *parent, const QStr QColorDialog::~QColorDialog() { - } /*! diff --git a/src/widgets/dialogs/qfiledialog.cpp b/src/widgets/dialogs/qfiledialog.cpp index a07cc33711..e985baa3af 100644 --- a/src/widgets/dialogs/qfiledialog.cpp +++ b/src/widgets/dialogs/qfiledialog.cpp @@ -835,41 +835,53 @@ void QFileDialog::open(QObject *receiver, const char *member) */ void QFileDialog::setVisible(bool visible) { - Q_D(QFileDialog); + // will call QFileDialogPrivate::setVisible override + QDialog::setVisible(visible); +} + +/*! + \internal + + The logic has to live here so that the call to hide() in ~QDialog calls + this function; it wouldn't call an override of QDialog::setVisible(). +*/ +void QFileDialogPrivate::setVisible(bool visible) +{ + Q_Q(QFileDialog); if (visible){ - if (testAttribute(Qt::WA_WState_ExplicitShowHide) && !testAttribute(Qt::WA_WState_Hidden)) + if (q->testAttribute(Qt::WA_WState_ExplicitShowHide) && !q->testAttribute(Qt::WA_WState_Hidden)) return; - } else if (testAttribute(Qt::WA_WState_ExplicitShowHide) && testAttribute(Qt::WA_WState_Hidden)) + } else if (q->testAttribute(Qt::WA_WState_ExplicitShowHide) && q->testAttribute(Qt::WA_WState_Hidden)) return; - if (d->canBeNativeDialog()){ - if (d->setNativeDialogVisible(visible)){ - // Set WA_DontShowOnScreen so that QDialog::setVisible(visible) below + if (canBeNativeDialog()){ + if (setNativeDialogVisible(visible)){ + // Set WA_DontShowOnScreen so that QDialogPrivate::setVisible(visible) below // updates the state correctly, but skips showing the non-native version: - setAttribute(Qt::WA_DontShowOnScreen); + q->setAttribute(Qt::WA_DontShowOnScreen); #if QT_CONFIG(fscompleter) // So the completer doesn't try to complete and therefore show a popup - if (!d->nativeDialogInUse) - d->completer->setModel(nullptr); + if (!nativeDialogInUse) + completer->setModel(nullptr); #endif } else { - d->createWidgets(); - setAttribute(Qt::WA_DontShowOnScreen, false); + createWidgets(); + q->setAttribute(Qt::WA_DontShowOnScreen, false); #if QT_CONFIG(fscompleter) - if (!d->nativeDialogInUse) { - if (d->proxyModel != nullptr) - d->completer->setModel(d->proxyModel); + if (!nativeDialogInUse) { + if (proxyModel != nullptr) + completer->setModel(proxyModel); else - d->completer->setModel(d->model); + completer->setModel(model); } #endif } } - if (visible && d->usingWidgets()) - d->qFileDialogUi->fileNameEdit->setFocus(); + if (visible && usingWidgets()) + qFileDialogUi->fileNameEdit->setFocus(); - QDialog::setVisible(visible); + QDialogPrivate::setVisible(visible); } /*! diff --git a/src/widgets/dialogs/qfiledialog_p.h b/src/widgets/dialogs/qfiledialog_p.h index dc5e33d7e4..0067a90061 100644 --- a/src/widgets/dialogs/qfiledialog_p.h +++ b/src/widgets/dialogs/qfiledialog_p.h @@ -221,6 +221,7 @@ public: // dialog. Returning false means that a non-native dialog must be // used instead. bool canBeNativeDialog() const override; + void setVisible(bool visible) override; inline bool usingWidgets() const; inline void setDirectory_sys(const QUrl &directory); diff --git a/src/widgets/dialogs/qfontdialog.cpp b/src/widgets/dialogs/qfontdialog.cpp index 45853e153f..855376292b 100644 --- a/src/widgets/dialogs/qfontdialog.cpp +++ b/src/widgets/dialogs/qfontdialog.cpp @@ -960,19 +960,32 @@ void QFontDialog::open(QObject *receiver, const char *member) */ void QFontDialog::setVisible(bool visible) { - if (testAttribute(Qt::WA_WState_ExplicitShowHide) && testAttribute(Qt::WA_WState_Hidden) != visible) + // will call QFontDialogPrivate::setVisible + QDialog::setVisible(visible); +} + +/*! + \internal + + The implementation of QFontDialog::setVisible() has to live here so that the call + to hide() in ~QDialog calls this function; it wouldn't call the override of + QDialog::setVisible(). +*/ +void QFontDialogPrivate::setVisible(bool visible) +{ + Q_Q(QFontDialog); + if (q->testAttribute(Qt::WA_WState_ExplicitShowHide) && q->testAttribute(Qt::WA_WState_Hidden) != visible) return; - Q_D(QFontDialog); - if (d->canBeNativeDialog()) - d->setNativeDialogVisible(visible); - if (d->nativeDialogInUse) { + if (canBeNativeDialog()) + setNativeDialogVisible(visible); + if (nativeDialogInUse) { // Set WA_DontShowOnScreen so that QDialog::setVisible(visible) below // updates the state correctly, but skips showing the non-native version: - setAttribute(Qt::WA_DontShowOnScreen, true); + q->setAttribute(Qt::WA_DontShowOnScreen, true); } else { - setAttribute(Qt::WA_DontShowOnScreen, false); + q->setAttribute(Qt::WA_DontShowOnScreen, false); } - QDialog::setVisible(visible); + QDialogPrivate::setVisible(visible); } /*! diff --git a/src/widgets/dialogs/qfontdialog_p.h b/src/widgets/dialogs/qfontdialog_p.h index 4b3b45a9be..d46d1986e8 100644 --- a/src/widgets/dialogs/qfontdialog_p.h +++ b/src/widgets/dialogs/qfontdialog_p.h @@ -105,6 +105,7 @@ public: QByteArray memberToDisconnectOnClose; bool canBeNativeDialog() const override; + void setVisible(bool visible) override; void _q_runNativeAppModalPanel(); private: diff --git a/tests/auto/printsupport/dialogs/qabstractprintdialog/tst_qabstractprintdialog.cpp b/tests/auto/printsupport/dialogs/qabstractprintdialog/tst_qabstractprintdialog.cpp index 377226d5ac..535972e52d 100644 --- a/tests/auto/printsupport/dialogs/qabstractprintdialog/tst_qabstractprintdialog.cpp +++ b/tests/auto/printsupport/dialogs/qabstractprintdialog/tst_qabstractprintdialog.cpp @@ -146,9 +146,26 @@ void tst_QAbstractPrintDialog::hideNativeByDestruction() QWidget window; QWidget *child = new QWidget(&window); QPointer<QPrintDialog> dialog = new QPrintDialog(child); + // Make it application modal so that we don't end up with a sheet on macOS + dialog->setWindowModality(Qt::ApplicationModal); window.show(); QVERIFY(QTest::qWaitForWindowActive(&window)); dialog->open(); + + // We test that the dialog opens and closes by watching the activation of the + // transient parent window. If it doesn't deactivate, then we have to skip. + const auto windowActive = [&window]{ return window.isActiveWindow(); }; + const auto windowInactive = [&window]{ return !window.isActiveWindow(); }; + if (!QTest::qWaitFor(windowInactive, 2000)) + QSKIP("Dialog didn't activate"); + + // This should destroy the dialog and close the native window + child->deleteLater(); + QTRY_VERIFY(!dialog); + // If the native window is still open, then the transient parent can't become + // active + window.activateWindow(); + QVERIFY(QTest::qWaitFor(windowActive)); } #endif diff --git a/tests/auto/widgets/dialogs/qcolordialog/tst_qcolordialog.cpp b/tests/auto/widgets/dialogs/qcolordialog/tst_qcolordialog.cpp index c7c9d3d359..aa7bddd81a 100644 --- a/tests/auto/widgets/dialogs/qcolordialog/tst_qcolordialog.cpp +++ b/tests/auto/widgets/dialogs/qcolordialog/tst_qcolordialog.cpp @@ -29,6 +29,8 @@ private slots: void QTBUG_43548_initialColor(); void hexColor_data(); void hexColor(); + + void hideNativeByDestruction(); }; class TestNativeDialog : public QColorDialog @@ -179,5 +181,32 @@ void tst_QColorDialog::hexColor() QCOMPARE(color.name(QColor::HexRgb), expectedHexColor.toLower()); } +void tst_QColorDialog::hideNativeByDestruction() +{ + QWidget window; + QWidget *child = new QWidget(&window); + QPointer<QColorDialog> dialog = new QColorDialog(child); + // Make it application modal so that we don't end up with a sheet on macOS + dialog->setWindowModality(Qt::ApplicationModal); + window.show(); + QVERIFY(QTest::qWaitForWindowActive(&window)); + dialog->open(); + + // We test that the dialog opens and closes by watching the activation of the + // transient parent window. If it doesn't deactivate, then we have to skip. + const auto windowActive = [&window]{ return window.isActiveWindow(); }; + const auto windowInactive = [&window]{ return !window.isActiveWindow(); }; + if (!QTest::qWaitFor(windowInactive, 2000)) + QSKIP("Dialog didn't activate"); + + // This should destroy the dialog and close the native window + child->deleteLater(); + QTRY_VERIFY(!dialog); + // If the native window is still open, then the transient parent can't become + // active + window.activateWindow(); + QVERIFY(QTest::qWaitFor(windowActive)); +} + QTEST_MAIN(tst_QColorDialog) #include "tst_qcolordialog.moc" diff --git a/tests/auto/widgets/dialogs/qfiledialog/tst_qfiledialog.cpp b/tests/auto/widgets/dialogs/qfiledialog/tst_qfiledialog.cpp index 4424ecec62..23390dc04c 100644 --- a/tests/auto/widgets/dialogs/qfiledialog/tst_qfiledialog.cpp +++ b/tests/auto/widgets/dialogs/qfiledialog/tst_qfiledialog.cpp @@ -128,9 +128,10 @@ private slots: void QTBUG49600_nativeIconProviderCrash(); void focusObjectDuringDestruction(); - // NOTE: Please keep widgetlessNativeDialog() as the LAST test! + // NOTE: Please keep widgetlessNativeDialog() and + // hideNativeByDestruction() as the LAST tests! // - // widgetlessNativeDialog() is the only test function that creates + // widgetlessNativeDialog() are the only test functions that create // a native file dialog instance. GTK+ versions prior 3.15.5 have // a nasty bug (https://bugzilla.gnome.org/show_bug.cgi?id=725164) // in GtkFileChooserWidget, which makes it leak its folder change @@ -141,6 +142,7 @@ private slots: // The crash has been fixed in GTK+ 3.15.5, but the RHEL 7.2 CI has // GTK+ 3.14.13 installed (QTBUG-55276). void widgetlessNativeDialog(); + void hideNativeByDestruction(); private: void cleanupSettingsFile(); @@ -1437,7 +1439,7 @@ void tst_QFiledialog::widgetlessNativeDialog() QSKIP("This platform always uses widgets to realize its QFileDialog, instead of the native file dialog."); #ifdef Q_OS_ANDROID // QTBUG-101194 - QSKIP("Android: This keeeps the window open. Figure out why."); + QSKIP("Android: This keeps the window open. Figure out why."); #endif QApplication::setAttribute(Qt::AA_DontUseNativeDialogs, false); QFileDialog fd; @@ -1451,6 +1453,46 @@ void tst_QFiledialog::widgetlessNativeDialog() QApplication::setAttribute(Qt::AA_DontUseNativeDialogs, true); } +void tst_QFiledialog::hideNativeByDestruction() +{ + if (!QGuiApplicationPrivate::platformTheme()->usePlatformNativeDialog(QPlatformTheme::FileDialog)) + QSKIP("This platform always uses widgets to realize its QFileDialog, instead of the native file dialog."); + +#ifdef Q_OS_ANDROID + // QTBUG-101194 + QSKIP("Android: This keeps the native window open. Figure out why."); +#endif + + QApplication::setAttribute(Qt::AA_DontUseNativeDialogs, false); + auto resetAttribute = qScopeGuard([]{ + QApplication::setAttribute(Qt::AA_DontUseNativeDialogs, true); + }); + + QWidget window; + QWidget *child = new QWidget(&window); + QPointer<QFileDialog> dialog = new QFileDialog(child); + // Make it application modal so that we don't end up with a sheet on macOS + dialog->setWindowModality(Qt::ApplicationModal); + window.show(); + QVERIFY(QTest::qWaitForWindowActive(&window)); + dialog->open(); + + // We test that the dialog opens and closes by watching the activation of the + // transient parent window. If it doesn't deactivate, then we have to skip. + const auto windowActive = [&window]{ return window.isActiveWindow(); }; + const auto windowInactive = [&window]{ return !window.isActiveWindow(); }; + if (!QTest::qWaitFor(windowInactive, 2000)) + QSKIP("Dialog didn't activate"); + + // This should destroy the dialog and close the native window + child->deleteLater(); + QTRY_VERIFY(!dialog); + // If the native window is still open, then the transient parent can't become + // active + window.activateWindow(); + QVERIFY(QTest::qWaitFor(windowActive, 2000)); +} + void tst_QFiledialog::selectedFilesWithoutWidgets() { // Test for a crash when widgets are not instantiated yet. diff --git a/tests/auto/widgets/dialogs/qfontdialog/tst_qfontdialog.cpp b/tests/auto/widgets/dialogs/qfontdialog/tst_qfontdialog.cpp index 0a77bc3808..fa808712ac 100644 --- a/tests/auto/widgets/dialogs/qfontdialog/tst_qfontdialog.cpp +++ b/tests/auto/widgets/dialogs/qfontdialog/tst_qfontdialog.cpp @@ -45,6 +45,7 @@ private slots: void qtbug_41513_stylesheetStyle(); #endif + void hideNativeByDestruction(); private: void runSlotWithFailsafeTimer(const char *member); @@ -238,5 +239,32 @@ void tst_QFontDialog::testNonStandardFontSize() qWarning("Fail using a non-standard font size."); } +void tst_QFontDialog::hideNativeByDestruction() +{ + QWidget window; + QWidget *child = new QWidget(&window); + QPointer<QFontDialog> dialog = new QFontDialog(child); + // Make it application modal so that we don't end up with a sheet on macOS + dialog->setWindowModality(Qt::ApplicationModal); + window.show(); + QVERIFY(QTest::qWaitForWindowActive(&window)); + dialog->open(); + + // We test that the dialog opens and closes by watching the activation of the + // transient parent window. If it doesn't deactivate, then we have to skip. + const auto windowActive = [&window]{ return window.isActiveWindow(); }; + const auto windowInactive = [&window]{ return !window.isActiveWindow(); }; + if (!QTest::qWaitFor(windowInactive, 2000)) + QSKIP("Dialog didn't activate"); + + // This should destroy the dialog and close the native window + child->deleteLater(); + QTRY_VERIFY(!dialog); + // If the native window is still open, then the transient parent can't become + // active + window.activateWindow(); + QVERIFY(QTest::qWaitFor(windowActive)); +} + QTEST_MAIN(tst_QFontDialog) #include "tst_qfontdialog.moc" diff --git a/tests/auto/widgets/dialogs/qmessagebox/tst_qmessagebox.cpp b/tests/auto/widgets/dialogs/qmessagebox/tst_qmessagebox.cpp index 3679a9367d..8985243e36 100644 --- a/tests/auto/widgets/dialogs/qmessagebox/tst_qmessagebox.cpp +++ b/tests/auto/widgets/dialogs/qmessagebox/tst_qmessagebox.cpp @@ -60,6 +60,8 @@ private slots: void overrideDone_data(); void overrideDone(); + void hideNativeByDestruction(); + void cleanup(); }; @@ -798,5 +800,32 @@ void tst_QMessageBox::acceptedRejectedSignals_data() addCustomButtonsData(); } +void tst_QMessageBox::hideNativeByDestruction() +{ + QWidget window; + QWidget *child = new QWidget(&window); + QPointer<QMessageBox> dialog = new QMessageBox(child); + // Make it application modal so that we don't end up with a sheet on macOS + dialog->setWindowModality(Qt::ApplicationModal); + window.show(); + QVERIFY(QTest::qWaitForWindowActive(&window)); + dialog->open(); + + // We test that the dialog opens and closes by watching the activation of the + // transient parent window. If it doesn't deactivate, then we have to skip. + const auto windowActive = [&window]{ return window.isActiveWindow(); }; + const auto windowInactive = [&window]{ return !window.isActiveWindow(); }; + if (!QTest::qWaitFor(windowInactive, 2000)) + QSKIP("Dialog didn't activate"); + + // This should destroy the dialog and close the native window + child->deleteLater(); + QTRY_VERIFY(!dialog); + // If the native window is still open, then the transient parent can't become + // active + window.activateWindow(); + QVERIFY(QTest::qWaitFor(windowActive)); +} + QTEST_MAIN(tst_QMessageBox) #include "tst_qmessagebox.moc" |