aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorOliver Eftevaag <oliver.eftevaag@qt.io>2023-12-11 19:47:24 +0100
committerOliver Eftevaag <oliver.eftevaag@qt.io>2023-12-22 04:12:14 +0100
commit1cc20d181bdee1131bf2eb191e7f8fe4e4927e03 (patch)
treea3dc98e24a64b2b9e8d85ca8f73a1c9dac721f8d
parent958de6c485f7c9f1bd8d4e1eee879c8bad3298bc (diff)
FileDialog: prompt the user when selecting an existing file
It is common for editing software to prompt the user when he/she wishes to save the work done in the editor, and an existing file is selected in the file dialog. This is an extra safety step, to hopefully prevent the user from accidentally shooting himself/herself in the foot, by overwriting an existing file and losing something valuable. One of the available file dialog option is DontConfirmOverwrite. Which according to the documentation, could be set in order to bypass a confirmation which is supposed to show up by default. But that weren't the case when using the non-native quick file dialog. The FileDialog will now show that confirmation dialog as a popup dialog, which popups up on top of the FileDialog, when selecting an existing file using the SaveFile file mode. The DontConfirmOverwrite option can now be used as intended, which will make the FileDialog behave like it used to, when selecting an existing file. In additon, hitting enter while the file dialog list view has focus, will now function the same as clicking the "Open" button. This was done in order to prevent the user from being able to bypass the new confirmation dialog. Fixes: QTBUG-119916 Pick-to: 6.7 6.6 6.5 Change-Id: I07710a7126c53f489fd5554ea21e7684244a93c1 Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org> Reviewed-by: Volker Hilsheimer <volker.hilsheimer@qt.io>
-rw-r--r--src/quickdialogs/quickdialogsquickimpl/qml/+Fusion/FileDialog.qml24
-rw-r--r--src/quickdialogs/quickdialogsquickimpl/qml/+Imagine/FileDialog.qml22
-rw-r--r--src/quickdialogs/quickdialogsquickimpl/qml/+Material/FileDialog.qml20
-rw-r--r--src/quickdialogs/quickdialogsquickimpl/qml/+Universal/FileDialog.qml23
-rw-r--r--src/quickdialogs/quickdialogsquickimpl/qml/FileDialog.qml20
-rw-r--r--src/quickdialogs/quickdialogsquickimpl/qquickfiledialogdelegate.cpp11
-rw-r--r--src/quickdialogs/quickdialogsquickimpl/qquickfiledialogimpl.cpp60
-rw-r--r--src/quickdialogs/quickdialogsquickimpl/qquickfiledialogimpl_p.h8
-rw-r--r--src/quickdialogs/quickdialogsquickimpl/qquickfiledialogimpl_p_p.h3
-rw-r--r--tests/auto/quickdialogs/qquickfiledialogimpl/tst_qquickfiledialogimpl.cpp85
10 files changed, 272 insertions, 4 deletions
diff --git a/src/quickdialogs/quickdialogsquickimpl/qml/+Fusion/FileDialog.qml b/src/quickdialogs/quickdialogsquickimpl/qml/+Fusion/FileDialog.qml
index a1223c8957..20631dc5c6 100644
--- a/src/quickdialogs/quickdialogsquickimpl/qml/+Fusion/FileDialog.qml
+++ b/src/quickdialogs/quickdialogsquickimpl/qml/+Fusion/FileDialog.qml
@@ -31,6 +31,29 @@ FileDialogImpl {
standardButtons: T.Dialog.Open | T.Dialog.Cancel
+ Dialog {
+ id: overwriteConfirmationDialog
+ objectName: "confirmationDialog"
+ anchors.centerIn: parent
+ closePolicy: Popup.CloseOnEscape | Popup.CloseOnPressOutsideParent
+ dim: true
+ modal: true
+ title: qsTr("“%1” already exists. Do you want to replace it?").arg(control.fileName)
+
+ Label {
+ text: qsTr("A file with the same name already exists in %1.\nReplacing it will overwrite its current contents.").arg(control.currentFolderName)
+ }
+
+ footer: DialogButtonBox {
+ alignment: Qt.AlignHCenter
+ standardButtons: DialogButtonBox.Yes | DialogButtonBox.No
+ }
+
+ Overlay.modal: Rectangle {
+ color: Fusion.darkShade
+ }
+ }
+
/*
We use attached properties because we want to handle logic in C++, and:
- We can't assume the footer only contains a DialogButtonBox (which would allow us
@@ -45,6 +68,7 @@ FileDialogImpl {
FileDialogImpl.breadcrumbBar: breadcrumbBar
FileDialogImpl.fileNameLabel: fileNameLabel
FileDialogImpl.fileNameTextField: fileNameTextField
+ FileDialogImpl.overwriteConfirmationDialog: overwriteConfirmationDialog
background: Rectangle {
implicitWidth: 600
diff --git a/src/quickdialogs/quickdialogsquickimpl/qml/+Imagine/FileDialog.qml b/src/quickdialogs/quickdialogsquickimpl/qml/+Imagine/FileDialog.qml
index 1edc0911be..3ab5574114 100644
--- a/src/quickdialogs/quickdialogsquickimpl/qml/+Imagine/FileDialog.qml
+++ b/src/quickdialogs/quickdialogsquickimpl/qml/+Imagine/FileDialog.qml
@@ -39,12 +39,34 @@ FileDialogImpl {
standardButtons: T.Dialog.Open | T.Dialog.Cancel
+ Dialog {
+ id: overwriteConfirmationDialog
+ objectName: "confirmationDialog"
+ anchors.centerIn: parent
+ closePolicy: Popup.CloseOnEscape | Popup.CloseOnPressOutsideParent
+ dim: true
+ modal: true
+ spacing: 12
+ title: qsTr("“%1” already exists. Do you want to replace it?").arg(control.fileName)
+
+ Label {
+ anchors.horizontalCenter: parent.horizontalCenter
+ text: qsTr("A file with the same name already exists in %1.\nReplacing it will overwrite its current contents.").arg(control.currentFolderName)
+ horizontalAlignment: Text.AlignHCenter
+ }
+
+ footer: DialogButtonBox {
+ standardButtons: DialogButtonBox.Yes | DialogButtonBox.No
+ }
+ }
+
FileDialogImpl.buttonBox: buttonBox
FileDialogImpl.nameFiltersComboBox: nameFiltersComboBox
FileDialogImpl.fileDialogListView: fileDialogListView
FileDialogImpl.breadcrumbBar: breadcrumbBar
FileDialogImpl.fileNameLabel: fileNameLabel
FileDialogImpl.fileNameTextField: fileNameTextField
+ FileDialogImpl.overwriteConfirmationDialog: overwriteConfirmationDialog
background: NinePatchImage {
source: Imagine.url + "dialog-background"
diff --git a/src/quickdialogs/quickdialogsquickimpl/qml/+Material/FileDialog.qml b/src/quickdialogs/quickdialogsquickimpl/qml/+Material/FileDialog.qml
index f74d8cef74..61301295af 100644
--- a/src/quickdialogs/quickdialogsquickimpl/qml/+Material/FileDialog.qml
+++ b/src/quickdialogs/quickdialogsquickimpl/qml/+Material/FileDialog.qml
@@ -32,12 +32,32 @@ FileDialogImpl {
Material.elevation: 24
+ Dialog {
+ id: overwriteConfirmationDialog
+ objectName: "confirmationDialog"
+ anchors.centerIn: parent
+ closePolicy: Popup.CloseOnEscape | Popup.CloseOnPressOutsideParent
+ dim: true
+ modal: true
+ title: qsTr("“%1” already exists. Do you want to replace it?").arg(control.fileName)
+
+ Label {
+ text: qsTr("A file with the same name already exists in %1.\nReplacing it will overwrite its current contents.").arg(control.currentFolderName)
+ }
+
+ footer: DialogButtonBox {
+ alignment: Qt.AlignHCenter
+ standardButtons: DialogButtonBox.Yes | DialogButtonBox.No
+ }
+ }
+
FileDialogImpl.buttonBox: buttonBox
FileDialogImpl.nameFiltersComboBox: nameFiltersComboBox
FileDialogImpl.fileDialogListView: fileDialogListView
FileDialogImpl.breadcrumbBar: breadcrumbBar
FileDialogImpl.fileNameLabel: fileNameLabel
FileDialogImpl.fileNameTextField: fileNameTextField
+ FileDialogImpl.overwriteConfirmationDialog: overwriteConfirmationDialog
background: Rectangle {
implicitWidth: 600
diff --git a/src/quickdialogs/quickdialogsquickimpl/qml/+Universal/FileDialog.qml b/src/quickdialogs/quickdialogsquickimpl/qml/+Universal/FileDialog.qml
index 311cbc17f9..5bea5d2194 100644
--- a/src/quickdialogs/quickdialogsquickimpl/qml/+Universal/FileDialog.qml
+++ b/src/quickdialogs/quickdialogsquickimpl/qml/+Universal/FileDialog.qml
@@ -30,12 +30,35 @@ FileDialogImpl {
standardButtons: T.Dialog.Open | T.Dialog.Cancel
+ Dialog {
+ id: overwriteConfirmationDialog
+ objectName: "confirmationDialog"
+ anchors.centerIn: parent
+ closePolicy: Popup.CloseOnEscape | Popup.CloseOnPressOutsideParent
+ dim: true
+ modal: true
+ title: qsTr("“%1” already exists. Do you want to replace it?").arg(control.fileName)
+
+ Label {
+ text: qsTr("A file with the same name already exists in %1.\nReplacing it will overwrite its current contents.").arg(control.currentFolderName)
+ }
+
+ footer: DialogButtonBox {
+ standardButtons: DialogButtonBox.Yes | DialogButtonBox.No
+ }
+
+ Overlay.modal: Rectangle {
+ color: overwriteConfirmationDialog.Universal.baseMediumColor
+ }
+ }
+
FileDialogImpl.buttonBox: buttonBox
FileDialogImpl.nameFiltersComboBox: nameFiltersComboBox
FileDialogImpl.fileDialogListView: fileDialogListView
FileDialogImpl.breadcrumbBar: breadcrumbBar
FileDialogImpl.fileNameLabel: fileNameLabel
FileDialogImpl.fileNameTextField: fileNameTextField
+ FileDialogImpl.overwriteConfirmationDialog: overwriteConfirmationDialog
background: Rectangle {
implicitWidth: 600
diff --git a/src/quickdialogs/quickdialogsquickimpl/qml/FileDialog.qml b/src/quickdialogs/quickdialogsquickimpl/qml/FileDialog.qml
index 80ed8abaa9..7478786fd9 100644
--- a/src/quickdialogs/quickdialogsquickimpl/qml/FileDialog.qml
+++ b/src/quickdialogs/quickdialogsquickimpl/qml/FileDialog.qml
@@ -34,6 +34,25 @@ FileDialogImpl {
standardButtons: T.Dialog.Open | T.Dialog.Cancel
+ Dialog {
+ id: overwriteConfirmationDialog
+ objectName: "confirmationDialog"
+ anchors.centerIn: parent
+ closePolicy: Popup.CloseOnEscape | Popup.CloseOnPressOutsideParent
+ dim: true
+ modal: true
+ title: qsTr("“%1” already exists. Do you want to replace it?").arg(control.fileName)
+
+ Label {
+ text: qsTr("A file with the same name already exists in %1.\nReplacing it will overwrite its current contents.").arg(control.currentFolderName)
+ }
+
+ footer: DialogButtonBox {
+ alignment: Qt.AlignHCenter
+ standardButtons: DialogButtonBox.Yes | DialogButtonBox.No
+ }
+ }
+
/*
We use attached properties because we want to handle logic in C++, and:
- We can't assume the footer only contains a DialogButtonBox (which would allow us
@@ -48,6 +67,7 @@ FileDialogImpl {
FileDialogImpl.breadcrumbBar: breadcrumbBar
FileDialogImpl.fileNameLabel: fileNameLabel
FileDialogImpl.fileNameTextField: fileNameTextField
+ FileDialogImpl.overwriteConfirmationDialog: overwriteConfirmationDialog
background: Rectangle {
implicitWidth: 600
diff --git a/src/quickdialogs/quickdialogsquickimpl/qquickfiledialogdelegate.cpp b/src/quickdialogs/quickdialogsquickimpl/qquickfiledialogdelegate.cpp
index 71b1fccbc5..369176f844 100644
--- a/src/quickdialogs/quickdialogsquickimpl/qquickfiledialogdelegate.cpp
+++ b/src/quickdialogs/quickdialogsquickimpl/qquickfiledialogdelegate.cpp
@@ -11,6 +11,7 @@
#include <QtQuickTemplates2/private/qquickitemdelegate_p_p.h>
#include "qquickfiledialogimpl_p.h"
+#include "qquickfiledialogimpl_p_p.h"
#include "qquickfolderdialogimpl_p.h"
QT_BEGIN_NAMESPACE
@@ -67,6 +68,16 @@ void QQuickFileDialogDelegatePrivate::chooseFile()
Q_ASSERT(fileDialog);
// Otherwise it's a file, so select it and close the dialog.
fileDialog->setSelectedFile(file);
+
+ // Prioritize closing the dialog with QQuickDialogPrivate::handleClick() over QQuickDialog::accept()
+ const QQuickFileDialogImplAttached *attached = QQuickFileDialogImplPrivate::get(fileDialog)->attachedOrWarn();
+ if (Q_LIKELY(attached)) {
+ auto *openButton = attached->buttonBox()->standardButton(QPlatformDialogHelper::Open);
+ if (Q_LIKELY(openButton)) {
+ emit openButton->clicked();
+ return;
+ }
+ }
fileDialog->accept();
}
}
diff --git a/src/quickdialogs/quickdialogsquickimpl/qquickfiledialogimpl.cpp b/src/quickdialogs/quickdialogsquickimpl/qquickfiledialogimpl.cpp
index 977f864b6a..c2f5531b9a 100644
--- a/src/quickdialogs/quickdialogsquickimpl/qquickfiledialogimpl.cpp
+++ b/src/quickdialogs/quickdialogsquickimpl/qquickfiledialogimpl.cpp
@@ -238,14 +238,35 @@ void QQuickFileDialogImplPrivate::handleClick(QQuickAbstractButton *button)
// Don't call accept(), because selecting a folder != accepting the dialog.
} else {
// Otherwise it's a file, so select it and close the dialog.
- q->setSelectedFile(selectedFile);
- q->accept();
- QQuickDialogPrivate::handleClick(button);
- emit q->fileSelected(selectedFile);
+
+ lastButtonClicked = button;
+
+ // Unless it already exists...
+ const bool dontConfirmOverride = q->options()->testOption(QFileDialogOptions::DontConfirmOverwrite);
+ const bool isSaveMode = q->options()->fileMode() == QFileDialogOptions::AnyFile;
+ if (QQuickFileDialogImplAttached *attached = attachedOrWarn();
+ attached && fileInfo.exists() && isSaveMode && !dontConfirmOverride) {
+ QQuickDialog *confirmationDialog = attached->overwriteConfirmationDialog();
+ confirmationDialog->open();
+ static_cast<QQuickDialogButtonBox *>(confirmationDialog->footer())->standardButton(QPlatformDialogHelper::Yes)
+ ->forceActiveFocus(Qt::PopupFocusReason);
+ } else {
+ selectFile();
+ }
}
}
}
+void QQuickFileDialogImplPrivate::selectFile()
+{
+ Q_Q(QQuickFileDialogImpl);
+ Q_ASSERT(lastButtonClicked);
+ q->setSelectedFile(selectedFile);
+ q->accept();
+ QQuickDialogPrivate::handleClick(lastButtonClicked);
+ emit q->fileSelected(selectedFile);
+}
+
QQuickFileDialogImpl::QQuickFileDialogImpl(QObject *parent)
: QQuickDialog(*(new QQuickFileDialogImplPrivate), parent)
{
@@ -473,6 +494,11 @@ void QQuickFileDialogImpl::setFileName(const QString &fileName)
setSelectedFile(QUrl(currentFolder().path() + u'/' + fileName));
}
+QString QQuickFileDialogImpl::currentFolderName() const
+{
+ return QDir(currentFolder().toLocalFile()).dirName();
+}
+
void QQuickFileDialogImpl::componentComplete()
{
Q_D(QQuickFileDialogImpl);
@@ -771,6 +797,32 @@ void QQuickFileDialogImplAttached::setFileNameTextField(QQuickTextField *fileNam
emit fileNameTextFieldChanged();
}
+QQuickDialog *QQuickFileDialogImplAttached::overwriteConfirmationDialog() const
+{
+ Q_D(const QQuickFileDialogImplAttached);
+ return d->overwriteConfirmationDialog;
+}
+
+void QQuickFileDialogImplAttached::setOverwriteConfirmationDialog(QQuickDialog *dialog)
+{
+ Q_D(QQuickFileDialogImplAttached);
+ if (dialog == d->overwriteConfirmationDialog)
+ return;
+
+ QQuickFileDialogImpl *fileDialogImpl = qobject_cast<QQuickFileDialogImpl*>(parent());
+ if (d->overwriteConfirmationDialog && fileDialogImpl)
+ QObjectPrivate::disconnect(d->overwriteConfirmationDialog, &QQuickDialog::accepted,
+ QQuickFileDialogImplPrivate::get(fileDialogImpl), &QQuickFileDialogImplPrivate::selectFile);
+
+ d->overwriteConfirmationDialog = dialog;
+
+ if (d->overwriteConfirmationDialog && fileDialogImpl)
+ QObjectPrivate::connect(d->overwriteConfirmationDialog, &QQuickDialog::accepted,
+ QQuickFileDialogImplPrivate::get(fileDialogImpl), &QQuickFileDialogImplPrivate::selectFile, Qt::QueuedConnection);
+
+ emit overwriteConfirmationDialogChanged();
+}
+
QT_END_NAMESPACE
#include "moc_qquickfiledialogimpl_p.cpp"
diff --git a/src/quickdialogs/quickdialogsquickimpl/qquickfiledialogimpl_p.h b/src/quickdialogs/quickdialogsquickimpl/qquickfiledialogimpl_p.h
index 616be4ee80..b8a02acf72 100644
--- a/src/quickdialogs/quickdialogsquickimpl/qquickfiledialogimpl_p.h
+++ b/src/quickdialogs/quickdialogsquickimpl/qquickfiledialogimpl_p.h
@@ -41,6 +41,7 @@ class Q_QUICKDIALOGS2QUICKIMPL_PRIVATE_EXPORT QQuickFileDialogImpl : public QQui
Q_PROPERTY(QStringList nameFilters READ nameFilters NOTIFY nameFiltersChanged FINAL)
Q_PROPERTY(QQuickFileNameFilter *selectedNameFilter READ selectedNameFilter CONSTANT)
Q_PROPERTY(QString fileName READ fileName WRITE setFileName NOTIFY selectedFileChanged FINAL)
+ Q_PROPERTY(QString currentFolderName READ currentFolderName NOTIFY selectedFileChanged FINAL)
QML_NAMED_ELEMENT(FileDialogImpl)
QML_ATTACHED(QQuickFileDialogImplAttached)
QML_ADDED_IN_VERSION(6, 2)
@@ -80,6 +81,8 @@ public:
QString fileName() const;
void setFileName(const QString &fileName);
+ QString currentFolderName() const;
+
public Q_SLOTS:
void selectNameFilter(const QString &filter);
@@ -107,6 +110,7 @@ class Q_QUICKDIALOGS2QUICKIMPL_PRIVATE_EXPORT QQuickFileDialogImplAttached : pub
Q_PROPERTY(QQuickFolderBreadcrumbBar *breadcrumbBar READ breadcrumbBar WRITE setBreadcrumbBar NOTIFY breadcrumbBarChanged)
Q_PROPERTY(QQuickLabel *fileNameLabel READ fileNameLabel WRITE setFileNameLabel NOTIFY fileNameLabelChanged FINAL)
Q_PROPERTY(QQuickTextField *fileNameTextField READ fileNameTextField WRITE setFileNameTextField NOTIFY fileNameTextFieldChanged FINAL)
+ Q_PROPERTY(QQuickDialog *overwriteConfirmationDialog READ overwriteConfirmationDialog WRITE setOverwriteConfirmationDialog NOTIFY overwriteConfirmationDialogChanged FINAL)
Q_MOC_INCLUDE(<QtQuickTemplates2/private/qquickdialogbuttonbox_p.h>)
Q_MOC_INCLUDE(<QtQuickTemplates2/private/qquickcombobox_p.h>)
Q_MOC_INCLUDE(<QtQuickTemplates2/private/qquicktextfield_p.h>)
@@ -136,6 +140,9 @@ public:
QQuickTextField *fileNameTextField() const;
void setFileNameTextField(QQuickTextField *fileNameTextField);
+ QQuickDialog *overwriteConfirmationDialog() const;
+ void setOverwriteConfirmationDialog(QQuickDialog *dialog);
+
Q_SIGNALS:
void buttonBoxChanged();
void nameFiltersComboBoxChanged();
@@ -143,6 +150,7 @@ Q_SIGNALS:
void breadcrumbBarChanged();
void fileNameLabelChanged();
void fileNameTextFieldChanged();
+ void overwriteConfirmationDialogChanged();
private:
Q_DISABLE_COPY(QQuickFileDialogImplAttached)
diff --git a/src/quickdialogs/quickdialogsquickimpl/qquickfiledialogimpl_p_p.h b/src/quickdialogs/quickdialogsquickimpl/qquickfiledialogimpl_p_p.h
index 862d748f03..ee8dbcadac 100644
--- a/src/quickdialogs/quickdialogsquickimpl/qquickfiledialogimpl_p_p.h
+++ b/src/quickdialogs/quickdialogsquickimpl/qquickfiledialogimpl_p_p.h
@@ -55,10 +55,12 @@ public:
void handleAccept() override;
void handleClick(QQuickAbstractButton *button) override;
+ void selectFile();
QSharedPointer<QFileDialogOptions> options;
QUrl currentFolder;
QUrl selectedFile;
+ QQuickAbstractButton *lastButtonClicked = nullptr;
QStringList nameFilters;
mutable QQuickFileNameFilter *selectedNameFilter = nullptr;
QString acceptLabel;
@@ -84,6 +86,7 @@ public:
QPointer<QQuickFolderBreadcrumbBar> breadcrumbBar;
QPointer<QQuickLabel> fileNameLabel;
QPointer<QQuickTextField> fileNameTextField;
+ QPointer<QQuickDialog> overwriteConfirmationDialog;
};
QT_END_NAMESPACE
diff --git a/tests/auto/quickdialogs/qquickfiledialogimpl/tst_qquickfiledialogimpl.cpp b/tests/auto/quickdialogs/qquickfiledialogimpl/tst_qquickfiledialogimpl.cpp
index 8b4bdad90b..480830bf48 100644
--- a/tests/auto/quickdialogs/qquickfiledialogimpl/tst_qquickfiledialogimpl.cpp
+++ b/tests/auto/quickdialogs/qquickfiledialogimpl/tst_qquickfiledialogimpl.cpp
@@ -89,6 +89,7 @@ private slots:
void setSelectedFile();
void selectNewFileViaTextField_data();
void selectNewFileViaTextField();
+ void selectExistingFileShouldWarnUserWhenFileModeEqualsSaveFile();
private:
enum DelegateOrderPolicy
@@ -1374,6 +1375,9 @@ void tst_QQuickFileDialogImpl::setSelectedFile()
};
FileDialogTestHelper dialogHelper(
this, "setSelectedFile.qml", {}, initialProperties);
+
+ dialogHelper.dialog->setOptions(QFileDialogOptions::DontConfirmOverwrite);
+
OPEN_QUICK_DIALOG();
// The selected file should be what we set.
@@ -1480,6 +1484,87 @@ void tst_QQuickFileDialogImpl::selectNewFileViaTextField()
}
}
+void tst_QQuickFileDialogImpl::selectExistingFileShouldWarnUserWhenFileModeEqualsSaveFile()
+{
+ FileDialogTestHelper dialogHelper(this, "fileDialog.qml");
+ dialogHelper.dialog->setFileMode(QQuickFileDialog::SaveFile);
+ dialogHelper.dialog->setSelectedFile(QUrl::fromLocalFile(tempFile1->fileName()));
+
+ OPEN_QUICK_DIALOG();
+ QQuickTest::qWaitForPolish(dialogHelper.window());
+
+ QSignalSpy acceptedSpy(dialogHelper.dialog, SIGNAL(accepted()));
+
+ auto *dialogButtonBox = dialogHelper.quickDialog->footer()->findChild<QQuickDialogButtonBox *>();
+ QVERIFY(dialogButtonBox);
+
+ auto *confirmationDialog = dialogHelper.quickDialog->findChild<QQuickDialog *>("confirmationDialog");
+ QVERIFY(confirmationDialog);
+
+ auto *openButton = dialogButtonBox->standardButton(QPlatformDialogHelper::Open);
+ QVERIFY(openButton);
+
+ auto *confirmationButtonBox = qobject_cast<QQuickDialogButtonBox *>(confirmationDialog->footer());
+ QVERIFY(confirmationButtonBox);
+
+ const QPoint openButtonCenterPos =
+ openButton->mapToScene({ openButton->width() / 2, openButton->height() / 2 }).toPoint();
+
+ QTest::mouseClick(dialogHelper.window(), Qt::LeftButton, Qt::NoModifier, openButtonCenterPos);
+
+ QTRY_VERIFY(confirmationDialog->isOpened());
+ QVERIFY(dialogHelper.dialog->isVisible());
+
+ // Yes button should have focus by default
+ QTest::keyClick(dialogHelper.window(), Qt::Key_Space, Qt::NoModifier);
+
+ QTRY_VERIFY(!confirmationDialog->isOpened());
+ QVERIFY(!dialogHelper.dialog->isVisible());
+ QCOMPARE(acceptedSpy.count(), 1);
+
+ // Try again, but click "No" this time.
+ QVERIFY(dialogHelper.openDialog());
+ QTRY_VERIFY(dialogHelper.isQuickDialogOpen());
+
+ QTest::keyClick(dialogHelper.window(), Qt::Key_Enter, Qt::NoModifier);
+
+ QTRY_VERIFY(confirmationDialog->isOpened());
+ QVERIFY(dialogHelper.dialog->isVisible());
+
+ // Make No button trigger a clicked() event.
+ auto *confirmationNoButton = confirmationButtonBox->standardButton(QPlatformDialogHelper::No);
+ QVERIFY(confirmationNoButton);
+ QVERIFY(clickButton(confirmationNoButton));
+
+ // FileDialog is still opened
+ QTRY_VERIFY(!confirmationDialog->isOpened());
+ QVERIFY(dialogHelper.dialog->isVisible());
+ QCOMPARE(acceptedSpy.count(), 1);
+
+ // Try again
+ QTest::keyClick(dialogHelper.window(), Qt::Key_Enter, Qt::NoModifier);
+
+ QTRY_VERIFY(confirmationDialog->isOpened());
+ QVERIFY(dialogHelper.dialog->isVisible());
+
+ QTest::keyClick(dialogHelper.window(), Qt::Key_Space, Qt::NoModifier);
+
+ QTRY_VERIFY(!confirmationDialog->isOpened());
+ QVERIFY(!dialogHelper.dialog->isVisible());
+ QCOMPARE(acceptedSpy.count(), 2);
+
+ // Make sure that DontConfirmOverwrite works
+ dialogHelper.dialog->setOptions(QFileDialogOptions::DontConfirmOverwrite);
+
+ QVERIFY(dialogHelper.openDialog());
+ QTRY_VERIFY(dialogHelper.isQuickDialogOpen());
+
+ QTest::keyClick(dialogHelper.window(), Qt::Key_Enter, Qt::NoModifier);
+ QTRY_VERIFY(!confirmationDialog->isOpened());
+ QVERIFY(!dialogHelper.dialog->isVisible());
+ QCOMPARE(acceptedSpy.count(), 3);
+}
+
QTEST_MAIN(tst_QQuickFileDialogImpl)
#include "tst_qquickfiledialogimpl.moc"