Don't override QDialog::setVisible() to implement native dialogs
Clients who called the base-class implementation in QDialog would as a result start hitting the canBeNativeDialog code path at the start of QDialog::setVisible(), which would show the native dialog, but without updating the QWidget visibility state. To keep things 100% compatible, we shuffle the implementation of QDialog::setVisible() into QDialogPrivate, which allows us to override it in QMessageBoxPrivate and QErrorMessagePrivate. The existing subclasses of QDialog that override setVisible have been left as is, to not cause any unintended behavior change. Change-Id: Icafe31a7b84a75049365e4e04b80492de08614d2 Reviewed-by: Volker Hilsheimer <volker.hilsheimer@qt.io> (cherry picked from commit e0bb9e81ab1a9d71f2893844ea82430467422e21) Reviewed-by: Tor Arne Vestbø <tor.arne.vestbo@qt.io>
This commit is contained in:
parent
1da8787f93
commit
969ba5e368
@ -742,35 +742,41 @@ void QDialog::closeEvent(QCloseEvent *e)
|
|||||||
void QDialog::setVisible(bool visible)
|
void QDialog::setVisible(bool visible)
|
||||||
{
|
{
|
||||||
Q_D(QDialog);
|
Q_D(QDialog);
|
||||||
if (!testAttribute(Qt::WA_DontShowOnScreen) && d->canBeNativeDialog() && d->setNativeDialogVisible(visible))
|
d->setVisible(visible);
|
||||||
|
}
|
||||||
|
|
||||||
|
void QDialogPrivate::setVisible(bool visible)
|
||||||
|
{
|
||||||
|
Q_Q(QDialog);
|
||||||
|
if (!q->testAttribute(Qt::WA_DontShowOnScreen) && canBeNativeDialog() && setNativeDialogVisible(visible))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// We should not block windows by the invisible modal dialog
|
// We should not block windows by the invisible modal dialog
|
||||||
// if a platform-specific dialog is implemented as an in-process
|
// if a platform-specific dialog is implemented as an in-process
|
||||||
// Qt window, because in this case it will also be blocked.
|
// Qt window, because in this case it will also be blocked.
|
||||||
const bool dontBlockWindows = testAttribute(Qt::WA_DontShowOnScreen)
|
const bool dontBlockWindows = q->testAttribute(Qt::WA_DontShowOnScreen)
|
||||||
&& d->styleHint(QPlatformDialogHelper::DialogIsQtWindow).toBool();
|
&& styleHint(QPlatformDialogHelper::DialogIsQtWindow).toBool();
|
||||||
Qt::WindowModality oldModality;
|
Qt::WindowModality oldModality;
|
||||||
bool wasModalitySet;
|
bool wasModalitySet;
|
||||||
|
|
||||||
if (dontBlockWindows) {
|
if (dontBlockWindows) {
|
||||||
oldModality = windowModality();
|
oldModality = q->windowModality();
|
||||||
wasModalitySet = testAttribute(Qt::WA_SetWindowModality);
|
wasModalitySet = q->testAttribute(Qt::WA_SetWindowModality);
|
||||||
setWindowModality(Qt::NonModal);
|
q->setWindowModality(Qt::NonModal);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (visible) {
|
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;
|
return;
|
||||||
|
|
||||||
QWidget::setVisible(visible);
|
q->QWidget::setVisible(visible);
|
||||||
|
|
||||||
// Window activation might be prevented. We can't test isActiveWindow here,
|
// Window activation might be prevented. We can't test isActiveWindow here,
|
||||||
// as the window will be activated asynchronously by the window manager.
|
// as the window will be activated asynchronously by the window manager.
|
||||||
if (!testAttribute(Qt::WA_ShowWithoutActivating)) {
|
if (!q->testAttribute(Qt::WA_ShowWithoutActivating)) {
|
||||||
QWidget *fw = window()->focusWidget();
|
QWidget *fw = q->window()->focusWidget();
|
||||||
if (!fw)
|
if (!fw)
|
||||||
fw = this;
|
fw = q;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
The following block is to handle a special case, and does not
|
The following block is to handle a special case, and does not
|
||||||
@ -783,14 +789,14 @@ void QDialog::setVisible(bool visible)
|
|||||||
have to use [widget*]->setFocus() themselves...
|
have to use [widget*]->setFocus() themselves...
|
||||||
*/
|
*/
|
||||||
#if QT_CONFIG(pushbutton)
|
#if QT_CONFIG(pushbutton)
|
||||||
if (d->mainDef && fw->focusPolicy() == Qt::NoFocus) {
|
if (mainDef && fw->focusPolicy() == Qt::NoFocus) {
|
||||||
QWidget *first = fw;
|
QWidget *first = fw;
|
||||||
while ((first = first->nextInFocusChain()) != fw && first->focusPolicy() == Qt::NoFocus)
|
while ((first = first->nextInFocusChain()) != fw && first->focusPolicy() == Qt::NoFocus)
|
||||||
;
|
;
|
||||||
if (first != d->mainDef && qobject_cast<QPushButton*>(first))
|
if (first != mainDef && qobject_cast<QPushButton*>(first))
|
||||||
d->mainDef->setFocus();
|
mainDef->setFocus();
|
||||||
}
|
}
|
||||||
if (!d->mainDef && isWindow()) {
|
if (!mainDef && q->isWindow()) {
|
||||||
QWidget *w = fw;
|
QWidget *w = fw;
|
||||||
while ((w = w->nextInFocusChain()) != fw) {
|
while ((w = w->nextInFocusChain()) != fw) {
|
||||||
QPushButton *pb = qobject_cast<QPushButton *>(w);
|
QPushButton *pb = qobject_cast<QPushButton *>(w);
|
||||||
@ -808,37 +814,37 @@ void QDialog::setVisible(bool visible)
|
|||||||
}
|
}
|
||||||
|
|
||||||
#if QT_CONFIG(accessibility)
|
#if QT_CONFIG(accessibility)
|
||||||
QAccessibleEvent event(this, QAccessible::DialogStart);
|
QAccessibleEvent event(q, QAccessible::DialogStart);
|
||||||
QAccessible::updateAccessibility(&event);
|
QAccessible::updateAccessibility(&event);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
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;
|
return;
|
||||||
|
|
||||||
#if QT_CONFIG(accessibility)
|
#if QT_CONFIG(accessibility)
|
||||||
if (isVisible()) {
|
if (q->isVisible()) {
|
||||||
QAccessibleEvent event(this, QAccessible::DialogEnd);
|
QAccessibleEvent event(q, QAccessible::DialogEnd);
|
||||||
QAccessible::updateAccessibility(&event);
|
QAccessible::updateAccessibility(&event);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Reimplemented to exit a modal event loop when the dialog is hidden.
|
// Reimplemented to exit a modal event loop when the dialog is hidden.
|
||||||
QWidget::setVisible(visible);
|
q->QWidget::setVisible(visible);
|
||||||
if (d->eventLoop)
|
if (eventLoop)
|
||||||
d->eventLoop->exit();
|
eventLoop->exit();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (dontBlockWindows) {
|
if (dontBlockWindows) {
|
||||||
setWindowModality(oldModality);
|
q->setWindowModality(oldModality);
|
||||||
setAttribute(Qt::WA_SetWindowModality, wasModalitySet);
|
q->setAttribute(Qt::WA_SetWindowModality, wasModalitySet);
|
||||||
}
|
}
|
||||||
|
|
||||||
#if QT_CONFIG(pushbutton)
|
#if QT_CONFIG(pushbutton)
|
||||||
const QPlatformTheme *theme = QGuiApplicationPrivate::platformTheme();
|
const QPlatformTheme *theme = QGuiApplicationPrivate::platformTheme();
|
||||||
if (d->mainDef && isActiveWindow()
|
if (mainDef && q->isActiveWindow()
|
||||||
&& theme->themeHint(QPlatformTheme::DialogSnapToDefaultButton).toBool())
|
&& theme->themeHint(QPlatformTheme::DialogSnapToDefaultButton).toBool())
|
||||||
QCursor::setPos(d->mainDef->mapToGlobal(d->mainDef->rect().center()));
|
QCursor::setPos(mainDef->mapToGlobal(mainDef->rect().center()));
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -51,6 +51,8 @@ public:
|
|||||||
{}
|
{}
|
||||||
~QDialogPrivate();
|
~QDialogPrivate();
|
||||||
|
|
||||||
|
virtual void setVisible(bool visible);
|
||||||
|
|
||||||
QWindow *transientParentWindow() const;
|
QWindow *transientParentWindow() const;
|
||||||
bool setNativeDialogVisible(bool visible);
|
bool setNativeDialogVisible(bool visible);
|
||||||
QVariant styleHint(QPlatformDialogHelper::StyleHint hint) const;
|
QVariant styleHint(QPlatformDialogHelper::StyleHint hint) const;
|
||||||
|
@ -53,6 +53,8 @@ public:
|
|||||||
bool nextPending();
|
bool nextPending();
|
||||||
void retranslateStrings();
|
void retranslateStrings();
|
||||||
|
|
||||||
|
void setVisible(bool) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void initHelper(QPlatformDialogHelper *) override;
|
void initHelper(QPlatformDialogHelper *) override;
|
||||||
void helperPrepareShow(QPlatformDialogHelper *) override;
|
void helperPrepareShow(QPlatformDialogHelper *) override;
|
||||||
@ -403,21 +405,21 @@ void QErrorMessage::showMessage(const QString &message, const QString &type)
|
|||||||
show();
|
show();
|
||||||
}
|
}
|
||||||
|
|
||||||
void QErrorMessage::setVisible(bool visible)
|
void QErrorMessagePrivate::setVisible(bool visible)
|
||||||
{
|
{
|
||||||
if (testAttribute(Qt::WA_WState_ExplicitShowHide) && testAttribute(Qt::WA_WState_Hidden) != visible)
|
Q_Q(QErrorMessage);
|
||||||
|
if (q->testAttribute(Qt::WA_WState_ExplicitShowHide) && q->testAttribute(Qt::WA_WState_Hidden) != visible)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
Q_D(QErrorMessage);
|
if (canBeNativeDialog())
|
||||||
if (d->canBeNativeDialog())
|
setNativeDialogVisible(visible);
|
||||||
d->setNativeDialogVisible(visible);
|
|
||||||
|
|
||||||
// Update WA_DontShowOnScreen based on whether the native dialog was shown,
|
// Update WA_DontShowOnScreen based on whether the native dialog was shown,
|
||||||
// so that QDialog::setVisible(visible) below updates the QWidget state correctly,
|
// so that QDialog::setVisible(visible) below updates the QWidget state correctly,
|
||||||
// but skips showing the non-native version.
|
// but skips showing the non-native version.
|
||||||
setAttribute(Qt::WA_DontShowOnScreen, d->nativeDialogInUse);
|
q->setAttribute(Qt::WA_DontShowOnScreen, nativeDialogInUse);
|
||||||
|
|
||||||
QDialog::setVisible(visible);
|
QDialogPrivate::setVisible(visible);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
|
@ -28,8 +28,6 @@ public Q_SLOTS:
|
|||||||
void showMessage(const QString &message);
|
void showMessage(const QString &message);
|
||||||
void showMessage(const QString &message, const QString &type);
|
void showMessage(const QString &message, const QString &type);
|
||||||
|
|
||||||
void setVisible(bool) override;
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void done(int) override;
|
void done(int) override;
|
||||||
void changeEvent(QEvent *e) override;
|
void changeEvent(QEvent *e) override;
|
||||||
|
@ -188,6 +188,8 @@ public:
|
|||||||
int layoutMinimumWidth();
|
int layoutMinimumWidth();
|
||||||
void retranslateStrings();
|
void retranslateStrings();
|
||||||
|
|
||||||
|
void setVisible(bool visible) override;
|
||||||
|
|
||||||
static int showOldMessageBox(QWidget *parent, QMessageBox::Icon icon,
|
static int showOldMessageBox(QWidget *parent, QMessageBox::Icon icon,
|
||||||
const QString &title, const QString &text,
|
const QString &title, const QString &text,
|
||||||
int button0, int button1, int button2);
|
int button0, int button1, int button2);
|
||||||
@ -1563,21 +1565,21 @@ void QMessageBox::open(QObject *receiver, const char *member)
|
|||||||
QDialog::open();
|
QDialog::open();
|
||||||
}
|
}
|
||||||
|
|
||||||
void QMessageBox::setVisible(bool visible)
|
void QMessageBoxPrivate::setVisible(bool visible)
|
||||||
{
|
{
|
||||||
if (testAttribute(Qt::WA_WState_ExplicitShowHide) && testAttribute(Qt::WA_WState_Hidden) != visible)
|
Q_Q(QMessageBox);
|
||||||
|
if (q->testAttribute(Qt::WA_WState_ExplicitShowHide) && q->testAttribute(Qt::WA_WState_Hidden) != visible)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
Q_D(QMessageBox);
|
if (canBeNativeDialog())
|
||||||
if (d->canBeNativeDialog())
|
setNativeDialogVisible(visible);
|
||||||
d->setNativeDialogVisible(visible);
|
|
||||||
|
|
||||||
// Update WA_DontShowOnScreen based on whether the native dialog was shown,
|
// Update WA_DontShowOnScreen based on whether the native dialog was shown,
|
||||||
// so that QDialog::setVisible(visible) below updates the QWidget state correctly,
|
// so that QDialog::setVisible(visible) below updates the QWidget state correctly,
|
||||||
// but skips showing the non-native version.
|
// but skips showing the non-native version.
|
||||||
setAttribute(Qt::WA_DontShowOnScreen, d->nativeDialogInUse);
|
q->setAttribute(Qt::WA_DontShowOnScreen, nativeDialogInUse);
|
||||||
|
|
||||||
QDialog::setVisible(visible);
|
QDialogPrivate::setVisible(visible);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
|
@ -113,8 +113,6 @@ public:
|
|||||||
using QDialog::open;
|
using QDialog::open;
|
||||||
void open(QObject *receiver, const char *member);
|
void open(QObject *receiver, const char *member);
|
||||||
|
|
||||||
void setVisible(bool visible) override;
|
|
||||||
|
|
||||||
QList<QAbstractButton *> buttons() const;
|
QList<QAbstractButton *> buttons() const;
|
||||||
ButtonRole buttonRole(QAbstractButton *button) const;
|
ButtonRole buttonRole(QAbstractButton *button) const;
|
||||||
|
|
||||||
|
@ -18,6 +18,7 @@ private slots:
|
|||||||
|
|
||||||
void dontShowAgain();
|
void dontShowAgain();
|
||||||
void dontShowCategoryAgain();
|
void dontShowCategoryAgain();
|
||||||
|
void baseClassSetVisible();
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -138,5 +139,13 @@ void tst_QErrorMessage::dontShowCategoryAgain()
|
|||||||
QVERIFY(errorMessageDialog.isVisible());
|
QVERIFY(errorMessageDialog.isVisible());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void tst_QErrorMessage::baseClassSetVisible()
|
||||||
|
{
|
||||||
|
QErrorMessage errorMessage;
|
||||||
|
errorMessage.QDialog::setVisible(true);
|
||||||
|
QCOMPARE(errorMessage.isVisible(), true);
|
||||||
|
errorMessage.close();
|
||||||
|
}
|
||||||
|
|
||||||
QTEST_MAIN(tst_QErrorMessage)
|
QTEST_MAIN(tst_QErrorMessage)
|
||||||
#include "tst_qerrormessage.moc"
|
#include "tst_qerrormessage.moc"
|
||||||
|
@ -27,6 +27,7 @@ private slots:
|
|||||||
void init();
|
void init();
|
||||||
|
|
||||||
void sanityTest();
|
void sanityTest();
|
||||||
|
void baseClassSetVisible();
|
||||||
void defaultButton();
|
void defaultButton();
|
||||||
void escapeButton();
|
void escapeButton();
|
||||||
void clickedButton();
|
void clickedButton();
|
||||||
@ -174,6 +175,15 @@ void tst_QMessageBox::sanityTest()
|
|||||||
msgBox.exec();
|
msgBox.exec();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void tst_QMessageBox::baseClassSetVisible()
|
||||||
|
{
|
||||||
|
QMessageBox msgBox;
|
||||||
|
msgBox.setText("Hello World");
|
||||||
|
msgBox.QDialog::setVisible(true);
|
||||||
|
QCOMPARE(msgBox.isVisible(), true);
|
||||||
|
msgBox.close();
|
||||||
|
}
|
||||||
|
|
||||||
void tst_QMessageBox::button()
|
void tst_QMessageBox::button()
|
||||||
{
|
{
|
||||||
QMessageBox msgBox;
|
QMessageBox msgBox;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user